Using Zen - InterSystems Documentation
Using Zen - InterSystems Documentation
Using Zen - InterSystems Documentation
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Using</strong> <strong>Zen</strong><br />
Version 2007.1<br />
04 June 2007<br />
<strong>InterSystems</strong> Corporation 1 Memorial Drive Cambridge MA 02142 www.intersystems.com
<strong>Using</strong> <strong>Zen</strong><br />
Caché Version 2007.1 04 June 2007<br />
Copyright © 2007 <strong>InterSystems</strong> Corporation<br />
All rights reserved.<br />
This book was assembled and formatted in Adobe Page Description Format (PDF) using tools and information from<br />
the following sources: Sun Microsystems, RenderX, Inc., Adobe Systems, and the World Wide Web Consortium at<br />
www.w3c.org. The primary document development tools were special-purpose XML-processing applications built<br />
by <strong>InterSystems</strong> using Caché and Java.<br />
and<br />
Caché WEBLINK, Distributed Cache Protocol, M/SQL, N/NET, and M/PACT are registered trademarks of <strong>InterSystems</strong><br />
Corporation.<br />
and<br />
<strong>InterSystems</strong> Jalapeño Technology, Enterprise Cache Protocol, ECP, and <strong>InterSystems</strong> <strong>Zen</strong> are trademarks of<br />
<strong>InterSystems</strong> Corporation.<br />
All other brand or product names used herein are trademarks or registered trademarks of their respective companies<br />
or organizations.<br />
This document contains trade secret and confidential information which is the property of <strong>InterSystems</strong> Corporation,<br />
One Memorial Drive, Cambridge, MA 02142, or its affiliates, and is furnished for the sole purpose of the operation<br />
and maintenance of the products of <strong>InterSystems</strong> Corporation. No part of this publication is to be used for any other<br />
purpose, and this publication is not to be reproduced, copied, disclosed, transmitted, stored in a retrieval system or<br />
translated into any human or computer language, in any form, by any means, in whole or in part, without the express<br />
prior written consent of <strong>InterSystems</strong> Corporation.<br />
The copying, use and disposition of this document and the software programs described herein is prohibited except<br />
to the limited extent set forth in the standard software license agreement(s) of <strong>InterSystems</strong> Corporation covering<br />
such programs and related documentation. <strong>InterSystems</strong> Corporation makes no representations and warranties<br />
concerning such software programs other than those set forth in such standard software license agreement(s). In<br />
addition, the liability of <strong>InterSystems</strong> Corporation for any losses or damages relating to or arising out of the use of<br />
such software programs is limited in the manner set forth in such standard software license agreement(s).<br />
THE FOREGOING IS A GENERAL SUMMARY OF THE RESTRICTIONS AND LIMITATIONS IMPOSED BY<br />
INTERSYSTEMS CORPORATION ON THE USE OF, AND LIABILITY ARISING FROM, ITS COMPUTER<br />
SOFTWARE. FOR COMPLETE INFORMATION REFERENCE SHOULD BE MADE TO THE STANDARD SOFTWARE<br />
LICENSE AGREEMENT(S) OF INTERSYSTEMS CORPORATION, COPIES OF WHICH WILL BE MADE AVAILABLE<br />
UPON REQUEST.<br />
<strong>InterSystems</strong> Corporation disclaims responsibility for errors which may appear in this document, and it reserves the<br />
right, in its sole discretion and without notice, to make substitutions and modifications in the products and practices<br />
described in this document.<br />
For Support questions about any <strong>InterSystems</strong> products, contact:<br />
<strong>InterSystems</strong> Worldwide Customer Support<br />
Tel: +1 617 621-0700<br />
Fax: +1 617 374-9391<br />
Email: support@<strong>InterSystems</strong>.com
Table of Contents<br />
Preface ................................................................................................................................................ 1<br />
1 Introducing <strong>Zen</strong> .............................................................................................................................. 3<br />
1.1 The <strong>Zen</strong> Demo ....................................................................................................................... 3<br />
1.2 Supported Browsers ............................................................................................................... 4<br />
1.3 Benefits of <strong>Zen</strong> ....................................................................................................................... 4<br />
1.4 Background Reading .............................................................................................................. 5<br />
2 <strong>Zen</strong> Tutorial .................................................................................................................................... 7<br />
2.1 Hello World ............................................................................................................................ 7<br />
2.2 Creating a <strong>Zen</strong> Application .................................................................................................... 9<br />
2.3 Creating a <strong>Zen</strong> Page ............................................................................................................. 10<br />
2.3.1 Step 1: New Page Wizard .......................................................................................... 10<br />
2.3.2 Step 2: XData Contents Block ................................................................................... 13<br />
2.3.3 Step 3: Client-Side Method ....................................................................................... 15<br />
2.3.4 Step 4: Viewing the HTML Output ............................................................................ 17<br />
2.3.5 Step 5: Server-Side Method ....................................................................................... 17<br />
2.4 Creating a <strong>Zen</strong> Report .......................................................................................................... 20<br />
2.5 <strong>Zen</strong> Naming Conventions .................................................................................................... 22<br />
2.6 <strong>Zen</strong> Sample Applications ..................................................................................................... 23<br />
2.7 <strong>Zen</strong> Wizards ......................................................................................................................... 24<br />
3 <strong>Zen</strong> Client and Server .................................................................................................................. 25<br />
3.1 <strong>Zen</strong> and Caché Server Pages ................................................................................................ 25<br />
3.2 <strong>Zen</strong> Pages at Runtime .......................................................................................................... 27<br />
4 <strong>Zen</strong> Application Concepts ............................................................................................................ 31<br />
4.1 <strong>Zen</strong> Applications .................................................................................................................. 31<br />
4.2 <strong>Zen</strong> Pages ............................................................................................................................. 33<br />
4.3 <strong>Zen</strong> Components .................................................................................................................. 34<br />
5 <strong>Zen</strong> Component Concepts ........................................................................................................... 37<br />
5.1 Page ...................................................................................................................................... 38<br />
5.2 Layout .................................................................................................................................. 39<br />
5.3 Style ..................................................................................................................................... 40<br />
5.4 Behavior ............................................................................................................................... 40<br />
5.5 Customization ...................................................................................................................... 41<br />
6 <strong>Zen</strong> Layout .................................................................................................................................... 43<br />
6.1 XData Contents .................................................................................................................... 44<br />
<strong>Using</strong> <strong>Zen</strong><br />
iii
6.2 Pages .................................................................................................................................... 45<br />
6.3 Titles ..................................................................................................................................... 45<br />
6.3.1 Simple Titles .............................................................................................................. 46<br />
6.3.2 Complex Titles ........................................................................................................... 47<br />
6.4 Groups .................................................................................................................................. 48<br />
6.4.1 Layout Strategy .......................................................................................................... 48<br />
6.4.2 Simple Group Components ........................................................................................ 48<br />
6.4.3 Menu Components ..................................................................................................... 49<br />
6.4.4 Complex Group Components .................................................................................... 50<br />
6.4.5 Group Layout and Style Attributes ............................................................................ 50<br />
6.5 Template Pages ..................................................................................................................... 53<br />
6.6 Panes .................................................................................................................................... 54<br />
6.7 Generated HTML ................................................................................................................. 56<br />
7 <strong>Zen</strong> Style ........................................................................................................................................ 57<br />
7.1 Component Style Attributes ................................................................................................. 57<br />
7.2 Enclosing Element ..................................................................................................... 60<br />
7.3 XData Style .......................................................................................................................... 61<br />
7.4 Inheritance of Styles ............................................................................................................ 62<br />
7.5 Cascade of Styles ................................................................................................................. 63<br />
7.6 Overriding Built-in Styles .................................................................................................... 65<br />
7.6.1 Finding the CSS Style Name ..................................................................................... 66<br />
7.6.2 Overriding a CSS Style Rule ..................................................................................... 67<br />
7.7 Applying New Styles ........................................................................................................... 69<br />
8 <strong>Zen</strong> Tables ..................................................................................................................................... 71<br />
8.1 .......................................................................................................................... 72<br />
8.2 Data Sources ........................................................................................................................ 73<br />
8.2.1 Specifying an SQL Query .......................................................................................... 74<br />
8.2.2 Generating an SQL Query ......................................................................................... 74<br />
8.2.3 Referencing a Class Query ........................................................................................ 76<br />
8.2.4 <strong>Using</strong> a Callback Method .......................................................................................... 76<br />
8.3 Query Parameters ................................................................................................................. 80<br />
8.4 Table Columns ..................................................................................................................... 81<br />
8.5 Table Style ............................................................................................................................ 83<br />
8.6 Conditional Style for Rows or Cells .................................................................................... 85<br />
8.7 Snapshot Mode ..................................................................................................................... 87<br />
8.7.1 Fetching Data From the Server .................................................................................. 88<br />
8.7.2 Navigating Snapshot Tables ....................................................................................... 89<br />
8.8 Column Filters ..................................................................................................................... 90<br />
8.9 Column Links ....................................................................................................................... 93<br />
8.10 User Interactions ................................................................................................................ 95<br />
iv<br />
<strong>Using</strong> <strong>Zen</strong>
8.10.1 Navigation Buttons .................................................................................................. 95<br />
8.10.2 Navigation Keys ....................................................................................................... 95<br />
8.10.3 Sorting Tables .......................................................................................................... 96<br />
8.10.4 Selecting Rows and Columns .................................................................................. 96<br />
8.11 Table Refresh ..................................................................................................................... 98<br />
8.12 Table Touchups .................................................................................................................. 99<br />
9 <strong>Zen</strong> and SVG ............................................................................................................................... 101<br />
9.1 SVG Component Layout .................................................................................................... 102<br />
9.1.1 ............................................................................................................. 102<br />
9.1.2 ............................................................................................................. 109<br />
9.1.3 ............................................................................................................ 109<br />
9.1.4 ....................................................................................................................... 109<br />
9.2 SVG Component Attributes ............................................................................................... 110<br />
9.3 Meters ................................................................................................................................ 112<br />
9.3.1 Providing Data for Meters ....................................................................................... 112<br />
9.3.2 Meter Attributes ....................................................................................................... 113<br />
9.3.3 ............................................................................................................ 115<br />
9.3.4 ..................................................................................................... 116<br />
9.3.5 ................................................................................................................ 117<br />
9.3.6 .................................................................................................................. 119<br />
9.3.7 ......................................................................................................... 119<br />
9.3.8 .......................................................................................................... 121<br />
9.4 Charts ................................................................................................................................. 121<br />
9.5 .............................................................................................................. 122<br />
9.6 .................................................................................................................... 125<br />
10 <strong>Zen</strong> Charts ................................................................................................................................ 127<br />
10.1 Types of Chart .................................................................................................................. 129<br />
10.1.1 Line Charts ............................................................................................................. 129<br />
10.1.2 Bar Charts .............................................................................................................. 131<br />
10.1.3 Difference Charts ................................................................................................... 133<br />
10.1.4 High/Low Charts .................................................................................................... 134<br />
10.1.5 Scatter Diagrams .................................................................................................... 136<br />
10.1.6 Pie Charts ............................................................................................................... 137<br />
10.2 Providing Data for Charts ................................................................................................ 141<br />
10.2.1 Limiting the Data Set ............................................................................................. 142<br />
10.2.2 <strong>Using</strong> a JavaScript Method .................................................................................... 143<br />
10.2.3 <strong>Using</strong> a Data Controller ......................................................................................... 144<br />
10.3 Chart Attributes ................................................................................................................ 145<br />
10.3.1 Layout and Style .................................................................................................... 145<br />
10.3.2 Plot Area ................................................................................................................ 146<br />
<strong>Using</strong> <strong>Zen</strong><br />
v
10.3.3 Markers .................................................................................................................. 148<br />
10.3.4 Legends .................................................................................................................. 149<br />
10.3.5 Titles ...................................................................................................................... 150<br />
10.3.6 User Selections ...................................................................................................... 151<br />
10.4 Chart Axes ........................................................................................................................ 152<br />
11 <strong>Zen</strong> Forms ................................................................................................................................. 155<br />
11.1 Forms and Controls .......................................................................................................... 155<br />
11.2 User Interactions .............................................................................................................. 158<br />
11.3 Defining a Form ............................................................................................................... 158<br />
11.4 Providing Values for a Form ............................................................................................ 161<br />
11.5 Detecting Modifications to the Form .............................................................................. 162<br />
11.6 Validating a Form ............................................................................................................. 162<br />
11.7 Errors and Invalid Values ................................................................................................. 163<br />
11.8 Processing a Form Submit ............................................................................................... 164<br />
11.9 User Login Forms ............................................................................................................ 166<br />
11.10 Dynamic Forms .............................................................................................................. 166<br />
12 <strong>Zen</strong> Controls ............................................................................................................................. 169<br />
12.1 Control Attributes ............................................................................................................. 170<br />
12.2 Control Methods .............................................................................................................. 173<br />
12.3 Buttons ............................................................................................................................. 174<br />
12.3.1 ................................................................................................................. 174<br />
12.3.2 ................................................................................................................. 174<br />
12.3.3 ................................................................................................................ 175<br />
12.4 Text ................................................................................................................................... 176<br />
12.4.1 ................................................................................................................... 176<br />
12.4.2 ..................................................................................................................... 176<br />
12.4.3 .............................................................................................................. 177<br />
12.4.4 ............................................................................................................ 177<br />
12.5 Simple Choices ................................................................................................................ 178<br />
12.5.1 ............................................................................................................ 178<br />
12.5.2 .......................................................................................................... 179<br />
12.5.3 ........................................................................................................ 180<br />
12.5.4 .............................................................................................................. 180<br />
12.5.5 ........................................................................................................ 183<br />
12.6 Lists .................................................................................................................................. 184<br />
12.6.1 .................................................................................................................. 185<br />
12.6.2 ............................................................................................................... 188<br />
12.6.3 ....................................................................................................... 189<br />
12.6.4 .......................................................................................................... 191<br />
12.6.5 ........................................................................................................ 195<br />
vi<br />
<strong>Using</strong> <strong>Zen</strong>
12.7 Calendars .......................................................................................................................... 202<br />
12.7.1 ............................................................................................................. 202<br />
12.7.2 ............................................................................................................. 205<br />
12.8 Hidden Items .................................................................................................................... 207<br />
12.9 Spreadsheet ...................................................................................................................... 207<br />
12.9.1 Data Set ............................................................................................. 208<br />
12.9.2 Methods ............................................................................................. 210<br />
12.9.3 ............................................................................................................. 212<br />
12.9.4 ........................................................................................................ 213<br />
12.9.5 Attributes ........................................................................................... 215<br />
13 Model View Controller ............................................................................................................. 219<br />
13.1 Architecture ...................................................................................................................... 219<br />
13.1.1 Data Model ............................................................................................................ 220<br />
13.1.2 Data Controller ...................................................................................................... 222<br />
13.1.3 Data View ............................................................................................................... 225<br />
13.2 Constructing a Model ....................................................................................................... 228<br />
13.2.1 Step 1: Type of Model ............................................................................................ 228<br />
13.2.2 Step 2: Object Data Model .................................................................................... 229<br />
13.3 Binding a to an Object Data Model .................................................................... 230<br />
13.3.1 Step 1: Data Controller .......................................................................................... 231<br />
13.3.2 Step 2: Data View .................................................................................................. 231<br />
13.3.3 Step 3: Initial Results ............................................................................................. 232<br />
13.3.4 Step 4: Saving the Form ......................................................................................... 232<br />
13.4 Adding Behavior to the ....................................................................................... 234<br />
13.4.1 Step 1: Opening a New Record .............................................................................. 234<br />
13.4.2 Step 2: Creating and Deleting Records .................................................................. 236<br />
13.5 with an Object Data Model ........................................................................ 238<br />
13.5.1 Step 1: is Easy .................................................................................. 238<br />
13.5.2 Step 2: Converting to ....................................................................... 239<br />
13.5.3 Step 3: Automatic Control Selection ..................................................................... 241<br />
13.6 with an Adaptor Data Model ...................................................................... 244<br />
13.6.1 Step 1: Generating the Form .................................................................................. 245<br />
13.6.2 Step 2: Property Parameters ................................................................................... 246<br />
13.6.3 Step 3: Adding Behavior to the ........................................................ 247<br />
13.6.4 Step 4: Virtual Properties ....................................................................................... 249<br />
13.7 Data Model Classes .......................................................................................................... 251<br />
13.7.1 Data Model Class Properties ................................................................................. 252<br />
13.7.2 Data Model Class Parameters ................................................................................ 252<br />
13.7.3 Data Model Property Parameters ........................................................................... 253<br />
13.7.4 Object Data Model Callback Methods ................................................................... 254<br />
<strong>Using</strong> <strong>Zen</strong><br />
vii
13.7.5 Virtual Properties ................................................................................................... 256<br />
13.7.6 Controller Actions .................................................................................................. 258<br />
13.7.7 Data Model Series .................................................................................................. 258<br />
13.7.8 Custom Data Model Classes .................................................................................. 260<br />
14 Navigation Components ........................................................................................................... 261<br />
14.1 Links ................................................................................................................................ 263<br />
14.1.1 ..................................................................................................................... 263<br />
14.1.2 .......................................................................................................... 265<br />
14.1.3 ........................................................................................................ 266<br />
14.2 Menus ............................................................................................................................... 267<br />
14.2.1 ........................................................................................................... 268<br />
14.2.2 , , and ........................................................................ 270<br />
14.2.3 ................................................................................................... 271<br />
14.3 Tabs .................................................................................................................................. 271<br />
14.3.1 ............................................................................................................ 272<br />
14.3.2 ..................................................................................................... 275<br />
14.3.3 ...................................................................................................................... 278<br />
14.4 Expanding Group ............................................................................................................. 279<br />
15 Popup Windows and Dialogs ................................................................................................... 285<br />
15.1 Modal Groups .................................................................................................................. 285<br />
15.1.1 Static Modal Groups .............................................................................................. 286<br />
15.1.2 Dynamic Modal Groups ........................................................................................ 288<br />
15.1.3 Built-in Modal Groups ........................................................................................... 291<br />
15.1.4 The show Method .................................................................................................. 295<br />
15.1.5 Attributes ...................................................................................... 296<br />
15.2 Popup Windows ............................................................................................................... 298<br />
15.3 Dialogs ............................................................................................................................. 299<br />
15.3.1 File Selection Dialog Window ............................................................................... 300<br />
15.3.2 Color Selection Dialog Window ............................................................................ 300<br />
15.3.3 Creating a Dialog Window ..................................................................................... 301<br />
15.3.4 Creating a Dialog Window Template ..................................................................... 302<br />
16 Other <strong>Zen</strong> Components ........................................................................................................... 305<br />
16.1 HTML Content ................................................................................................................. 305<br />
16.2 Framed Content ................................................................................................................ 307<br />
16.3 Page Timer ....................................................................................................................... 308<br />
16.4 Field Sets .......................................................................................................................... 309<br />
16.5 Color Selector .................................................................................................................. 311<br />
16.6 Repeating Group .............................................................................................................. 313<br />
16.7 Dynamic Tree ................................................................................................................... 316<br />
viii<br />
<strong>Using</strong> <strong>Zen</strong>
16.7.1 Defining a Tree <strong>Using</strong> a Global ............................................................................. 316<br />
16.7.2 Defining a Tree <strong>Using</strong> a Callback .......................................................................... 317<br />
16.7.3 Attributes ........................................................................................... 320<br />
16.8 Dynamic View .................................................................................................................. 322<br />
16.8.1 Defining a View <strong>Using</strong> a Callback ......................................................................... 322<br />
16.8.2 Attributes .......................................................................................... 324<br />
17 Custom Components ................................................................................................................ 327<br />
17.1 Building Composite Components .................................................................................... 328<br />
17.1.1 The composite Property ......................................................................................... 330<br />
17.1.2 Composites and Panes ........................................................................................... 330<br />
17.2 Overriding Component Style ........................................................................................... 331<br />
17.3 Creating Custom Components ......................................................................................... 331<br />
17.3.1 Package and Namespace ........................................................................................ 333<br />
17.3.2 Base Class .............................................................................................................. 333<br />
17.3.3 <strong>Zen</strong> Component Wizard ........................................................................................ 334<br />
17.4 Custom Style .................................................................................................................... 334<br />
17.4.1 XData SVGStyle .................................................................................................... 336<br />
17.4.2 XData SVGDef ...................................................................................................... 336<br />
17.4.3 <strong>Zen</strong> Color Definitions ............................................................................................ 337<br />
17.5 Custom Properties ............................................................................................................ 337<br />
17.5.1 Naming Conventions ............................................................................................. 337<br />
17.5.2 XML Projection ..................................................................................................... 338<br />
17.5.3 setProperty Method ................................................................................................ 338<br />
17.5.4 Datatype Parameters .............................................................................................. 338<br />
17.5.5 Datatype Classes .................................................................................................... 340<br />
17.6 Custom Methods .............................................................................................................. 342<br />
17.6.1 %DrawHTML ........................................................................................................ 343<br />
17.6.2 Helper Methods for %DrawHTML ....................................................................... 344<br />
17.6.3 Identifying HTML Elements ................................................................................. 346<br />
17.6.4 Finding HTML Elements ....................................................................................... 347<br />
17.6.5 Setting HTML Attribute Values ............................................................................. 348<br />
17.6.6 Attaching Event Handlers to HTML Elements ..................................................... 348<br />
17.6.7 HTML for Dynamic Components ......................................................................... 350<br />
17.7 Examples of Custom Components ................................................................................... 351<br />
17.8 Creating Custom Meters .................................................................................................. 353<br />
17.8.1 Custom Meters in XData Contents ........................................................................ 354<br />
17.8.2 Odometer Meter Example ...................................................................................... 354<br />
17.8.3 Clock Meter Example ............................................................................................ 356<br />
18 <strong>Zen</strong> Application Programming ................................................................................................ 361<br />
18.1 <strong>Zen</strong> Classes as CSP Classes ............................................................................................. 361<br />
<strong>Using</strong> <strong>Zen</strong><br />
ix
18.2 <strong>Zen</strong> Application Classes ................................................................................................... 362<br />
18.3 <strong>Zen</strong> Page Classes .............................................................................................................. 363<br />
18.3.1 <strong>Zen</strong> Page Parameters .............................................................................................. 363<br />
18.3.2 <strong>Zen</strong> Special Variables ............................................................................................. 364<br />
18.3.3 <strong>Zen</strong> Runtime Expressions ...................................................................................... 368<br />
18.3.4 <strong>Zen</strong> Page Properties ............................................................................................... 371<br />
18.3.5 <strong>Zen</strong> Utility Methods .............................................................................................. 371<br />
18.3.6 Client-Side Functions and Variables ...................................................................... 372<br />
18.3.7 <strong>Zen</strong> Page URI Parameters ...................................................................................... 373<br />
18.3.8 <strong>Zen</strong> Page Event Handling ...................................................................................... 374<br />
18.4 <strong>Zen</strong> Properties on Client and Server ................................................................................ 374<br />
18.5 <strong>Zen</strong> Methods .................................................................................................................... 375<br />
18.5.1 Synchronous and Asynchronous Methods ............................................................. 376<br />
18.5.2 Server-Side Callback Methods .............................................................................. 376<br />
18.5.3 Server-Only Methods ............................................................................................. 378<br />
18.5.4 Type Conversion for Server-Side Methods ............................................................ 378<br />
18.5.5 Background Tasks on the Server ............................................................................ 379<br />
18.5.6 Client-Side Page Callback Methods ...................................................................... 379<br />
18.5.7 Client-Side Page Methods ..................................................................................... 380<br />
18.5.8 Client-Side Component Methods .......................................................................... 381<br />
18.6 <strong>Zen</strong> Page Contents ........................................................................................................... 381<br />
18.6.1 Defining Page Contents <strong>Using</strong> XML ..................................................................... 382<br />
18.6.2 XML Namespaces .................................................................................................. 382<br />
18.6.3 Defining Page Contents Programmatically ............................................................ 382<br />
18.6.4 <strong>Zen</strong> Layout Handler ............................................................................................... 383<br />
18.7 Sample Development Project ........................................................................................... 384<br />
19 <strong>Zen</strong> Security .............................................................................................................................. 391<br />
19.1 Controlling Access to Applications .................................................................................. 391<br />
19.2 Controlling Access to Pages ............................................................................................. 392<br />
19.3 Controlling Access to Components .................................................................................. 392<br />
20 <strong>Zen</strong> Localization ....................................................................................................................... 395<br />
20.1 CSP Localization ............................................................................................................. 395<br />
20.1.1 Localization Practices ............................................................................................ 395<br />
20.1.2 Message Dictionary ............................................................................................... 396<br />
20.1.3 $$$Text Macros ..................................................................................................... 396<br />
20.2 <strong>Zen</strong> Localization .............................................................................................................. 400<br />
20.2.1 Localization for Built-In Components ................................................................... 400<br />
20.2.2 Localization for Custom Components ................................................................... 401<br />
21 <strong>Zen</strong> Reports ............................................................................................................................... 403<br />
x<br />
<strong>Using</strong> <strong>Zen</strong>
21.1 Building a Report ............................................................................................................. 405<br />
21.2 <strong>Zen</strong> Report Parameters ..................................................................................................... 410<br />
21.3 XData ReportDefinition ................................................................................................... 413<br />
21.3.1 The %val Variable .................................................................................................. 414<br />
21.3.2 ................................................................................................................. 414<br />
21.3.3 .............................................................................................................. 414<br />
21.3.4 .............................................................................................................. 415<br />
21.3.5 ........................................................................................................... 415<br />
21.3.6 .................................................................................................................. 418<br />
21.4 XData ReportDisplay ....................................................................................................... 421<br />
21.4.1 Dimension and Size ............................................................................................... 423<br />
21.4.2 ................................................................................................................. 423<br />
21.4.3 ........................................................................................................... 424<br />
21.4.4 ......................................................................................................... 427<br />
21.4.5 .......................................................................................................... 427<br />
21.4.6 ................................................................................................................... 427<br />
21.5 Layout and Display Elements .......................................................................................... 427<br />
21.5.1 .................................................................................................................. 429<br />
21.5.2 .................................................................................................................. 429<br />
21.5.3 and .......................................................................................... 430<br />
21.5.4 ..................................................................................................................... 430<br />
21.5.5 .................................................................................................................... 431<br />
21.5.6 ..................................................................................................................... 432<br />
21.5.7 ...................................................................................................................... 433<br />
21.5.8 ......................................................................................................................... 434<br />
21.5.9 .......................................................................................................... 434<br />
21.5.10 ................................................................................................................. 434<br />
21.6 Charts in <strong>Zen</strong> Reports ...................................................................................................... 436<br />
21.7 Stylesheet Control Elements ............................................................................................ 437<br />
21.7.1 ........................................................................................................................ 437<br />
21.7.2 .................................................................................................................... 438<br />
21.7.3 ................................................................................................................... 438<br />
21.8 <strong>Zen</strong> Reports from a Web Browser .................................................................................... 438<br />
21.8.1 Sample XHTML Output ........................................................................................ 439<br />
21.8.2 Sample XML Data View ........................................................................................ 440<br />
21.9 Configuring <strong>Zen</strong> for PDF Output ..................................................................................... 440<br />
21.10 Troubleshooting <strong>Zen</strong> Reports ......................................................................................... 441<br />
21.11 <strong>Zen</strong> Reports from a Command Line .............................................................................. 443<br />
22 <strong>Zen</strong> Wizards .............................................................................................................................. 445<br />
22.1 New <strong>Zen</strong> Application Wizard ........................................................................................... 445<br />
<strong>Using</strong> <strong>Zen</strong><br />
xi
22.2 New <strong>Zen</strong> Component Wizard ........................................................................................... 446<br />
22.3 New <strong>Zen</strong> Page Wizard ...................................................................................................... 447<br />
22.4 New <strong>Zen</strong> Report Wizard ................................................................................................... 448<br />
22.5 Studio Assist ..................................................................................................................... 450<br />
22.6 <strong>Zen</strong> Chart Wizard ............................................................................................................. 450<br />
22.7 <strong>Zen</strong> Element Wizard ......................................................................................................... 452<br />
22.8 <strong>Zen</strong> Method Wizard ......................................................................................................... 453<br />
22.9 <strong>Zen</strong> Style Wizard .............................................................................................................. 455<br />
Index ............................................................................................................................................... 459<br />
xii<br />
<strong>Using</strong> <strong>Zen</strong>
List of Figures<br />
How to Access the Sample <strong>Zen</strong> Code in Studio ................................................................................ 24<br />
How Caché Server Pages Work ......................................................................................................... 26<br />
How <strong>Zen</strong> Pages Work ........................................................................................................................ 30<br />
<strong>Zen</strong> Application with Pages and Components ................................................................................... 32<br />
<strong>Zen</strong> Page Synchronized on Client and Server at Runtime ................................................................ 33<br />
Defining the Look and Feel of a <strong>Zen</strong> Page ........................................................................................ 34<br />
Use of Panes on a <strong>Zen</strong> Page .............................................................................................................. 55<br />
Cascade of Style Definitions ............................................................................................................. 65<br />
Layout Conventions for <strong>Zen</strong> Charts ................................................................................................ 128<br />
How <strong>Zen</strong> Plots Pie Charts by Item .................................................................................................. 139<br />
How <strong>Zen</strong> Plots Pie Charts by Series ................................................................................................ 140<br />
<strong>Zen</strong> Pie Chart from Both Items and Series ...................................................................................... 141<br />
Data Series Count and Size ............................................................................................................. 143<br />
Class Inheritance Among Form and Control Components .............................................................. 157<br />
Data Model for the Dynamic Grid Control ..................................................................................... 210<br />
Model View Controller Architecture ............................................................................................... 220<br />
Data Model Classes ......................................................................................................................... 221<br />
Data Controller and Data View Classes .......................................................................................... 223<br />
Data Model with Name-Value Pairs ................................................................................................ 258<br />
Data Model with Data Series .......................................................................................................... 259<br />
<strong>Zen</strong> Navigation Components ........................................................................................................... 263<br />
Base Classes for Custom Components ............................................................................................ 334<br />
Sample Log of <strong>Zen</strong> Events .............................................................................................................. 372<br />
How a <strong>Zen</strong> Report Class Produces a Report ................................................................................... 404<br />
XSL-FO to PDF Transformation Log ............................................................................................. 442<br />
XSL-FO Prior to PDF Rendering .................................................................................................... 443<br />
<strong>Using</strong> <strong>Zen</strong><br />
xiii
List of Tables<br />
Naming Conventions ......................................................................................................................... 22<br />
Component Concepts ........................................................................................................................ 38<br />
Group Layout and Style Attributes .................................................................................................... 51<br />
Component Style Attributes .............................................................................................................. 57<br />
Where and How to Override Built-in Styles ..................................................................................... 68<br />
QueryInfo Properties ......................................................................................................................... 78<br />
predicate Values ............................................................................................................ 86<br />
SVG Component Attributes ............................................................................................................ 110<br />
Meter Component Attributes ........................................................................................................... 113<br />
Chart Layout and Style Attributes ................................................................................................... 146<br />
Chart Axis Attributes ....................................................................................................................... 152<br />
Form Component Attributes ............................................................................................................ 158<br />
Form Submit Sequence ................................................................................................................... 165<br />
Control Component Attributes ........................................................................................................ 170<br />
List Box Component Attributes ....................................................................................................... 189<br />
Combo Box Component Attributes ................................................................................................. 193<br />
Display Sequence .................................................................................................... 201<br />
Controls Based on Property Types ............................................................................ 244<br />
Data Model Class Parameters ......................................................................................................... 253<br />
Data Model Property Parameters .................................................................................................... 253<br />
Object Data Model Callback Methods ............................................................................................ 255<br />
Custom Data Model Class Methods ................................................................................................ 260<br />
Menu Cell Attributes ....................................................................................................................... 268<br />
Tab Group Attributes ....................................................................................................................... 275<br />
Options for Extending <strong>Zen</strong> .............................................................................................................. 328<br />
Extending <strong>Zen</strong> with Composite Components ................................................................................. 328<br />
Extending <strong>Zen</strong> with Custom Components ...................................................................................... 332<br />
Custom Component Base Classes ................................................................................................... 333<br />
Datatype Classes ............................................................................................................................. 340<br />
Component Class Method Conventions .......................................................................................... 343<br />
Extending <strong>Zen</strong> with Custom Meters ............................................................................................... 353<br />
Application Class Elements ............................................................................................................ 362<br />
Page Class Parameters ..................................................................................................................... 364<br />
Special Variables on the Server Side ............................................................................................... 365<br />
Client-Side Functions and Variables ............................................................................................... 373<br />
Page Class Method Conventions ..................................................................................................... 375<br />
Page Class Server-side Callback Methods ...................................................................................... 377<br />
xiv<br />
<strong>Using</strong> <strong>Zen</strong>
Page Class Server Methods ............................................................................................................. 378<br />
Page Class Client-side Callback Methods ....................................................................................... 380<br />
Page Class Client-side Methods ...................................................................................................... 380<br />
Page Class Client-side Component Methods .................................................................................. 381<br />
Report Class Parameters .................................................................................................................. 411<br />
Report Display Attributes ................................................................................................................ 428<br />
<strong>Using</strong> <strong>Zen</strong><br />
xv
Preface<br />
This book is intended for Web application developers. It describes how to use <strong>Zen</strong>, the <strong>InterSystems</strong><br />
framework for Web application development.<br />
General Information<br />
The first several chapters in the book provide the general information required to become productive<br />
with <strong>Zen</strong>. Readers who are new to <strong>Zen</strong> should read the following chapters in sequence:<br />
• Introducing <strong>Zen</strong><br />
• <strong>Zen</strong> Tutorial<br />
• <strong>Zen</strong> Client and Server<br />
• <strong>Zen</strong> Application Concepts<br />
Experienced <strong>Zen</strong> programmers can choose specific topics from among the remaining chapters.<br />
Introducing <strong>Zen</strong> Components<br />
<strong>Zen</strong> provides a large set of Web page components and a variety of mechanisms for laying them out<br />
on the page. The following chapters provide information that applies to all <strong>Zen</strong> components:<br />
• <strong>Zen</strong> Component Concepts<br />
• <strong>Zen</strong> Layout<br />
• <strong>Zen</strong> Style<br />
Essential <strong>Zen</strong> Components<br />
The following chapters provide details about the most essential built-in <strong>Zen</strong> components:<br />
• <strong>Zen</strong> Tables<br />
• <strong>Zen</strong> and SVG<br />
• <strong>Zen</strong> Charts<br />
• <strong>Zen</strong> Forms<br />
• <strong>Zen</strong> Controls<br />
Complex <strong>Zen</strong> Components<br />
The following chapters describe the more complex <strong>Zen</strong> components, and explain how to extend the<br />
<strong>Zen</strong> component library with custom code.<br />
<strong>Using</strong> <strong>Zen</strong> 1
Preface<br />
• Model View Controller<br />
• Navigation Components<br />
• Popup Windows and Dialogs<br />
• Other <strong>Zen</strong> Components<br />
• Custom Components<br />
Developing <strong>Zen</strong> Applications<br />
The following chapters describe additional programming issues relating to <strong>Zen</strong>:<br />
• <strong>Zen</strong> Application Programming<br />
• <strong>Zen</strong> Security<br />
• <strong>Zen</strong> Localization<br />
• <strong>Zen</strong> Reports<br />
• <strong>Zen</strong> Wizards<br />
2 <strong>Using</strong> <strong>Zen</strong>
1<br />
Introducing <strong>Zen</strong><br />
Welcome to <strong>Zen</strong>!<br />
The <strong>Zen</strong> application framework provides a simple way to rapidly create complex, data-rich Web<br />
applications by assembling pre-built object components. These components automatically create<br />
standard HTML and JavaScript needed to render complex Web applications. Moreover, they provide<br />
a common object model that is shared between the user’s browser and the application logic running<br />
on the server.<br />
<strong>Zen</strong> is based on <strong>InterSystems</strong>’ successful Caché Server Page (CSP) and Caché Object Database technologies.<br />
These technologies offer a robust, scalable, and portable platform for hosting Web applications.<br />
<strong>Zen</strong> does not replace or deprecate Caché Server Pages in any way. Instead, <strong>Zen</strong> makes the development<br />
of web-based applications easier while building upon the basic features provided by CSP: performance,<br />
data access, security, localization, and configuration.<br />
1.1 The <strong>Zen</strong> Demo<br />
<strong>Zen</strong> includes a sample application, which you can try out as follows:<br />
1. Start your browser. You may use Firefox or Internet Explorer.<br />
2. Enter this URI:<br />
http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
If you are unsure of the port number, start the System Management Portal. At the top of the page,<br />
click About. View the Web Server Port setting.<br />
<strong>Using</strong> <strong>Zen</strong> 3
Introducing <strong>Zen</strong><br />
1.2 Supported Browsers<br />
The browser you use with <strong>Zen</strong> must support SVG (Scalable Vector Graphics). <strong>Zen</strong> supports the following<br />
browsers:<br />
• Firefox 1.5 or later. This download is available from:<br />
http://www.mozilla.com/firefox/<br />
Support for SVG is built into Firefox.<br />
• Internet Explorer 6.0 or later.<br />
IE 6.0 does not support SVG natively, so you must download the free SVG Viewer from this<br />
Adobe site:<br />
http://www.adobe.com/svg/<br />
Note:<br />
<strong>InterSystems</strong> recommends that you use Firefox as your primary development browser, and<br />
reserve Internet Explorer for compatibility testing. Firefox offers better JavaScript and HTML<br />
troubleshooting options and can help track down programming problems. This is especially<br />
true if you use some of the many developer plug-ins available for Firefox.<br />
1.3 Benefits of <strong>Zen</strong><br />
The benefits of using <strong>Zen</strong> include:<br />
• Rapid Development—Assembling applications from pre-built components is a proven method for<br />
creating user interfaces rapidly. <strong>Zen</strong> makes it possible to use this approach for Web-based applications.<br />
• Simplicity—<strong>Zen</strong> uses a standard HTML client, so there are no additional client components<br />
required. There is no “middle” tier between server and client, so <strong>Zen</strong> applications are much easier<br />
to develop, deploy, and support.<br />
• Extensive Library of Components—The <strong>Zen</strong> library comes with a large set of pre-built components.<br />
These include all the standard control types as well as data-aware combo boxes, tables, grids, tabs,<br />
tree controls, menus, and grouping components.<br />
• Object Database Integration—<strong>Zen</strong> is tightly integrated with the underlying Caché object database.<br />
The <strong>Zen</strong> client and server communicate by sending objects back and forth. Underlying details<br />
such as encryption and data marshalling are handled automatically using proven Caché technology.<br />
4 <strong>Using</strong> <strong>Zen</strong>
Background Reading<br />
• Code Generation—Much of the code and business logic is generated automatically from higherlevel<br />
models, ensuring consistency and rapid development.<br />
• Extensibility—You can easily modify the look and feel of <strong>Zen</strong> applications by using standard CSS<br />
style sheets; by supplying different property values for the <strong>Zen</strong> components; or by creating your<br />
own custom components.<br />
• Integrated use of SVG—<strong>Zen</strong> lets you add interactive graphics to Web applications by means of a<br />
set of SVG (Scalable Vector Graphics) components. These components include pre-built charts<br />
and meters. In addition, you can create new graphical components.<br />
• Client Independence—<strong>Zen</strong> applications run in either Firefox or Internet Explorer. The <strong>Zen</strong> components<br />
insulate applications from the differences in behavior of these browsers.<br />
• Security—<strong>Zen</strong> offers tight integration with the security model provided by the Caché object<br />
database.<br />
• Form Handling—The <strong>Zen</strong> framework lets you define forms that contain a variety of controls for<br />
displaying and editing of data. The framework includes extensible support for loading data into<br />
forms; validating the contents of forms; and saving form contents.<br />
• Page Layout—<strong>Zen</strong> includes an extensible framework for specifying the grouping and layout of<br />
components on a Web page.<br />
• Event Management—<strong>Zen</strong> applications can easily define how their components respond to user<br />
events. All events are handled by invoking methods that can be defined to run within the client<br />
browser or on the data server.<br />
• Multilingual Support—For applications that must support multiple languages, <strong>Zen</strong> includes a<br />
mechanism that tracks which titles and captions need to be localized, and automatically builds a<br />
database of these values. This database can be exported as XML and given to a translator for<br />
conversion into other languages. At runtime, <strong>Zen</strong> automatically displays pages in the user’s preferred<br />
language.<br />
• Document Output—<strong>Zen</strong> includes an extensible framework for specifying the data contents and<br />
display layout of reports in XHTML or PDF format.<br />
1.4 Background Reading<br />
Before using <strong>Zen</strong>, you need a good understanding of the following topics:<br />
• HTML, JavaScript, and Cascading Style Sheets (CSS).<br />
Many excellent books are available through the Internet and commercial bookstores.<br />
• Caché, Caché Objects, Caché Server Pages, and Caché SQL.<br />
<strong>Using</strong> <strong>Zen</strong> 5
Introducing <strong>Zen</strong><br />
Depending on your level of experience, you might want to review the following books from the<br />
<strong>InterSystems</strong> online documentation category Caché Development Guides:<br />
- <strong>Using</strong> Caché Objects<br />
- <strong>Using</strong> Caché ObjectScript<br />
- <strong>Using</strong> Caché Server Pages (CSP)<br />
- <strong>Using</strong> Caché SQL<br />
6 <strong>Using</strong> <strong>Zen</strong>
2<br />
<strong>Zen</strong> Tutorial<br />
This chapter describes how to create some simple Web pages using <strong>Zen</strong>. The chapter is organized as<br />
a step-by-step tutorial. Topics include:<br />
• Hello World<br />
• Creating a <strong>Zen</strong> Application<br />
• Creating a <strong>Zen</strong> Page<br />
• Creating a <strong>Zen</strong> Report<br />
• <strong>Zen</strong> Naming Conventions<br />
• <strong>Zen</strong> Sample Applications<br />
2.1 Hello World<br />
The following steps display “Hello world!” on a <strong>Zen</strong> page:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4.<br />
Choose File > New or Ctrl-N or the<br />
5. Click the Custom tab.<br />
6. Click the New <strong>Zen</strong> Page icon.<br />
icon.<br />
7. Click OK.<br />
<strong>Using</strong> <strong>Zen</strong> 7
<strong>Zen</strong> Tutorial<br />
8. For Package Name choose ZENDemo.<br />
9. In the Class Name field, type:<br />
hello<br />
10. For Application Name choose ZENDemo.Application.<br />
11. Click Next.<br />
12. Click Finish.<br />
13. Position the cursor at the start of this line:<br />
<br />
14. Press Enter.<br />
15. Move the cursor up to the blank line.<br />
16. Type a left angle bracket:<br />
<<br />
A context-sensitive list of XML elements displays.<br />
17. Click button.<br />
18. Press Enter.<br />
19. Type a space. A context-sensitive list of XML attributes displays.<br />
20. Click caption.<br />
21. Press Enter.<br />
22. Type:<br />
23.<br />
24.<br />
Hello world!"/><br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the<br />
icon.<br />
icon.<br />
Your simple new <strong>Zen</strong> page displays “Hello world!” on the face of a button.<br />
25. Also try steps 13–24 with:<br />
<br />
<br />
<br />
If you encounter difficulties during this exercise, return to The <strong>Zen</strong> Demo and Supported Browsers in<br />
the previous chapter. These topics provide useful background information for getting started with <strong>Zen</strong>.<br />
8 <strong>Using</strong> <strong>Zen</strong>
Creating a <strong>Zen</strong> Application<br />
2.2 Creating a <strong>Zen</strong> Application<br />
A <strong>Zen</strong> application class extends %ZEN.application to provide application-wide styling behavior. In this<br />
exercise you will create a <strong>Zen</strong> new application class, as follows:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4.<br />
Choose File > New or Ctrl-N or the<br />
5. Select the Custom tab.<br />
6. Click the New <strong>Zen</strong> Application icon.<br />
icon.<br />
7. Click OK.<br />
The <strong>Zen</strong> Application Wizard presents the fields shown in the following table. For this exercise,<br />
enter the values shown in the right-hand column of the table.<br />
Field<br />
Package Name<br />
Class Name<br />
Application Name<br />
Description<br />
Meaning<br />
The package that will contain<br />
the new application class.<br />
The class name of the new<br />
application class.<br />
The logical name of the<br />
application.<br />
Any text that you want to use<br />
to describe the application.<br />
Value to Enter<br />
MyApp<br />
MyNewApp<br />
My New <strong>Zen</strong> Application<br />
This is my first new <strong>Zen</strong><br />
application.<br />
Click Finish.<br />
8. The <strong>Zen</strong> Application Wizard creates and displays a skeletal application class. It includes some<br />
pre-defined class parameters and an XData Style block as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 9
<strong>Zen</strong> Tutorial<br />
/// This is my first new <strong>Zen</strong> application.<br />
Class MyApp.MyNewApp Extends %ZEN.application<br />
{<br />
/// This is the name of this application.<br />
Parameter APPLICATIONNAME = "My New <strong>Zen</strong> Application";<br />
/// This is the URL of the main starting page of this application.<br />
Parameter HOMEPAGE = "";<br />
/// This Style block contains application-wide CSS style definitions.<br />
XData Style<br />
{<br />
<br />
}<br />
}<br />
<br />
9.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
icon.<br />
2.3 Creating a <strong>Zen</strong> Page<br />
A <strong>Zen</strong> page class extends %ZEN.Component.page to define the contents and behavior of a Web page.<br />
In this exercise you will create a new <strong>Zen</strong> page class in several steps.<br />
2.3.1 Step 1: New Page Wizard<br />
Create the new class as follows:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4.<br />
Choose File > New or Ctrl-N or the<br />
5. Select the Custom tab.<br />
6. Click the New <strong>Zen</strong> Page icon.<br />
icon.<br />
7. Click OK.<br />
The <strong>Zen</strong> Page Wizard presents the fields shown in the following table. For this exercise, enter the<br />
values shown in the right-hand column of the table.<br />
10 <strong>Using</strong> <strong>Zen</strong>
Creating a <strong>Zen</strong> Page<br />
Field<br />
Package Name<br />
Class Name<br />
Application<br />
Page Name<br />
Domain<br />
Description<br />
Page type<br />
Meaning<br />
The package that will<br />
contain the page class.<br />
The page class name.<br />
The package and class<br />
name of the application<br />
that this page belongs to.<br />
The logical name of this<br />
page within its application.<br />
The domain this page will<br />
use for localization of<br />
caption text.<br />
Any text that you want to<br />
use to describe the page.<br />
Regular page, or subclass<br />
of a template page class.<br />
Value to Enter<br />
MyApp<br />
MyNewPage<br />
MyApp.MyNewApp<br />
My Home Page<br />
For this exercise, leave the Domain field<br />
empty.<br />
My very first <strong>Zen</strong> page class.<br />
For this exercise, leave the Page type<br />
field with its default selection of Page.<br />
Click Next.<br />
8. The wizard prompts you to select an initial page layout, for example:<br />
• Column 2 — two columns, plus space for a title along the top<br />
• Title Page — space for a title along the top<br />
• Default — no pre-defined layout<br />
For this exercise, click Title Page. Then click Finish.<br />
9. The New Page Wizard creates and displays a skeletal <strong>Zen</strong> page with pre-defined class parameters<br />
and the XML blocks XData Style and XData Contents, as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 11
<strong>Zen</strong> Tutorial<br />
/// My very first <strong>Zen</strong> page class.<br />
Class MyApp.MyNewPage Extends %ZEN.Component.page<br />
{<br />
/// Class name of application this page belongs to.<br />
Parameter APPLICATION = "MyApp.MyNewApp";<br />
/// Displayed name of this page.<br />
Parameter PAGENAME = "My Home Page";<br />
/// Domain used for localization.<br />
Parameter DOMAIN = "";<br />
/// This Style block contains page-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
/* style for title bar */<br />
#title {<br />
background: #C5D6D6;<br />
color: black;<br />
font-family: Verdana;<br />
font-size: 1.5em;<br />
font-weight: bold;<br />
padding: 5px;<br />
border-bottom: 1px solid black;<br />
text-align: center;<br />
}<br />
<br />
}<br />
/// This XML block defines the contents of this page.<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
}<br />
}<br />
Title<br />
<br />
<br />
<br />
<br />
The XML blocks in this page class work together as follows:<br />
• XData Style defines a style rule called #title that defines a background color, padding,<br />
borders, and font characteristics for HTML output.<br />
• XData Contents provides an XMLNamespace keyword. The value<br />
http://www.intersystems.com/zen enables the Studio Assist type-ahead feature for<br />
built-in <strong>Zen</strong> components. You first experienced this feature during the Hello World exercise.<br />
• XData Contents uses the element to define a page object.<br />
• XData Contents uses the element to define a simple HTML excerpt for display in the<br />
browser. The id value title creates the connection between the html object and the #title<br />
rule from XData Style. The html object formats a string of text, Title. The resulting output<br />
functions as a simple title bar for the page.<br />
• XData Contents provides an empty . Later exercises add components here.<br />
12 <strong>Using</strong> <strong>Zen</strong>
Creating a <strong>Zen</strong> Page<br />
10.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
11.<br />
Choose View > Web Page or the icon.<br />
Your new <strong>Zen</strong> page displays as follows:<br />
icon.<br />
If you encounter difficulties when displaying any <strong>Zen</strong> page from Studio, you can display the page by<br />
opening a browser session and entering a URI in this format:<br />
http://localhost:57772/csp/samples/MyApp.MyNewPage.cls<br />
Where:<br />
• 57772 is the Web server port number assigned to Caché<br />
• samples is the namespace that contains the <strong>Zen</strong> page class (all-lowercase)<br />
• MyApp.MyNewPage is the <strong>Zen</strong> page package and class name (case-sensitive)<br />
2.3.2 Step 2: XData Contents Block<br />
In this exercise you will modify the element to add a simple button to the page. You can do<br />
this by typing text into the XData Contents block, or by using templates to generate a element<br />
with the correct syntax. This exercise uses both techniques:<br />
1. In Studio, open the page class.<br />
2. Select the text Title within the element. Replace Title with a meaningful string, for<br />
example:<br />
<strong>Zen</strong> Exercise Results<br />
3. Remove this line just after the element:<br />
<br />
Place the cursor between and .<br />
4. Choose Tools > Templates > Templates or press Ctrl-T to display the Studio Templates dialog.<br />
Choose <strong>Zen</strong> Element Wizard. Click OK.<br />
5. In the drop-down list of XML elements, choose button. Click Next. Add properties as follows:<br />
• In the caption row, click Edit. Enter a string value and click OK. For example:<br />
<strong>Using</strong> <strong>Zen</strong> 13
<strong>Zen</strong> Tutorial<br />
Press Me<br />
• In the id row, click Edit. Enter a string value and click OK. For example:<br />
myButton<br />
• In the onclick row, click Edit. Type a short JavaScript expression. For this exercise, use the<br />
following expression:<br />
zenPage.btnClick();<br />
Click OK.<br />
6. Click Finish. The XData Contents block now looks like this:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<strong>Zen</strong> Exercise Results<br />
<br />
<br />
<br />
<br />
}<br />
New additions to this XData Contents block accomplish the following:<br />
• Define a button object as a child of the vgroup object. This places the button at the top lefthand<br />
corner of the display, under the title. The button is an instance of the<br />
%ZEN.Component.button class.<br />
• The id value myButton provides a way to find the button object programmatically.<br />
• The caption value Press Me indicates the text that will be displayed on the button when the<br />
page appears.<br />
• The onclick value zenPage.btnClick(); is a JavaScript expression that will be executed<br />
on the client when a user clicks this button.<br />
• At present, when you click this button it does nothing. The next exercise changes this.<br />
7.<br />
8.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the icon.<br />
Your new <strong>Zen</strong> page displays as follows:<br />
icon.<br />
14 <strong>Using</strong> <strong>Zen</strong>
Creating a <strong>Zen</strong> Page<br />
2.3.3 Step 3: Client-Side Method<br />
In the previous step you added this JavaScript expression to your definition:<br />
zenPage.btnClick();<br />
This expression executes a method called btnClick in an object called zenPage. zenPage is the<br />
JavaScript variable that represents the page object on the client side. btnClick is available to the<br />
JavaScript page object only if you define it in your <strong>Zen</strong> page class as a client-side method.<br />
In this exercise, you will add a JavaScript client-side method to your <strong>Zen</strong> page class, as follows:<br />
1. In Studio, open the page class.<br />
2. Position the cursor just below the closing curly brace of the XData Contents block.<br />
3. Choose Tools > Templates > Templates or press Ctrl-T to display the Studio Template dialog.<br />
Choose <strong>Zen</strong> Method Wizard. Click OK. The following dialog displays:<br />
Edit the dialog as follows:<br />
• Enter the name btnClick<br />
• Choose is an instance method<br />
• Choose runs on the client<br />
• Enter a description.<br />
• Uncheck the Try/Catch checkbox.<br />
• Click Finish. Your new method appears in the page class as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 15
<strong>Zen</strong> Tutorial<br />
///What to do if the user clicks this button.<br />
Method btnClick() [Language = JavaScript]<br />
{<br />
// TODO: implement<br />
alert('Client Method');<br />
}<br />
4. Change the code within curly braces so the method now looks like this:<br />
5.<br />
6.<br />
///What to do if the user clicks this button.<br />
Method btnClick() [Language = JavaScript]<br />
{<br />
alert('Hello, World!');<br />
}<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the<br />
icon.<br />
icon.<br />
7. Click the “Press Me” button. Your JavaScript alert message displays:<br />
8. Click OK to close the popup.<br />
Some important things to notice about the btnClick method:<br />
• It is defined as an instance method (it does not use the ClassMethod keyword).<br />
• Its Language keyword is set to JavaScript. This means that the implementation of this method<br />
uses JavaScript. Studio syntax-colors and validates this method as JavaScript.<br />
• When this class is compiled, the btnClick method will not be available as a callable method on<br />
the server. It will, however, be made available as an instance method of the zenPage object on<br />
the client.<br />
• The class compiler resolves inheritance. This means that you can define JavaScript methods within<br />
a super class and they will automatically be available to any subclasses. While this is possible to<br />
accomplish in traditional JavaScript, it is also very tedious and error-prone. A lot of the power of<br />
<strong>Zen</strong> comes from this ability to support inheritance on both the server and client.<br />
• The body of this method uses the standard JavaScript alert method to display a message on the<br />
client.<br />
• At runtime, this method is run within the client (browser) environment.<br />
• The method is defined within the same logical unit (that is, the class) as the page definition that<br />
references it. This makes pages easy to develop and maintain.<br />
16 <strong>Using</strong> <strong>Zen</strong>
Creating a <strong>Zen</strong> Page<br />
2.3.4 Step 4: Viewing the HTML Output<br />
While viewing your <strong>Zen</strong> page in the browser, use the View Source option to look at the HTML served<br />
by the <strong>Zen</strong> page. You will see that the <strong>Zen</strong> page consists of the following elements, from top to bottom:<br />
• A standard HTML header<br />
• A set of included elements such as pre-generated JavaScript (for library components) and CSS<br />
(stylesheet) files.<br />
• Some generated JavaScript utility code (for error detection, timeout management, encrypted server<br />
calls, etc.)<br />
• JavaScript class definitions for any user-defined classes used on this page (such as the page object<br />
itself).<br />
• JavaScript code to create any client-side objects defined by the page. This is a client-side version<br />
of the same objects defined in the page’s XData Contents block.<br />
• HTML needed to display any components that generate HTML (such as the button component).<br />
• If needed, additional JavaScript code to “finalize” the client-side object model.<br />
2.3.5 Step 5: Server-Side Method<br />
In this exercise, you will make a simple modification in your new <strong>Zen</strong> page. This modification<br />
demonstrates the ability to invoke server logic from within a client page, as follows:<br />
1. In Studio, open the page class.<br />
2. <strong>Using</strong> techniques from the previous exercises, add a new button inside the XData Contents block.<br />
Give the new button the attribute values listed in the following table.<br />
Attribute<br />
id<br />
caption<br />
onclick<br />
Value to Enter<br />
myButtonToo<br />
No, Me!<br />
zenPage.BtnClickMe();<br />
Your XData Contents block should now resemble this one:<br />
<strong>Using</strong> <strong>Zen</strong> 17
<strong>Zen</strong> Tutorial<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<strong>Zen</strong> Exercise Results<br />
<br />
<br />
<br />
<br />
<br />
}<br />
3. Position the cursor just below the closing curly brace of the XData Contents block.<br />
4. Choose Tools > Templates > Templates or press Ctrl-T to display the Studio Template dialog.<br />
Choose <strong>Zen</strong> Method Wizard. Click OK. The following dialog displays:<br />
Edit the dialog as follows:<br />
• Enter the name BtnClickMe<br />
• Choose is an instance method<br />
• Choose runs on the server<br />
• Enter a description.<br />
• Uncheck the Try/Catch checkbox.<br />
• Click Finish. Your new method appears in the page class as follows:<br />
///When the user clicks the button, ask<br />
///the server which version it is running.<br />
Method BtnClickMe() [<strong>Zen</strong>Method]<br />
{<br />
// TODO: implement<br />
&js<br />
Quit<br />
}<br />
18 <strong>Using</strong> <strong>Zen</strong>
Creating a <strong>Zen</strong> Page<br />
5. Change the code within curly braces so the method now looks like this:<br />
///When the user clicks the button, ask<br />
///the server which version it is running<br />
Method BtnClickMe() [<strong>Zen</strong>Method]<br />
{<br />
Set msg = $ZVERSION<br />
&js<br />
Quit<br />
}<br />
6.<br />
7.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the icon.<br />
Your new <strong>Zen</strong> page displays as follows:<br />
icon.<br />
8. Click the “No, Me!” button. The following popup message appears. It displays the text returned<br />
by the ObjectScript $ZVERSION utility. This text is a full description of the Caché version that<br />
you are running:<br />
9. Click OK to close the popup.<br />
10. Use the View Source option of your browser to look at the HTML.<br />
Some important things to notice about the BtnClickMe method:<br />
• It is defined as an instance method.<br />
• It omits the Language keyword. This means that this method will use the default server scripting<br />
language (ObjectScript or Caché Basic, in this case ObjectScript).<br />
• It executes on the server but (as further notes explain) it also sends a hyperevent to the client.<br />
• It uses the <strong>Zen</strong>Method keyword. The <strong>Zen</strong>Method keyword means that this is a server-side method<br />
that can be called from the client. Even when this method is called from within the client (browser)<br />
environment, it is still executed on the server.<br />
<strong>Using</strong> <strong>Zen</strong> 19
<strong>Zen</strong> Tutorial<br />
• The method assigns the value of the $ZVERSION utility to the variable msg, then sends msg to<br />
the client so that the user can see the value in a JavaScript alert popup. The statement:<br />
&js< alert('#(msg)#'); ><br />
is an example of embedded JavaScript syntax. While executing your BtnClickMe method on<br />
the server, <strong>Zen</strong> finds the snippet of JavaScript code between &js< and > and sends this snippet<br />
to the client for execution.<br />
Note:<br />
This behavior is provided by the CSP hyperevent mechanism. For details see the book<br />
<strong>Using</strong> Caché Server Pages (CSP).<br />
• Within the embedded JavaScript, the syntax:<br />
#(msg)#<br />
is the convention for transferring the value of the variable msg from ObjectScript code executing<br />
on the server to embedded JavaScript executing on the client. For details, see <strong>Zen</strong> Runtime<br />
Expressions.<br />
• The client-side zenPage object can invoke your server-side BtnClickMe method.<br />
Because you defined BtnClickMe as an instance method, the server needs the current client-side<br />
object’s complete state to be able to execute the method.<br />
When zenPage invokes your server-side method, the client-side implementation of BtnClickMe<br />
gathers up any argument and object context information available on the client side, serializes the<br />
entire page object and sends it through to the server, then invokes the server-side method, all using<br />
the CSP session-encrypted hyperevent mechanism.<br />
• BtnClickMe does not return a value. This is intentional. When you use CSP hyperevents, a method<br />
with no return value automatically runs asynchronously (does not wait for a response). This way,<br />
the user interface does not appear to “freeze” as it would if it had to wait for a method to return a<br />
value.<br />
2.4 Creating a <strong>Zen</strong> Report<br />
A <strong>Zen</strong> report page extends %ZEN.Report.reportPage to display a database report. <strong>Zen</strong> reports support<br />
a variety of useful output formats including XHTML and PDF. In this exercise you will copy and<br />
modify an existing <strong>Zen</strong> report class and view it as XHTML.<br />
If you have a new Caché installation, you must first generate data records for the SAMPLES namespace.<br />
You only need to do this once per Caché installation. Enter the following URI in the browser:<br />
http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />
20 <strong>Using</strong> <strong>Zen</strong>
Where 57772 is the Web server port number that you have assigned to Caché.<br />
Now begin the report exercise as follows:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4. Choose Tools > Copy Class.<br />
Creating a <strong>Zen</strong> Report<br />
5. The Class Copy dialog presents the fields shown in the following table. For this exercise, enter<br />
the values shown in the right-hand column of the table.<br />
Field<br />
Copy Class<br />
To<br />
Meaning<br />
The class to copy.<br />
The new class to create.<br />
Value to Enter<br />
ZENApp.MyReport<br />
MyApp.MyNewReport<br />
Check the Replace Instances of Class Name box.<br />
Click OK.<br />
6. The new class definition for MyApp.MyNewReport displays in Studio.<br />
7.<br />
8.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the<br />
icon.<br />
9. The report displays a report title and header block, followed by a table of information for each<br />
sales person in the database:<br />
icon.<br />
<strong>Using</strong> <strong>Zen</strong> 21
<strong>Zen</strong> Tutorial<br />
2.5 <strong>Zen</strong> Naming Conventions<br />
<strong>Zen</strong> programs are case-sensitive. If you are not experienced with case-sensitive programming, case<br />
might be your biggest adjustment in using <strong>Zen</strong>. Remember that a is not the same as A.<br />
The following naming conventions apply throughout the <strong>Zen</strong> code. These conventions use case to<br />
distinguish between different categories of method or property. myMethodName and MyMethodName<br />
are not the same name.<br />
Naming Conventions<br />
Convention<br />
Client-side methods are defined using the Language=JavaScript<br />
key phrase, and are written in JavaScript. They can be called from<br />
the client and, when called, run on the client. These names start<br />
with a lowercase letter and use an initial capital letter for each<br />
successive word (in-word capitalization). The same is true of<br />
client-only properties.<br />
<strong>Zen</strong> methods are defined using the keyword <strong>Zen</strong>Method. They<br />
can be called from the client, but are executed on the server.These<br />
methods are written in ObjectScript or Basic, but they may include<br />
embedded JavaScript that calls back to the client. Their names<br />
start with an uppercase letter and use in-word capitalization.<br />
Server-side methods use no special keyword. They are written<br />
in ObjectScript or Basic. They are available to be called from code<br />
that is executing on the server and, when called, they run on the<br />
server.These method names start with the % character. Server-only<br />
properties use this naming convention too.<br />
Typically, <strong>Zen</strong> class names start with lowercase and use in-word<br />
capitalization, similar to the conventions for client-side methods<br />
and properties. The exceptions to this rule include some of the<br />
server-only utility classes, which begin with an uppercase letter.<br />
Attribute and property names start with lowercase and use in-word<br />
capitalization, except for event handlers and callbacks.<br />
Attributes that identify event handlers for components follow the<br />
JavaScript convention of all-lowercase.<br />
Attributes that identify server-side callbacks for components start<br />
with On (capital letter O) and use in-word capitalization.<br />
Example<br />
myMethodName<br />
MyMethodName<br />
%MyMethodName<br />
tablePane<br />
filterOp<br />
onmousedown<br />
OnCreateDataSet<br />
22 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> offers many built-in variables, as described in <strong>Zen</strong> Application Programming. The most important<br />
of these are the two variables that represent the <strong>Zen</strong> page object on the client and server sides. These<br />
two variables conform to <strong>Zen</strong> naming conventions for client and server identifiers, as follows:<br />
• In JavaScript code that runs on the client side, the page object is zenPage<br />
• In ObjectScript or Basic code that runs on the server side, the page object is %page<br />
<strong>Zen</strong> Sample Applications<br />
2.6 <strong>Zen</strong> Sample Applications<br />
If you are an experienced Caché user, you are already familiar with the SAMPLES namespace. In<br />
particular, the sample application Cinema is a favorite with users learning about Caché Server Pages<br />
(CSP). <strong>Zen</strong> offers a large number of sample pages, organized into four packages in the SAMPLES<br />
namespace.<br />
If you have a new Caché installation, you must first generate data records for the SAMPLES namespace.<br />
You only need to do this once per Caché installation. Enter the following URI in the browser:<br />
http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
Now you can view the <strong>Zen</strong> sample code at any time by following these steps:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4. In the Workspace window, choose the Namespace tab and open the Classes category.<br />
Packages ZENApp, ZENDemo, ZENMVC, and ZENTest are available for you to explore.<br />
<strong>Using</strong> <strong>Zen</strong> 23
<strong>Zen</strong> Tutorial<br />
How to Access the Sample <strong>Zen</strong> Code in Studio<br />
2.7 <strong>Zen</strong> Wizards<br />
<strong>Zen</strong> supplies a rich set of application programming wizards that you can run from within Caché Studio.<br />
The exercises in this chapter use several of them. For a complete list and description of the available<br />
options, see the chapter <strong>Zen</strong> Wizards at the end of this book.<br />
24 <strong>Using</strong> <strong>Zen</strong>
3<br />
<strong>Zen</strong> Client and Server<br />
<strong>Zen</strong> is a client/server Web technology. The terms client and server are commonly used. This chapter<br />
explains how <strong>Zen</strong> uses these terms. The topics in this chapter are:<br />
• <strong>Zen</strong> and Caché Server Pages — A <strong>Zen</strong> application uses CSP technologies to serve Web pages to<br />
the client browser. This topic summarizes the CSP client/server relationship.<br />
• <strong>Zen</strong> Pages at Runtime — This topic extends the <strong>Zen</strong> and CSP discussion to explain how <strong>Zen</strong><br />
responds to HTTP requests. <strong>Zen</strong> responses to XML or SVG follow a similar sequence.<br />
3.1 <strong>Zen</strong> and Caché Server Pages<br />
Important:<br />
This topic briefly outlines material that fills several chapters in <strong>Using</strong> Caché Server<br />
Pages (CSP). If you are new to CSP, please study the detailed explanations in the<br />
other book.<br />
<strong>Using</strong> Caché Server Pages (CSP) describes the relationship between the client and server in CSP<br />
applications. It outlines the flow of events between issuing the HTTP request and displaying the page<br />
in the browser. <strong>Zen</strong> applications and <strong>Zen</strong> pages are CSP pages, so all of this information also applies<br />
to <strong>Zen</strong>.<br />
The following diagram summarizes the interactions between the CSP client and server.<br />
<strong>Using</strong> <strong>Zen</strong> 25
<strong>Zen</strong> Client and Server<br />
How Caché Server Pages Work<br />
Numbers in the previous diagram highlight the flow of events on the client and server while CSP<br />
processes an HTTP request. The sequence is as follows:<br />
1. The browser (or similar Web client) makes an HTTP request.<br />
2. If the Web server determines that this is a CSP request, it dispatches the request to the CSP<br />
Gateway installed on the Web Server.<br />
Alternatively, if the request is for a static file (such as an .html or .jpg file), the Web server finds<br />
the file within the local file system and sends its contents back to the client.<br />
3. The CSP Gateway repackages the request and sends it to the correct Caché server.<br />
26 <strong>Using</strong> <strong>Zen</strong>
4. The Caché server decodes the message, determines which event handling class (part of your<br />
application) should process the event, and invokes the OnPage method in that class.<br />
<strong>Zen</strong> pages are CSP pages, so each <strong>Zen</strong> page class has an OnPage method. However, <strong>Zen</strong> pages<br />
offer a much wider selection of potential actions than CSP pages, with a correspondingly rich set<br />
of methods that CSP pages do not provide.<br />
5. The Caché server returns the output of the OnPage method to the CSP Gateway as an HTTP<br />
response.<br />
6. The CSP Gateway hands the HTTP response to the Web server (actually, Caché streams the<br />
response back to the Web Server via the CSP Gateway).<br />
7. The Web server returns the response to the Web browser which then processes the response. In<br />
the case of HTML, it displays the page. There may be other results depending on what type of<br />
data the response contains.<br />
<strong>Zen</strong> applications use CSP technologies to:<br />
• Filter and respond to HTTP requests.<br />
• Manage sessions and session lifecycle.<br />
• Manage user identity, authentication, and access control.<br />
• Provide the hyperevent mechanism used to call server methods from the client.<br />
• Call from the server to execute code securely on the client.<br />
<strong>Zen</strong> Pages at Runtime<br />
Important:<br />
If you make use of the CSP session preserve mode, be aware that the server-side <strong>Zen</strong><br />
page (%page) and application (%application) objects are not preserved between<br />
server requests.<br />
3.2 <strong>Zen</strong> Pages at Runtime<br />
A <strong>Zen</strong> page automatically responds to HTTP requests from a browser and serves up a complete HTML<br />
document to satisfy such a request. <strong>Zen</strong> pages can also satisfy other types of requests, such as for XML<br />
or SVG content. The behavior for XML or SVG is documented in later chapters. It is similar to the<br />
HTML behavior documented in this chapter.<br />
The following sequence displays a <strong>Zen</strong> page in a browser window:<br />
1. The Web browser sends an HTTP request that names a specific <strong>Zen</strong> page. The Caché server<br />
receives the request and automatically routes it to the <strong>Zen</strong> page class.<br />
Note:<br />
CSP handles this step. Details appear in the previous topic.<br />
<strong>Using</strong> <strong>Zen</strong> 27
<strong>Zen</strong> Client and Server<br />
2. The page class invokes its %OnBeforeCreatePage callback method. This method provides the<br />
opportunity for the application to perform any setup work that may be required before<br />
%CreatePage begins execution.<br />
3. The page class creates an instance of itself on the Caché server.<br />
The page class invokes its class method %CreatePage. This method creates the set of component<br />
objects and adds these objects as children of the page object.<br />
When a <strong>Zen</strong> page class contains a description of the page in XML format (as described in later<br />
chapters) <strong>Zen</strong> automatically generates a %CreatePage method whenever the class is compiled.<br />
The compiler uses the information in XData Contents to generate the method.<br />
Alternatively, a programmer may omit the XData Contents block and implement %CreatePage<br />
manually. This more complex option gives the opportunity to create dynamic page content.<br />
4. The page class invokes its %OnAfterCreatePage callback method. In this method, the application<br />
can modify the content generated by %CreatePage in any way that is needed.<br />
After %OnAfterCreatePage completes execution, there is a page object in memory that contains<br />
some number of child component objects. This page object is a document object model (DOM)<br />
that will be used to draw the HTML needed to display the page.<br />
5. The page object constructs an HTML document from its DOM.<br />
The page invokes its %DrawHTML method. Every <strong>Zen</strong> page and component object has a<br />
%DrawHTML method that knows how to render the object as HTML. In the case of a <strong>Zen</strong> page,<br />
the %DrawHTML method supplies:<br />
• The page title.<br />
• Any meta-HTML tags needed by the page.<br />
• Any content needed to support hyperevents (the mechanism used to make in-page calls back<br />
to the server).<br />
• Include statements for any required JavaScript or CSS include files.<br />
• JavaScript needed to define the set of client component classes used on the page.<br />
• JavaScript needed to create and initialize the set of client component objects used on the page.<br />
That is, a client-side version of the server-side page object is created.<br />
• Default CSS style definitions defined by the component classes.<br />
• CSS style definitions defined by the application class.<br />
• CSS style definitions defined by the page class. (This order is important as it allows the<br />
application settings to override defaults and page settings to override application settings).<br />
• The HTML content of every component on the page (obtained by invoking the %DrawHTML<br />
method for every component on the page).<br />
28 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Pages at Runtime<br />
As with %CreatePage, for the most part a <strong>Zen</strong> programmer can ignore %DrawHTML. Caché<br />
generates and invokes it automatically. The important fact about %DrawHTML is when it occurs.<br />
%DrawHTML is the last step before the page leaves the server.<br />
The <strong>Zen</strong> programmer must ensure that all adjustments to the page are complete before the end of<br />
%OnAfterCreatePage. After that, Caché draws whatever is in the DOM.<br />
6. The Caché server delivers the HTML document to the client, and the browser displays the HTML<br />
document.<br />
Note:<br />
CSP handles this step. Details appear in the previous topic.<br />
The following diagram illustrates the sequence described above. This <strong>Zen</strong> diagram builds on the CSP<br />
diagram from the previous topic. It using regular numbers for CSP steps and highlights the <strong>Zen</strong> steps<br />
with larger, bold numbers such as:<br />
<strong>Using</strong> <strong>Zen</strong> 29
<strong>Zen</strong> Client and Server<br />
How <strong>Zen</strong> Pages Work<br />
30 <strong>Using</strong> <strong>Zen</strong>
4<br />
<strong>Zen</strong> Application Concepts<br />
A <strong>Zen</strong> application specifies the full set of activities that can result when a <strong>Zen</strong> client and server interact.<br />
These activities may consist of displaying Web pages, issuing queries to a database, writing data to<br />
disk, and more. When you create a <strong>Zen</strong> application, you create a suite of <strong>Zen</strong> classes that specify these<br />
activities. The language you use for these classes is Caché ObjectScript — with embedded snippets<br />
of XML, HTML, SVG, and JavaScript as needed.<br />
If you are new to Caché objects and the ObjectScript programming language, the discussion in this<br />
chapter will make most sense after you have mastered the supporting material available in other books.<br />
The best starting points are <strong>Using</strong> Caché Objects and <strong>Using</strong> Caché ObjectScript.<br />
The examples in this book use ObjectScript, but you can also use Caché Basic as your programming<br />
language. See <strong>Using</strong> Caché Basic.<br />
4.1 <strong>Zen</strong> Applications<br />
A <strong>Zen</strong> application consists of the following parts:<br />
An Application class<br />
Page classes<br />
Every <strong>Zen</strong> application has an application class. This is a class derived from %ZEN.application<br />
that provides application-wide behavior such as a common style sheet. The style sheet is<br />
specified as an XML block embedded within the class.<br />
An application consists of one or more pages. Each page is a class derived from<br />
%ZEN.Component.page which is, in turn, a subclass of both %CSP.Page and<br />
%ZEN.Component.component.<br />
<strong>Using</strong> <strong>Zen</strong> 31
<strong>Zen</strong> Application Concepts<br />
Component classes<br />
Every page contains components. Components provide “look and feel” and permit the user<br />
to interact with the page. All components are derived from %ZEN.Component.component.<br />
They include buttons, tables, list boxes, text fields, panels — essentially any item that can be<br />
displayed on a page.<br />
<strong>Zen</strong> Application with Pages and Components<br />
This architecture works as follows:<br />
• A <strong>Zen</strong> application consists of page classes.<br />
• Every <strong>Zen</strong> page identifies the application that it belongs to.<br />
• Every <strong>Zen</strong> page consists of a page object and a set of component objects.<br />
• The set of components for a page is defined using a block of XML embedded into the page class.<br />
• The page class can also define a set of methods that provide additional behavior, such as<br />
responding to user actions. These methods can run within the browser, or on the server, depending<br />
on how the code is written.<br />
• When the client sends a page request, the page object and all of its constituent component objects<br />
are instantiated on the Caché server. This is the object tree.<br />
• This object tree can be further modified by user code on the Caché server.<br />
32 <strong>Using</strong> <strong>Zen</strong>
• The object tree generates all the CSS (style sheet), JavaScript (client logic) and HTML (layout<br />
instructions) needed to display the page within the client browser. Alternatively, a page could<br />
generate XML or SVG.<br />
• On the client browser, the same object tree is automatically recreated as a set of JavaScript objects.<br />
• Properties and methods of the object tree are thus available to the client.<br />
• As the user interacts with a page, events are fired that invoke the various methods of the client<br />
object tree. Some of these methods execute within the browser, while others can be defined to run<br />
back on the server (for database access, etc.).<br />
• <strong>Zen</strong> automatically manages any calls that a page makes back to the server, including session<br />
context, security, and synchronizing changes between the client and the server.<br />
• Users create <strong>Zen</strong> applications by assembling classes (both pre-built and user-defined) into larger<br />
functional units: components are assembled into pages, and pages are assembled into applications.<br />
<strong>Zen</strong> Page Synchronized on Client and Server at Runtime<br />
<strong>Zen</strong> Pages<br />
4.2 <strong>Zen</strong> Pages<br />
A <strong>Zen</strong> page class consists of:<br />
• A contents definition—An XML block embedded within the page class. It defines the set of<br />
components that make up the page, along with their settings. It is possible to define the contents<br />
of a page programmatically, but in most cases an XML block is more convenient.<br />
<strong>Using</strong> <strong>Zen</strong> 33
<strong>Zen</strong> Application Concepts<br />
• Style overrides—An XML block embedded within the page class. It defines page-specific overrides<br />
of CSS styles for the components on this page.<br />
• Event-handling methods—A page class typically contains a number of methods that handle events<br />
associated with a page, such as when the user interacts with a component. Some of these methods<br />
may run on the server and some on the client. Later chapters provide details.<br />
Defining the Look and Feel of a <strong>Zen</strong> Page<br />
4.3 <strong>Zen</strong> Components<br />
<strong>Zen</strong> component classes define the behavior and layout of the page. Every <strong>Zen</strong> component has the following<br />
characteristics:<br />
• Defines a set of properties and methods that determine its runtime state and behavior.<br />
• Defines how its initial HTML is drawn (if any). It is also possible to define components that only<br />
render themselves using client-side, dynamic HTML.<br />
• Defines a standard CSS style sheet that specifies how it should appear on the page. Applications<br />
can selectively override these styles without having to modify the pre-built components.<br />
34 <strong>Using</strong> <strong>Zen</strong>
• Defines settings that adjust the appearance or behavior of a component. A <strong>Zen</strong> component class<br />
formally exposes certain settings so that it is easy to dynamically modify these setting values<br />
while designing a <strong>Zen</strong> page.<br />
• New component classes can be derived from existing classes. <strong>Zen</strong> automatically provides inheritance<br />
for the client JavaScript classes it creates.<br />
• New components are automatically ready for use within a page’s XML content definition.<br />
Component classes vary in complexity from simple wrappers for native HTML controls to full-featured<br />
calendar and grid controls. Components include the following specialized types:<br />
• Controls display data and allow for user input (such as text or button controls).<br />
• Groups contain sets of other components (such as groups, tab groups, menus, and forms).<br />
• Panes display rich information (such as a tables retrieved from queries).<br />
• Other components simply display data on the page.<br />
<strong>Zen</strong> Components<br />
<strong>Using</strong> <strong>Zen</strong> 35
5<br />
<strong>Zen</strong> Component Concepts<br />
Components provide layout, style, and behavior for the page. The following table defines these<br />
commonly used terms. These definitions are important because each <strong>Zen</strong> component provides a large<br />
number of attributes that you can manipulate as you program the application. Some of these attributes<br />
affect layout, some style, and some behavior. With a strong grounding in these concepts, you can<br />
manipulate attributes fluently to get the results you want from <strong>Zen</strong> components.<br />
<strong>Using</strong> <strong>Zen</strong> 37
<strong>Zen</strong> Component Concepts<br />
Term<br />
Page<br />
Illustration<br />
Component Concepts<br />
Summary<br />
The rectangular display in a browser window.<br />
Layout<br />
The position of each component, and of each<br />
group of components, on the page.<br />
Style<br />
The visual appearance of components,<br />
regardless of their position on the page.<br />
Behavior<br />
An application action that results from user<br />
input, a timer, or some other event.<br />
5.1 Page<br />
A page is initially empty. It fills with components as you add them. A layout strategy is necessary to<br />
determine where these components appear on the page.<br />
38 <strong>Using</strong> <strong>Zen</strong>
Layout<br />
5.2 Layout<br />
As <strong>Zen</strong> constructs a page for display, it adds components individually, one after another, according to<br />
the description that you have provided in the page class. The user is not aware of the page construction<br />
process. The user only sees that a page appears. However, as a <strong>Zen</strong> programmer, you must understand<br />
the construction process so that your pages lay themselves out exactly as you intend.<br />
Components are contained within groups: a special type of component that can contain zero or more<br />
components. A group is responsible for the placement of its components on the page. The page is itself<br />
a group. <strong>Zen</strong> generates standard HTML table elements based on the group definition. You can cause<br />
components to line up vertically or horizontally, by enclosing them within a vertical or horizontal<br />
group. Generally, the largest width or height of any component in a group determines the overall width<br />
or height of the group on the page. A spacer component is available to help insert additional space<br />
between components in the group. The entire group places itself on the page as one component.<br />
Certain components permit layers, similar to sheets of paper that occupy one position in a stack. Only<br />
one layer is revealed at one time, based on user clicks. Menus and tabs work on this principle.<br />
Other components may have variable size, depending on their state. For example, if an expando list<br />
is closed, it contains only one item and is short. If the list is opened, it may contain many items; then<br />
it is long. The opened list could push aside other components later in the layout, causing a shift in the<br />
physical geography of the page. Or, the containing group may have a fixed size larger than the maximum<br />
expected list size, allowing the list to expand and contract within the larger boundary without affecting<br />
the page layout.<br />
For details about the built-in <strong>Zen</strong> component expando, see Navigation Components.<br />
<strong>Zen</strong> manages layout by generating HTML and CSS style statements based on the inputs that you provide<br />
<strong>Zen</strong>. Essentially there are three ways to specify your layout intentions to <strong>Zen</strong>:<br />
• Let the containing group lay out its components.<br />
• Provide CSS style statements to <strong>Zen</strong>.<br />
• Use client-side JavaScript to dynamically change the geography of the page.<br />
For details, see the chapter <strong>Zen</strong> Layout.<br />
Scalable Vector Graphics (SVG) components are handled differently from other types of page content.<br />
For details see the chapter <strong>Zen</strong> and SVG.<br />
<strong>Using</strong> <strong>Zen</strong> 39
<strong>Zen</strong> Component Concepts<br />
5.3 Style<br />
Style determines the visual appearance of a component. <strong>Zen</strong> manages style by generating standard<br />
CSS statements based on the inputs that you provide <strong>Zen</strong>.<br />
There are many style attributes that you can set for each component. These include background color,<br />
size, fill patterns, line width, and font family, just to name a few. You can accept the default styles.<br />
You can also override styles at the component, page, or application level.<br />
For details, see the chapter <strong>Zen</strong> Style.<br />
5.4 Behavior<br />
Behavior refers to an internal or external application action that is triggered by user input, a timer, or<br />
some other type of event. Behavior encompasses a wide range of topics in this book, from processing<br />
user clicks and key presses to automatically generating tables based on database queries.<br />
Component behavior is unique per component. Subsequent chapters provide details as they discuss<br />
each type of <strong>Zen</strong> component. These chapters include:<br />
• <strong>Zen</strong> Tables<br />
• <strong>Zen</strong> and SVG<br />
• <strong>Zen</strong> Charts<br />
• <strong>Zen</strong> Forms<br />
• <strong>Zen</strong> Controls<br />
• Model View Controller<br />
• Navigation Components<br />
• Popup Windows and Dialogs<br />
• Other <strong>Zen</strong> Components<br />
• Custom Components<br />
40 <strong>Using</strong> <strong>Zen</strong>
Customization<br />
5.5 Customization<br />
<strong>Zen</strong> serves a wide audience range. At one end is the programmer who wants to use <strong>Zen</strong> to quickly<br />
assemble a user interface for a data-rich Web application. This programmer rapidly places <strong>Zen</strong> components<br />
on the page with the goal of allowing the user to see and manipulate the underlying data.<br />
At the other end of this range is the programmer who wants to use <strong>Zen</strong> for pinpoint control of the<br />
layout, style, and behavior of each component on the page. This programmer may react to introductory<br />
topics with this phrase: “But I want to...”<br />
Everyone can relax.<br />
<strong>Zen</strong> provides ample opportunities for customization. In addition to the wide range of variations available<br />
by manipulating layout, style, and behavior of built-in components, you can create new components,<br />
or even replace the <strong>Zen</strong> layout handler with custom code. For details, see the chapter Custom Components.<br />
On the other hand, customization is entirely optional. Everyone should begin by reading the next several<br />
chapters. Come to appreciate the power, ease, and flexibility of <strong>Zen</strong>. Then, after understanding what<br />
<strong>Zen</strong> provides, make your own decision about whether or not to extend it. The option is always there.<br />
<strong>Using</strong> <strong>Zen</strong> 41
6<br />
<strong>Zen</strong> Layout<br />
Previous chapters have introduced <strong>Zen</strong> components as classes. It is true that components are classes.<br />
All <strong>Zen</strong> components extend the class %ZEN.Component.component. However, when you place <strong>Zen</strong><br />
components on the page, your primary programming language is usually not ObjectScript. It is XML.<br />
This chapter explains how to lay out <strong>Zen</strong> pages using XML:<br />
• The chapter begins with an XData Contents example<br />
• The next several topics discuss the XML elements in the example:<br />
- — The top-level container element<br />
- — Allows you to place HTML directly on the page<br />
- — Creates a horizontal row of components<br />
- — Creates a vertical column of components<br />
- — Creates space between groups<br />
- — Subdivides the page into regions<br />
• The chapter ends by discussing:<br />
- How to organize XData Contents using template pages<br />
- The HTML page that <strong>Zen</strong> generates from XData Contents<br />
<strong>Using</strong> <strong>Zen</strong> 43
<strong>Zen</strong> Layout<br />
6.1 XData Contents<br />
When you prepare a <strong>Zen</strong> page class for an application, you place components on the page by providing<br />
an XData Contents block. XData Contents is a well-formed XML document that describes the layout<br />
and (optionally) style and behavior of the page.<br />
Each XML element in the document corresponds to a component class of the same name. The following<br />
sample XData Contents block includes the XML elements , , , ,<br />
, and . These XML elements represent the <strong>Zen</strong> classes %ZEN.Component.page,<br />
%ZEN.Component.html, %ZEN.Component.hgroup, and so on.<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
My Title<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
When you compile the class that contains the previous XData Contents block, <strong>Zen</strong> generates the code<br />
that displays this page in the browser. At runtime, this code instantiates the indicated component classes<br />
as children of the page object. <strong>Zen</strong> handles these details automatically and transparently, as described<br />
in the chapter <strong>Zen</strong> Application Concepts.<br />
As the programmer laying out an XData Contents block, you do not work with component classes<br />
directly. You work with the XML projection of the component classes. For each component, this<br />
projection consists of:<br />
• An XML element with the same name as the class (, , , etc.)<br />
• XML attributes, which are properties of that class (width, height, etc.)<br />
This convention gives you the power of the <strong>Zen</strong> runtime environment for serving <strong>Zen</strong> pages, without<br />
requiring you to understand the underlying mechanisms in detail. You use the XML projection to place<br />
components on the page, and <strong>Zen</strong> generates the HTML that displays these components in the browser.<br />
44 <strong>Using</strong> <strong>Zen</strong>
Pages<br />
6.2 Pages<br />
The XData Contents block contains one element that acts as the top-level container for all the<br />
XML elements in the block. A is a group component with the standard group attributes and<br />
the unique attributes listed in the following table.<br />
Attribute<br />
title<br />
xmlns<br />
Description<br />
Use this attribute to store page title text. This text is not automatically used<br />
on the page, but the attribute is available should you want to refer to this text<br />
programmatically. If you do not specify a value for title it takes its value from<br />
the page class parameter PAGETITLE.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
The title value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
Allows you to include an XML namespace declaration for the .<br />
As you add custom components, chances increase that there will be conflicts<br />
between components in different namespaces. Adding the xmlns attribute<br />
prevents this.<br />
6.3 Titles<br />
The first item most pages need is a title bar. The title bar answers the user’s implicit question: “Where<br />
am I” <strong>Zen</strong> offers several elements that can serve this purpose. They work in entirely different ways:<br />
• for simple titles<br />
• for complex titles<br />
• A custom component to use as your title bar<br />
<strong>Using</strong> <strong>Zen</strong> 45
<strong>Zen</strong> Layout<br />
6.3.1 Simple Titles<br />
draws a title box along with an optional subtitle. You can use to provide a<br />
simple title for any component, including the page itself. Simply make the first child<br />
component inside the component whose title you want it to be. For example:<br />
<br />
<br />
<br />
<br />
Components like have a caption attribute and so do not need to provide a label.<br />
is most useful and appropriate for a or . has the attributes listed<br />
in the following table.<br />
Attribute<br />
title<br />
subtitle<br />
titleStyle<br />
Description<br />
Title text.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
The title value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
(Optional) Subtitle text.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
The subtitle value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
(Optional) String containing a CSS style statement such as:<br />
"color:red; background: yellow;"<br />
There is also a element that omits the subtitle and titleStyle attributes.<br />
46 <strong>Using</strong> <strong>Zen</strong>
Titles<br />
6.3.2 Complex Titles<br />
The element permits you to insert an arbitrary HTML excerpt on the <strong>Zen</strong> page. You can use<br />
the component to output title text in the appropriate font and size. You can use to<br />
quickly produce a title when you are first drafting the page. Simply enclose the desired HTML tags<br />
inside and . For example:<br />
<br />
<br />
Welcome to My Application!<br />
You are Here:<br />
<br />
<br />
<br />
The real power of the element comes from its optional OnDrawContent attribute.<br />
OnDrawContent identifies a server-side callback method that provides HTML content by using &html<br />
or by using the WRITE command. If defined, this callback is invoked on the server when this component<br />
is drawn. The value of OnDrawContent must be the name of a server-only method in the page class<br />
that contains this component. This method must accept an optional %String as input and return a<br />
%Status data type. What is significant about this feature is that server-side methods normally consist<br />
of ObjectScript code, whereas a callback referenced by OnDrawContent may consist of ObjectScript<br />
code plus as much HTML as you wish to embed within &html or WRITE.<br />
Thus, a page class that contains an XData Contents block with this line:<br />
<br />
must also contain a server-side callback method called DrawMessage that meets the above criteria.<br />
The following example is from the ZENApp.HelpDesk class in the SAMPLES namespace:<br />
Method DrawMessage(pSeed As %String) As %Status<br />
{<br />
#; create a random message<br />
Set tColors = $LB("red","green","blue","black","orange")<br />
Set tColor = $LG(tColors,$R($LL(tColors))+1)<br />
Set tMsgs = $LB("Fresh coffee in kitchen!",<br />
"Company share price has gone up.",<br />
"The boss is coming!",<br />
"Customer crisis!",<br />
"Lunch Time!")<br />
Set tMsg = $LG(tMsgs,$R($LL(tMsgs))+1)<br />
&html<br />
}<br />
Quit $$$OK<br />
For more detail, see the Other <strong>Zen</strong> Components chapter, topic.<br />
<strong>Using</strong> <strong>Zen</strong> 47
<strong>Zen</strong> Layout<br />
6.4 Groups<br />
A group component extends %ZEN.Component.group. A group component is the only type of component<br />
that can contain child components. That is why components such as pages, panes, menus, forms, and<br />
composites all inherit from %ZEN.Component.group.<br />
6.4.1 Layout Strategy<br />
Each group is responsible for the layout of its children on the page. A group can have a horizontal or<br />
vertical layout. With the exception of and , every <strong>Zen</strong> group and page has vertical<br />
layout by default. You can reset to horizontal layout by providing the layout attribute for the group.<br />
layout may have the following values:<br />
• "horizontal" — Lay out components horizontally. When <strong>Zen</strong> generates the page, it constructs<br />
an HTML table row to contain the child components.<br />
• "vertical" — Lay out components vertically. When <strong>Zen</strong> generates the page, it constructs an<br />
HTML table column to contain the child components.<br />
• "" or omitted — Default to vertical layout.<br />
6.4.2 Simple Group Components<br />
The following table lists group components such as you have seen in previous code examples. These<br />
are all derived from %ZEN.Component.group.<br />
Component<br />
<br />
<br />
Description<br />
The basic group. Used to create a group of components, either for layout<br />
purposes or to treat a set of components as a logical unit (for example<br />
making them hidden or visible as a unit). The attributes of the group<br />
component control the layout of its child components.<br />
A horizontal group, identical to a component with its layout<br />
property set to "horizontal". For example:<br />
<br />
<br />
<br />
<br />
<br />
<br />
A specialized group component with layout set to "vertical" and cellVAlign<br />
set to "top".<br />
48 <strong>Using</strong> <strong>Zen</strong>
Groups<br />
Component<br />
<br />
<br />
<br />
Description<br />
A specialized group component with an additional attribute, paneName,<br />
that references an XData block outside XData Contents.<br />
The is not a group component, but it is useful within groups.<br />
Use with a width value to inject additional space in a horizontal<br />
group, or height for additional space within a vertical group.<br />
A vertical group, identical to a component with its layout property<br />
set to "vertical". For example:<br />
<br />
<br />
<br />
<br />
<br />
6.4.3 Menu Components<br />
Menu components are groups derived from the %ZEN.Component.group class. Being a group permits<br />
the menu to contain child components. A later chapter, Navigation Components, describes how to use<br />
menus.<br />
Component<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Description<br />
A specialized form of group that displays a set of menu choices.<br />
A with layout set to "horizontal".<br />
A specialized whose tabs present menus.<br />
An item within a <br />
A separator within a .<br />
Defines a group of components that are used as a tab within a<br />
or .<br />
A specialized group that contains components (which<br />
themselves contain components). One tab at a time is visible.When<br />
the user selects a new tab, its contents become visible and the<br />
other tabs are hidden.<br />
A with layout set to "vertical".<br />
<strong>Using</strong> <strong>Zen</strong> 49
<strong>Zen</strong> Layout<br />
6.4.4 Complex Group Components<br />
The <strong>Zen</strong> library contains a number of other classes derived from %ZEN.Component.group. The following<br />
table lists these group components. Later chapters describe them in full.<br />
Component<br />
<br />
<br />
<br />
<br />
<br />
Description<br />
A specialized form of the group component that lets the user show<br />
or hide the members of a group by clicking on a small icon: a plus<br />
sign to expand (show) the group, or a minus sign to contract (hide)<br />
the group.<br />
A group that wraps its members within an HTML <br />
element. The draws an outer box around the children<br />
and displays a title within this box. creates a visual panel<br />
that organizes a large form.<br />
A form is defined as a group, so that it can contain child<br />
components.<br />
Defines a set of components that act together as a modalGroup.<br />
This is a set of components that are initially not displayed but can<br />
later be displayed with modal behavior.<br />
A specialized group that defines the layout for a single entry, then<br />
lays out multiple entries of this type based on data supplied by a<br />
runtime query.<br />
6.4.5 Group Layout and Style Attributes<br />
The following table lists the XML attributes that apply to all group components. These attributes can<br />
affect the positioning or appearance of components in the groups.<br />
50 <strong>Using</strong> <strong>Zen</strong>
Groups<br />
Group Layout and Style Attributes<br />
Attribute<br />
<strong>Zen</strong><br />
component<br />
attributes<br />
cellAlign<br />
Description<br />
Groups have the same general-purpose attributes as any <strong>Zen</strong><br />
component. The next chapter, <strong>Zen</strong> Style, describes them.<br />
Specifies horizontal alignment for child components within the group<br />
table.The possible values are "left", "right", "center", and "even". cellAlign<br />
behavior depends on the layout strategy for the group:<br />
• Horizontal — A cellAlign value of "left" or "right" places the child<br />
components towards the left or right edges of the group, respectively.<br />
"center" places the child components in the horizontal center of the<br />
group with additional space added on either side of the children.<br />
"even" places the child components in the horizontal center of the<br />
group, with no additional space added.<br />
• Vertical — cellAlign specifies the default vertical alignment used by<br />
the elements containing the child components. "even" is the<br />
same as "center" in this case. An individual child component can<br />
override cellAlign by setting its own align value. For align, see<br />
Component Style Attributes.<br />
When specifying cellAlign, also set the height or width property of the<br />
group, to control how the group takes up the space provided by its container.<br />
For vertical alignment, set cellVAlign instead of cellAlign.<br />
cellSize<br />
How much space (in the direction specified by the layout strategy) to<br />
allot to the elements used to contain each child component within<br />
the layout table. Possible values are:<br />
• "same" — Attempt to allot the same amount of space to each component.<br />
• "stretch" — Allot space to each component based on its relative<br />
value of slice. For slice, see Component Style Attributes.<br />
cellStyle<br />
String containing a CSS style statement such as:<br />
"color:red; background: yellow;"<br />
<strong>Zen</strong> applies this style to the elements used to contain each child<br />
component within the layout table. An individual child component can<br />
override cellStyle by setting its own containerStyle value. For<br />
containerStyle, see Component Style Attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 51
<strong>Zen</strong> Layout<br />
Attribute<br />
cellVAlign<br />
Description<br />
Specifies vertical alignment for child components within the group table.<br />
The possible values are "top", "bottom", "middle", and "even". cellVAlign<br />
behavior depends on the layout strategy for the group:<br />
• Vertical — A cellVAlign value of "top" or "bottom" places the child<br />
components towards the top or bottom edges of the group, respectively.<br />
"middle" places the child components in the vertical center of<br />
the group with additional space added above and below the children.<br />
"even" places the child components in the vertical center of the<br />
group, with no additional space added.<br />
• Horizontal — cellVAlign specifies the default horizonal alignment<br />
used by the elements containing the child components. "even"<br />
is the same as "middle" in this case. An individual child component<br />
can override cellVAlign by setting its own valign value. For valign,<br />
see Component Style Attributes.<br />
When specifying cellVAlign, also set the height or width property of the<br />
group, to control how the group takes up the space provided by its container.<br />
For horizontal alignment, set cellAlign instead of cellVAlign.<br />
disabled<br />
groupClass<br />
groupStyle<br />
If true, this group and its children are disabled. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
Name of a CSS style class. When <strong>Zen</strong> lays out this group, it assigns this<br />
value to the HTML class attribute.<br />
String containing a CSS style statement such as:<br />
"color:red; background: yellow;"<br />
When <strong>Zen</strong> lays out this group, it assigns this value to the HTML <br />
style attribute.<br />
labelPosition<br />
layout<br />
Specifies where labels should be displayed for components within this<br />
group. Possible values are "top" and "left". "top" places the labels above<br />
the components; "left" places the labels to the left of the components.<br />
The layout strategy used by this group: "horizontal" or "vertical". If<br />
omitted, the default is vertical.<br />
52 <strong>Using</strong> <strong>Zen</strong>
Template Pages<br />
6.5 Template Pages<br />
You can define an abstract page class that provides the characteristics that you want on all your pages<br />
for the application, then define all application pages as children of the abstract template class. This<br />
would be your template page class:<br />
Class MyApp.TemplatePage Extends %ZEN.Component.page [ Abstract ]<br />
{<br />
/// Class details here<br />
}<br />
All your page classes would look like this:<br />
Class MyApp.AnotherPage Extends MyApp.TemplatePage<br />
{<br />
/// Class details here<br />
}<br />
Template pages offer a convenient way to organize <strong>Zen</strong> applications for a consistent look and feel. To<br />
view an example of this practice, start Studio, and in the SAMPLES namespace, open the page classes<br />
ZENApp.Chart and ZENApp.HelpDesk. Each of these pages inherits from the template page<br />
ZENApp.TemplatePage, which you can also view.<br />
The effect of class inheritance on XData Contents is one of simple replacement. The child class uses<br />
the child XData if it is present, and if not, it uses the parent XData.<br />
Parent Defines<br />
XData Contents<br />
Yes<br />
Yes<br />
No<br />
No<br />
Child Defines<br />
XData Contents<br />
No<br />
Yes<br />
No<br />
Result<br />
Child inherits XData Contents from the parent.<br />
Child uses its own XData Contents definition.<br />
The page is empty.<br />
Inheritance works a bit differently for style. Style involves a cascade of decisions that may coexist<br />
without overriding or replacing each other. Thus, the simple rules for inheritance of XData Contents<br />
are not always true for inheritance of XData Style. To understand how <strong>Zen</strong> applies style, see the next<br />
chapter, <strong>Zen</strong> Style.<br />
<strong>Using</strong> <strong>Zen</strong> 53
<strong>Zen</strong> Layout<br />
6.6 Panes<br />
You can organize your page layout into panes for convenience. A is a specialized group<br />
component with an additional attribute, paneName, that references an XData block outside XData<br />
Contents. At compile time, <strong>Zen</strong> substitutes the appropriate XData block wherever the element<br />
appears in XData Contents.<br />
Consider the following <strong>Zen</strong> page. This sample was introduced at the beginning of this chapter. It<br />
organizes a page into three panes — menuPane, tablePane, and detailPane:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
My Title<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
The reference to a specific pane looks like this:<br />
<br />
At compile time, <strong>Zen</strong> resolves this reference by finding an XData block in the page class whose name<br />
matches paneName. In the example above, the value of paneName is menuPane, so <strong>Zen</strong> looks for an<br />
XData block called menuPane. <strong>Zen</strong> substitutes this block for the reference. At display time,<br />
whatever is contained within the XData menuPane block appears on the page in the position occupied<br />
by the element . The following is a conceptual view of the result.<br />
54 <strong>Using</strong> <strong>Zen</strong>
Panes<br />
Use of Panes on a <strong>Zen</strong> Page<br />
The following XData block defines the menuPane referenced by the sample :<br />
XData menuPane<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
If you are using template pages, you can place a reference in the parent class and allow it to<br />
resolve in either the parent class or the child class. Suppose the reference in the child class is:<br />
<br />
The following table discusses the options for inheritance.<br />
<strong>Using</strong> <strong>Zen</strong> 55
<strong>Zen</strong> Layout<br />
Parent Defines<br />
XData myPane<br />
Yes<br />
Yes<br />
No<br />
No<br />
Child Defines<br />
XData myPane<br />
No<br />
Yes<br />
No<br />
Result<br />
Child inherits XData myPane from the parent.<br />
Child uses its own XData myPane definition. The<br />
parent may reference and allow this reference<br />
to resolve in the child class. This common practice<br />
is illustrated in the ZENApp.HelpDesk sample class.<br />
Any reference to <br />
in either class is ignored.<br />
6.7 Generated HTML<br />
The generated code from XData Contents expresses the <strong>Zen</strong> page as an HTML table, using the standard<br />
HTML elements , , , and . Vertical groups become columns in the table; horizontal<br />
groups become rows. If you are familiar with encoding HTML by hand, you probably recognize this<br />
technique for ensuring the position of items on the page.<br />
<strong>Zen</strong> groups are easy and convenient to set up, and require no coding in HTML. Rather than arranging<br />
HTML , , , and elements into complex nests, all you need to do is place your<br />
<strong>Zen</strong> components into groups. Groups handle all the layout details for you.<br />
56 <strong>Using</strong> <strong>Zen</strong>
7<br />
<strong>Zen</strong> Style<br />
The previous chapter, <strong>Zen</strong> Layout, explained how to place <strong>Zen</strong> components on the page. To do this,<br />
you provide an XData Contents block in the page class and fill it with XML elements that represent<br />
<strong>Zen</strong> components.<br />
This chapter explains how to specify styles for <strong>Zen</strong> components. You can do this by:<br />
• Setting style attributes while placing XML elements in the XData Contents block.<br />
• Applying cascading style sheet (CSS) style definitions in an XData Style block.<br />
• Referencing external CSS files in a variety of ways.<br />
7.1 Component Style Attributes<br />
All <strong>Zen</strong> components provide the XML attributes listed in the following table. These attributes control<br />
how a component behaves within its enclosing group.<br />
Component Style Attributes<br />
Attribute<br />
align<br />
condition<br />
Description<br />
Possible values are "left", "right", or "center". This becomes the align<br />
value for the element that contains the child component in the<br />
generated HTML.<br />
Server-side expression that, if true, allows this component to be<br />
added to the set of page components. This server-only attribute is<br />
not defined on the client side.<br />
<strong>Using</strong> <strong>Zen</strong> 57
<strong>Zen</strong> Style<br />
Attribute<br />
containerStyle<br />
Description<br />
Overrides the parent group’s cellStyle, to provide extra padding or<br />
alignment values for the element that contains the child component<br />
in the generated HTML.<br />
containerStyle is a string containing a CSS style statement such as:<br />
"color:red; background: yellow;"<br />
enclosingClass<br />
enclosingStyle<br />
Name of a CSS style class. When <strong>Zen</strong> lays out this group, it applies<br />
this style to the component’s enclosing element.<br />
String containing a CSS style statement such as:<br />
"color:red; background: yellow;"<br />
When <strong>Zen</strong> lays out this group, it applies this style to the component’s<br />
enclosing element.<br />
height<br />
hidden<br />
id<br />
import<br />
CSS length value (integer or percentage). This becomes the height<br />
value for the element that contains the child component in the<br />
generated HTML.<br />
If true, the component is hidden (placed on the page, but not displayed).<br />
If the status of a component is hidden, its label text (if any)<br />
is also hidden. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
The hidden value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
This value can be used to select a CSS style definition for the<br />
component. It becomes the id value for the component’s enclosing<br />
element.<br />
Comma-separated list of additional component classes that this<br />
component needs to have defined on the client side. Use the full<br />
package and class name for each class in the list. Use import for<br />
cases in which the client needs classes that are not directly defined<br />
in the original object tree. The correct format is as follows:<br />
import="ZENDemo.Component.demoMenu,ZENTest.customComponent"<br />
This server-only attribute is not defined on the client side.<br />
58 <strong>Using</strong> <strong>Zen</strong>
Component Style Attributes<br />
Attribute<br />
label<br />
labelClass<br />
labelStyle<br />
Description<br />
A text label for the component. The component simply supplies the<br />
label text. Displaying this label is the responsibility of the component’s<br />
parent group.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its<br />
text into other languages. See <strong>Zen</strong> Localization.<br />
Name of a CSS style class. When <strong>Zen</strong> lays out this group, it applies<br />
this style to the label displayed for the component.<br />
String containing a CSS style statement such as:<br />
"color:red; background: yellow;"<br />
When <strong>Zen</strong> lays out this group, it applies this style to the label displayed<br />
for the component.<br />
name<br />
slice<br />
title<br />
valign<br />
width<br />
Specifies the name of the component.Typically, this is used to identify<br />
a control within a form. See <strong>Zen</strong> Forms.<br />
Used when this component’s parent group has a cellSize value of<br />
"stretch", slice is an integer value indicating the size of this component<br />
relative to other components within the group. <strong>Zen</strong> computes this<br />
size by dividing this component’s slice value by the sum of all slice<br />
values for all child components in the same group. The minimum<br />
value for slice is 0.<br />
Help text that displays when the user hovers the mouse over this<br />
component (or its label).<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its<br />
text into other languages. See <strong>Zen</strong> Localization.<br />
Possible values are "top", "bottom", or "middle". This becomes the<br />
valign value for the element that contains the child component<br />
in the generated HTML.<br />
CSS length value (integer or percentage). It may be "*" to indicate<br />
that the element should take up the remaining space in the layout<br />
table.This becomes the width value for the element that contains<br />
the child component in the generated HTML.<br />
<strong>Using</strong> <strong>Zen</strong> 59
<strong>Zen</strong> Style<br />
You can apply component style attributes while placing the component in the XData Contents block.<br />
The following example applies the style attributes valign, height, and width to the <strong>Zen</strong> components<br />
and :<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
My Title<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
7.2 Enclosing Element<br />
To facilitate use of CSS styles as well as dynamic HTML, every <strong>Zen</strong> component that you place on a<br />
<strong>Zen</strong> page is enclosed within an element on the generated HTML page. This is the enclosing<br />
for the component.<br />
If you have assigned a specific value to the component’s id attribute, this becomes the HTML id of<br />
the enclosing . This convention makes it possible to directly select the enclosing element from<br />
a CSS style sheet. For example, suppose you define a button as follows:<br />
<br />
You could then used the following CSS definition in your page’s XData Style block, to set the color<br />
of this button:<br />
XData Style<br />
{<br />
<br />
#myButton input {<br />
color: red;<br />
}<br />
<br />
}<br />
It is also possible to work with a component’s enclosing programmatically. Every component<br />
has a client-side getEnclosingDiv method that returns the HTML element that <strong>Zen</strong> is using as<br />
the component’s enclosing . For example:<br />
60 <strong>Using</strong> <strong>Zen</strong>
XData Style<br />
Method GiveMyButtonStyleToAbc() [ Language = javascript ]<br />
{<br />
var comp = zenPage.getComponentById('abc');<br />
var div = comp.getEnclosingDiv();<br />
}<br />
// div is an HTML div element<br />
div.className = 'myButton';<br />
7.3 XData Style<br />
Any <strong>Zen</strong> component class, page class, or application class can provide an XData Style block to define<br />
CSS styles. The <strong>Zen</strong> Tutorial chapter introduced XData Style when it displayed the skeleton class<br />
generated by the New <strong>Zen</strong> Application wizard, as follows:<br />
/// This is my first new <strong>Zen</strong> application.<br />
Class MyApp.MyNewApp Extends %ZEN.application<br />
{<br />
}<br />
/// This is the name of this application.<br />
Parameter APPLICATIONNAME = "My New <strong>Zen</strong> Application";<br />
/// This is the URL of the main starting page of this application.<br />
Parameter HOMEPAGE = "";<br />
/// This Style block contains application-wide CSS style definitions.<br />
XData Style<br />
{<br />
<br />
<br />
}<br />
To define styles for the application class shown above, you would add CSS statements between the<br />
tag and the closing tag.<br />
The following example shows an XData Style block in a page class. This class defines styles in the<br />
XData Style block and then references them from XData Contents by using the id attribute with components.<br />
The following example defines and then references the styles title, vg1, and vg2.<br />
<strong>Using</strong> <strong>Zen</strong> 61
<strong>Zen</strong> Style<br />
/// My very first <strong>Zen</strong> page class.<br />
Class MyApp.MyNewPage Extends %ZEN.Component.page<br />
{<br />
}<br />
/// Class name of application this page belongs to.<br />
Parameter APPLICATION = "MyApp.MyNewApp";<br />
/// Displayed name of this page.<br />
Parameter PAGENAME = "My Home Page";<br />
/// Domain used for localization.<br />
Parameter DOMAIN = "";<br />
/// This Style block contains page-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
/* style for title bar */<br />
#title {<br />
background: #C5D6D6;<br />
color: black;<br />
font-family: Verdana;<br />
font-size: 1.5em;<br />
font-weight: bold;<br />
padding: 5px;<br />
border-bottom: 1px solid black;<br />
text-align: center;<br />
}<br />
}<br />
#vg1 {<br />
border-right: 1px solid black;<br />
background: #E0E0FF;<br />
height: 600px;<br />
}<br />
#vg2 {<br />
}<br />
<br />
/// This XML block defines the contents of this page.<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
Title<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
7.4 Inheritance of Styles<br />
The effect of class inheritance on XData Style is one of simple replacement.<br />
62 <strong>Using</strong> <strong>Zen</strong>
Cascade of Styles<br />
Parent Defines<br />
XData Style<br />
Yes<br />
Yes<br />
No<br />
No<br />
Child Defines<br />
XData Style<br />
No<br />
Yes<br />
No<br />
Result<br />
Child inherits XData Style from the parent.<br />
Child uses its own XData Style definition.<br />
Some parent of both classes probably defines XData<br />
Style. If not, the browser applies its own style<br />
defaults.<br />
A class that inherits from another class overrides its parent’s XData Style. Thus, a custom component<br />
that provides XData Style overrides the XData Style in the base component class. A page class that<br />
provides XData Style overrides the XData Style in its template page class.<br />
However, this behavior does not cross over the boundaries of class inheritance. A is a component,<br />
but no component actually inherits from . So a component that appears on a page within<br />
an application does not override the XData Style block in either the page class or the application class.<br />
The XData Style blocks provided by the component class, page class, and application class all coexist,<br />
subject to the rules described in the next topic, Cascade of Styles.<br />
7.5 Cascade of Styles<br />
When a <strong>Zen</strong> page constructs itself, it collects all the CSS style information that you have provided for<br />
each component on the page, and applies it to the component. There may be many sources for this<br />
information: page classes, application classes, and component classes. <strong>Zen</strong> applies the information in<br />
these sources in the following order. Note that when conflicts exist, the styles that are defined last take<br />
precedence:<br />
1. Styles defined by the CSS file for the <strong>Zen</strong> component library, ZEN_Component.css<br />
2. Styles defined by base component classes.<br />
The default styles for the built-in <strong>Zen</strong> components are provided via an XData Style block in the<br />
corresponding %ZEN.Component class (or one of its parents). However, if you want to change<br />
the style of a built-in <strong>Zen</strong> component, do not edit the class directly. Either subclass the component<br />
to create a custom component, or override the corresponding style definitions in the page or<br />
application class.<br />
3. Styles defined by subclasses of base component classes (that is, custom components).<br />
<strong>Using</strong> <strong>Zen</strong> 63
<strong>Zen</strong> Style<br />
Any subclass of %ZEN.Component.component can provide an XData Style block. If the child has<br />
an XData Style block, this replaces the XData Style from the parent class. If not, the child inherits<br />
XData Style from the parent.<br />
4. Styles defined within the application class for the current application. These may come from any<br />
of the following sources. Styles from each source are evaluated in the sequential order as shown:<br />
• An XData Style block containing CSS statements<br />
• A reference to an external CSS file using the CSSINCLUDES parameter.<br />
5. Styles defined within the template page class (if there is one for the current page). These may<br />
come from any of the following sources. Styles from each source are evaluated in the sequential<br />
order as shown:<br />
• A reference to an external CSS file using the CSSINCLUDES parameter<br />
• An XData Style block containing CSS statements<br />
• Style attributes in XData Contents. For an individual component, these may provide:<br />
- Simple values for HTML attributes, such as "300" for height<br />
- Literal CSS statements, such as "color:red; background: yellow;")<br />
- The name of a CSS style that is defined somewhere in the cascade of styles<br />
6. Styles defined within the page class. For example:<br />
• A reference to an external CSS file using the CSSINCLUDES parameter<br />
• An XData Style block containing CSS statements<br />
• Style attributes in XData Contents. For an individual component, these may provide:<br />
- Simple values for HTML attributes, such as "300" for height<br />
- Literal CSS statements, such as "color:red; background: yellow;")<br />
- The name of a CSS style that is defined somewhere in the cascade of styles<br />
Thus, when it comes to style, “page” overrides “application” overrides “component.” Within each of<br />
these categories, “child” overrides “parent.”<br />
64 <strong>Using</strong> <strong>Zen</strong>
Overriding Built-in Styles<br />
Cascade of Style Definitions<br />
This order of precedence makes it easier to ensure a consistent “look and feel” for your application.<br />
You can override the style definition within the application class (for an application-wide style override),<br />
within a template page class (to override a value for a suite of pages) or within an ordinary page class<br />
(to override a value for a specific page).<br />
However, it is important to note that this order of precedence does not exactly match the hierarchy of<br />
these objects when ZEN constructs the page for display. Compare this discussion and diagram with<br />
the chapter <strong>Zen</strong> Application Concepts, topic <strong>Zen</strong> Applications.<br />
7.6 Overriding Built-in Styles<br />
Suppose you want to override the style of a built-in <strong>Zen</strong> component such as . There is no<br />
requirement to do this, but once you get your table onto the page, you might discover that you want<br />
to change its appearance. If so, you must override the CSS styles for . To accomplish this,<br />
you need to know:<br />
• The name of the CSS style definition that you want to change<br />
• Where, in the cascade of styles, you want to interject changes to this style<br />
<strong>Using</strong> <strong>Zen</strong> 65
<strong>Zen</strong> Style<br />
• Which technique you want to use to apply changes to the style:<br />
- Referencing an external CSS file from a <strong>Zen</strong> class<br />
- Providing an XData Style block in a <strong>Zen</strong> class<br />
The following XData Style block changes the background color, border style, and font family choices<br />
for a CSS rule called table.tpTable. How did the developer choose this rule to change How does<br />
this XData Style block fit into the cascade of styles And why did the developer choose to provide an<br />
XData Style block rather than an external CSS file The next several topics provide answers.<br />
XData Style<br />
{<br />
<br />
table.tpTable {<br />
background: green;<br />
border: 1px solid red;<br />
font-family: courier new;<br />
}<br />
<br />
}<br />
7.6.1 Finding the CSS Style Name<br />
You can determine which CSS rules to override for a specific <strong>Zen</strong> component as follows:<br />
1. Somewhere in the inheritance tree for each <strong>Zen</strong> component, there is an XData Style block that<br />
defines the CSS rules for this component. To find the correct one, usually you must know something<br />
about the inheritance of the component class. For example, %ZEN.Component.tablePane inherits<br />
from %ZEN.Component.simpleTablePane. It is the simpleTablePane class that contains the relevant<br />
XData Style block. There is no XData Style block in the tablePane class.<br />
You can use the online class documentation to trace inheritance. Start the documentation in one<br />
of the following ways:<br />
• From Studio, choose Tools > Class Browser. Under the %ZEN.Component package, find the<br />
class you are interested in. Right-click on the class name and choose <strong>Documentation</strong>.<br />
• Start the <strong>InterSystems</strong> online documentation. Scroll to the bottom of the documentation home<br />
page and choose Class Reference Information. Choose the %SYS namespace and<br />
%ZEN.Component package. Click on the class name.<br />
Once you have found the documentation page for the class of interest, see if it inherits from another<br />
<strong>Zen</strong> component class. If so, the XData Style block is probably in the parent class. You can click<br />
on the parent class name to navigate to its documentation page.<br />
2. When you know the class name of the component you want to research, you need to view its CSS<br />
style definitions. You can do this in one of the following ways:<br />
66 <strong>Using</strong> <strong>Zen</strong>
• In Studio, run the <strong>Zen</strong> Style Wizard to see if the component or its parent are listed. The <strong>Zen</strong><br />
Style Wizard is the easiest way to modify styles. It does not include every style, but lists the<br />
most popular styles for modification. simpleTablePane is there, with the entry:<br />
table.tpTable<br />
Described as:<br />
Main table for tablePane<br />
• In Studio, in the %SYS namespace and %ZEN.Component package, open the component class<br />
for viewing. Find its XData Style block or that of its parent, and see what CSS rules it contains.<br />
• Examine the CSS file for the <strong>Zen</strong> component library. The file is located as follows, where<br />
C:\CacheSys is the name of your installation directory:<br />
C:\CacheSys\CSP\broker\ZEN_Component.css<br />
Search for the component name in the code comments. The styles that follow (until the next<br />
component name) are those for the component. For example:<br />
/* %ZEN.Component.simpleTablePane */<br />
/* table */<br />
table.tpTable {<br />
background: white;;<br />
border: 1px solid black;<br />
font-family: arial;<br />
width: 100%;<br />
table-layout: fixed;<br />
empty-cells: show;<br />
}<br />
/* ...etc... */<br />
Overriding Built-in Styles<br />
7.6.2 Overriding a CSS Style Rule<br />
Once you have found the CSS rule that applies to the component whose appearance you want to<br />
modify, you can override the CSS rule in one of two ways:<br />
• Referencing an external CSS file from a <strong>Zen</strong> application, or page class<br />
• Providing an XData Style block in a <strong>Zen</strong> application, page, or custom component class<br />
To effectively predict the results of your changes, keep in mind the order of precedence rules described<br />
in the previous topic, Cascade of Styles. The following table restates these rules in terms of the results<br />
that you are trying to accomplish.<br />
<strong>Using</strong> <strong>Zen</strong> 67
<strong>Zen</strong> Style<br />
Where and How to Override Built-in Styles<br />
What to Accomplish<br />
Application-wide<br />
styling rules. You can<br />
override these styles<br />
in template pages or<br />
in individual page<br />
classes.<br />
Styles that apply to a<br />
group of pages within<br />
an application. You<br />
can override these<br />
styles in individual<br />
page classes.<br />
Where to Interject Style Changes<br />
Place the revised CSS rule in an external CSS file and reference<br />
from the application class using the CSSINCLUDES class<br />
parameter. The value of CSSINCLUDES can be a<br />
comma-separated list of multiple CSS files.<br />
Place an XData Style block in the application class and place<br />
the revised CSS rule definition within it.You can either type rule<br />
syntax into XData Style or use the <strong>Zen</strong> Style Wizard for<br />
convenient style editing. If there are style conflicts between XData<br />
Style and CSSINCLUDES for the application, XData Style takes<br />
precedence.<br />
Create a template page class. Ensure that all the pages you want<br />
to have consistent style are subclasses of this template page.<br />
Place the revised CSS rule in an external CSS file and reference<br />
from the template page class using the CSSINCLUDES class<br />
parameter. The value of CSSINCLUDES can be a<br />
comma-separated list of multiple CSS files.<br />
Place an XData Style block in the template page class and place<br />
the revised CSS rule definition within it.You can either type rule<br />
syntax into XData Style or use the <strong>Zen</strong> Style Wizard for<br />
convenient style editing. If there are style conflicts between XData<br />
Style and CSSINCLUDES for the template page class, XData<br />
Style takes precedence.<br />
Styles that apply to<br />
only one page within<br />
an application.<br />
Place the revised CSS rule in an external CSS file and reference<br />
from the page class using the CSSINCLUDES class parameter.<br />
The value of CSSINCLUDES can be a comma-separated list of<br />
multiple CSS files.<br />
Place an XData Style block in the page class and place the<br />
revised CSS rule definition within it. You can either type rule<br />
syntax into XData Style or use the <strong>Zen</strong> Style Wizard for<br />
convenient style editing. If there are style conflicts between XData<br />
Style and CSSINCLUDES for the page class, XData Style takes<br />
precedence.<br />
68 <strong>Using</strong> <strong>Zen</strong>
Applying New Styles<br />
What to Accomplish<br />
Styles that apply to<br />
all instances of a<br />
particular component.<br />
Where to Interject Style Changes<br />
Any styles defined in application or page classes automatically<br />
override styles defined in component classes, so for stylistic<br />
consistency and control you should make changes near the end<br />
of the cascade, in the application or page class, rather than in<br />
the component class.<br />
However, if you wish, you may create a custom components that<br />
is a subclass of the built-in <strong>Zen</strong> component whose styles you<br />
wish to change. Place an XData Style block in the custom<br />
component class and place the revised CSS rule definition within<br />
this XData Style.You can either type rule syntax into XData Style<br />
or use the <strong>Zen</strong> Style Wizard for convenient style editing.<br />
In any case, do not edit the XData Style block in a built-in <strong>Zen</strong><br />
component class or its parent. Do not edit the built-in stylesheet<br />
ZEN_Component.css. Changes of this kind will be lost next time<br />
you upgrade the Caché server version.<br />
7.7 Applying New Styles<br />
The above topics explain how to modify styles that are already in use by a built-in <strong>Zen</strong> component. If<br />
you want to define an entirely new CSS style (with a new name) and apply that style to a component,<br />
there are additional steps to perform. In that case you must not only subclass the component and define<br />
the CSS style, but also reference that CSS style from the portion of the subclass that renders the component<br />
on the page as HTML. A later chapter, Custom Components, covers these steps in detail.<br />
<strong>Using</strong> <strong>Zen</strong> 69
8<br />
<strong>Zen</strong> Tables<br />
A <strong>Zen</strong> table is data-driven. It takes the resultset returned by an SQL query and displays it as an HTML<br />
table. There are a number of ways to generate the resultset for a <strong>Zen</strong> table. You can specify an SQL<br />
statement, reference a pre-defined SQL query, or provide <strong>Zen</strong> with the inputs it needs to generate an<br />
SQL query for you.<br />
Once you have the data, you can style the resulting table in any way you wish. The following figure<br />
shows a simple example. This table uses “zebra” patterning for alternate rows. The user has entered<br />
data in the table header to filter the results that the table displays. In this case, the user has selected<br />
only entries whose names begin with X, with Active status, who are also Assistants.<br />
This chapter explains how to work with <strong>Zen</strong> tables as follows:<br />
• How to place a table on a <strong>Zen</strong> page<br />
• How to work with the table programmatically after it is on the <strong>Zen</strong> page<br />
• How to identify the data source for a <strong>Zen</strong> table<br />
<strong>Using</strong> <strong>Zen</strong> 71
<strong>Zen</strong> Tables<br />
• How to supply parameters for the table query, if needed<br />
• How to specify column details, including filters and links<br />
• General style properties that <strong>Zen</strong> tables can have<br />
• How to define data-specific styling for rows and columns<br />
• How snapshot mode supports multipage tables and simplifies refresh operations<br />
• How a <strong>Zen</strong> table handles user interactions<br />
• What happens during table refresh operations, and how to request them<br />
8.1 <br />
is the XML projection of the versatile %ZEN.Component.tablePane class. To place a table<br />
on a <strong>Zen</strong> page, place a component inside the page class XData Contents block.<br />
As you read this chapter, you will encounter descriptions of the various component and auxiliary<br />
classes that <strong>Zen</strong> supplies to support tables. The following list summarizes the XML elements that you<br />
will use to represent these classes in XData Contents. The most important of these is :<br />
• — Draws an HTML table based on an SQL query. Each row in the resultset is displayed<br />
as a row in the table. A may contain the following elements, as needed:<br />
- — Each element provides one of the parameters required to construct<br />
the query.<br />
- — Each element specifies layout, style, and behavior details for a particular<br />
column in the resulting table. elements are optional when all columns in<br />
the resultset are displayed. However, sometimes a needs to select which of the<br />
columns in the resultset should be displayed. When this is the case, elements are<br />
required.<br />
- — Each element defines one data-specific detail that applies to<br />
rows and cells within the table. For example, cells that contain a certain value might display<br />
a certain background color, such as red to indicate an error condition. The specific cells that<br />
contain this value might be different each time the table refreshes; <strong>Zen</strong> keeps track of these<br />
details for you and colors all cells appropriately.<br />
• — Automatically provides a standard set of buttons for moving through the<br />
pages of a multipage table.<br />
• — An alternative to , this element provides extra buttons<br />
to help users navigate large, multipage tables.<br />
72 <strong>Using</strong> <strong>Zen</strong>
Data Sources<br />
has the following general-purpose attributes.<br />
Attribute<br />
dataSource<br />
Description<br />
Specifies which columns from the %ResultSet to display, and in what order.<br />
Possible values are:<br />
• "query" — All columns referenced by the query appear, in order from<br />
left to right.<br />
• "columns" — Only the columns explicitly defined as entries<br />
within the appear, in order from left to right.<br />
When you omit dataSource from the , <strong>Zen</strong> uses the value<br />
"query" by default, unless there are entries defined, in which<br />
case <strong>Zen</strong> ignores any dataSource value and uses "columns".<br />
initialExecute<br />
If initialExecute is true, the query associated with this is<br />
executed when the table is first displayed. Otherwise the <br />
will execute the query only on demand. The default is true.<br />
initialExecute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
offers many additional attributes that you can use to configure layout, style, and behavior.<br />
The following topics describe them.<br />
8.2 Data Sources<br />
A element must indicate a data source for the table in one of the following ways:<br />
• Specifying an SQL statement<br />
• Providing a simple description that <strong>Zen</strong> uses to generate an SQL statement<br />
• Referencing a class query that generates an SQL statement<br />
• Referencing a callback method that generates an SQL statement<br />
The following topics describe each option in detail. Regardless of which option you use, all techniques<br />
support the maxRows attribute. It controls the size of the data returned.<br />
<strong>Using</strong> <strong>Zen</strong> 73
<strong>Zen</strong> Tables<br />
Attribute<br />
maxRows<br />
Description<br />
The maximum number of rows to fetch. For ordinary tables this is the<br />
maximum number of rows to display. For snapshot tables, maxRows is<br />
the maximum size of the snapshot and pageSize is the number of rows to<br />
display per page. The default value for maxRows is 100.<br />
8.2.1 Specifying an SQL Query<br />
A can provide a complete SQL statement as the value of its sql attribute. <strong>Zen</strong> executes<br />
this SQL statement to provide the contents of the table.<br />
The following is an example of a simple SQL statement:<br />
<br />
You may provide any input parameter values using elements inside the .<br />
The attribute is the XML projection of the %ZEN.Component.tablePane property sql.<br />
Unlike most other %ZEN.Component.tablePane properties, the sql property cannot be set from the<br />
client at runtime. It can only be set from XData Contents. This is because sql is an encrypted attribute.<br />
The sqlvalue is encrypted (using the current session key) when it is sent to the client. If this value is<br />
returned to the server, it is automatically decrypted.<br />
This prevents users from seeing the definition of an SQL statement if they view page source within<br />
their browser and prevents client logic from constructing arbitrary queries. For security reasons, query<br />
activities should always be restricted to the server.<br />
8.2.2 Generating an SQL Query<br />
Constructing SQL queries can be tedious, so the supports attributes that allow you to<br />
automatically generate the query based on a simple description. Basically, this is similar to using a<br />
callback method (as described in a later topic) except that <strong>Zen</strong> generates the callback method for you,<br />
based on your description of the query.<br />
Attribute<br />
groupByClause<br />
Description<br />
(Optional) An SQL GROUP BY clause such as "Year,State". The<br />
groupByClause value can be a literal string, or it can contain a <strong>Zen</strong><br />
#()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
74 <strong>Using</strong> <strong>Zen</strong>
Data Sources<br />
Attribute<br />
orderByClause<br />
tableName<br />
whereClause<br />
Description<br />
(Optional) An SQL ORDER BY clause such as "Name,State". If not<br />
provided, then whenever the user clicks on a column header, the next<br />
query contains the appropriate ORDER BY clause based on the user’s<br />
choice. The orderByClause value can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
The name of the SQL table that provides the data for the table. This<br />
value is used in the FROM clause for the generated query. The<br />
tableName value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
(Optional) An SQL WHERE clause such as "Name='Elvis'". If not<br />
provided, then if any column filters are defined in this table, a WHERE<br />
clause is created based on the current filter values. The whereClause<br />
value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
To have the generate an SQL query, you must do the following:<br />
1. Provide a value for the tableName attribute.<br />
2. Do not provide values for the sql, queryClass, queryName, or OnCreateResultSet. All of these<br />
attributes take precedence over the behavior described in this topic.<br />
After you satisfy the first two conditions, <strong>Zen</strong> assumes a "columns" value for dataSource.<br />
3. Define the names of one or more columns by providing elements inside the .<br />
There must be at least one column defined or a “Missing SELECT list” error will result.<br />
4. You can add query parameters by providing elements inside the .<br />
5. You can add clauses for the generated query by providing the attributes<br />
groupByClause, orderByClause, or whereClause, or by allowing defaults to prevail as described<br />
in the table above.<br />
The following is a simple example:<br />
<br />
<br />
<br />
<br />
This example generates an SQL statement similar to the following:<br />
SELECT ID,Name FROM MyApp.Employee<br />
<strong>Using</strong> <strong>Zen</strong> 75
<strong>Zen</strong> Tables<br />
<strong>Zen</strong> executes this query to provide the contents of the table. In the example, the ID column is marked<br />
as hidden. This means that its value is fetched (it can be used for conditions or actions) but not displayed.<br />
For details about hidden and other attributes, see the Table Columns topic.<br />
Note:<br />
A generated SQL query can be useful for tables with column filters.<br />
8.2.3 Referencing a Class Query<br />
A can reference a pre-existing class query to obtain a %ResultSet object. The following<br />
attributes support this approach.<br />
Attribute<br />
queryClass<br />
queryName<br />
Description<br />
The name of the class containing the query.You must also provide a value<br />
for queryName.<br />
The name of the class query that will provide the %ResultSet for this<br />
. You must also provide a value for queryClass.<br />
You may provide any input parameter values for the query by placing elements inside<br />
the . For example:<br />
<br />
<br />
<br />
<br />
8.2.4 <strong>Using</strong> a Callback Method<br />
A can generate a table using an application-defined %ResultSet object. The following<br />
attributes support this approach.<br />
76 <strong>Using</strong> <strong>Zen</strong>
Data Sources<br />
Attribute<br />
OnCreateResultSet<br />
OnExecuteResultSet<br />
showQuery<br />
Description<br />
The name of a server-side callback method to call to create a<br />
%ResultSet object. The OnCreateResultSet value must be the<br />
name of a server-only method defined in the page class whose<br />
XData Contents references the component.<br />
The name of a server-side callback method to call to execute the<br />
%ResultSet object returned by the method identified by<br />
OnCreateResultSet. The OnExecuteResultSet value must be the<br />
name of a server-only method defined in the page class whose<br />
XData Contents references the component.<br />
showQuery works only if a callback method is used to generate<br />
the table, and only if this method sets the queryText property of the<br />
QueryInfo object to contain the text of the query. The next topic,<br />
Data Sources, explains the details. Of the various components<br />
that use callback methods to generate SQL queries, only<br />
and support the showQuery attribute.<br />
If showQuery is true, the <strong>Zen</strong> page displays the SQL query used<br />
to provide the contents of the or <br />
component. This is useful for troubleshooting purposes, during<br />
application development. The default showQuery value is false.<br />
showQuery has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
The showQuery value can be a literal string, or it can contain a<br />
<strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
Consider the following example:<br />
<br />
The corresponding server-side callback method is defined within the page class as follows. The callback<br />
method must return a new instance of %ResultSet object that is executed and processed by the tablePane.<br />
It must also return a status code by reference to indicate if there were any errors encountered in creating<br />
the %ResultSet object.<br />
Method CreateRS(Output pSC As %Status,<br />
pInfo As %ZEN.Auxiliary.QueryInfo) As %ResultSet<br />
{<br />
Set pSC = $$$OK<br />
Set tRS = ##class(%ResultSet).%New()<br />
// ... method activities here ...<br />
Quit tRS<br />
}<br />
<strong>Using</strong> <strong>Zen</strong> 77
<strong>Zen</strong> Tables<br />
As you can see from the method signature in the example above, the callback method receives information<br />
from the tablePane class via a %ZEN.Auxiliary.QueryInfo object; some information is also passed<br />
back via this object. For details about this object, see the following table.<br />
QueryInfo Properties<br />
Property<br />
columnExpression<br />
columns<br />
filterOps<br />
filters<br />
filterTypes<br />
groupByClause<br />
orderByClause<br />
parms<br />
queryExecuted<br />
queryText<br />
Description<br />
The colExpression values from each in the .<br />
columnExpression organizes these values as a multidimensional array<br />
subscripted by colName.<br />
The colName values from each in the .<br />
columns organizes these values as a multidimensional array<br />
subscripted by column number (1–based).<br />
The filterOp values from each in the . filterOps<br />
organizes these values as a multidimensional array subscripted by<br />
colName.<br />
The filterValue values from each in the .<br />
filters organizes these values as a multidimensional array subscripted<br />
by colName.<br />
The filterType values from each in the .<br />
filterTypes organizes these values as a multidimensional array<br />
subscripted by by colName.<br />
The groupByClause value for the , if supplied.<br />
The orderByClause value for the , if supplied.<br />
Multidimensional array, subscripted by parameter number (1–based).<br />
This array contains any input values provided by <br />
elements within the .<br />
Set this property to true in the method identified by<br />
OnCreateResultSet, to indicate that the newly created %ResultSet<br />
has already been executed and you do not want the method<br />
identified by OnExecuteResultSet to be called. The default is false.<br />
The method identified by OnCreateResultSet can set this value to<br />
the actual query text, to be displayed if the showQuery value is true.<br />
78 <strong>Using</strong> <strong>Zen</strong>
Data Sources<br />
Property<br />
rowCount<br />
Description<br />
If this value is set by the callback, upon return the rowCount property<br />
contains the number of rows returned by the query. After the query<br />
is executed, rowCount could be different from rows.<br />
Note that rowCount is a string, and not numeric, as its value might<br />
be "" or "100+". Any number of rows greater than 100 is represented<br />
as "100+". When testing rowCount from JavaScript, if you<br />
want to convert to a numeric value use parseInt for base 10:<br />
rowCount = parseInt(rowCount,10);<br />
rows<br />
sortColumn<br />
sortOrder<br />
tableName<br />
whereClause<br />
The number of rows requested. For tables, this is the maxRows<br />
value.<br />
The colName of the current sort column selected by the user.<br />
The table’s current sort order (usually determined by user clicks)<br />
such as "asc" or "desc".<br />
The tableName value.<br />
The whereClause value for the , if supplied.<br />
Just like tablePane, the control components dataCombo and dataListBox can also use a callback method<br />
to generate a %ResultSet. repeatingGroup can do this as well. Some of the properties in the QueryInfo<br />
object apply only to tablePane queries. dataCombo, dataListBox, and repeatingGroup ignore any tableonly<br />
properties, including those for columns, filters, and sorting. Only tablePane and dataCombo<br />
support queryText.<br />
The following is a more detailed example of using a callback method to create a %ResultSet. The<br />
callback method constructs a dynamic SQL statement in response to current values of tablePane<br />
properties sortOrder and sortColumn. The tablePane automatically passes these values to the callback<br />
method as the corresponding properties of the input %ZEN.Auxiliary.QueryInfo object.<br />
Also note how the method places the SQL statement text in the queryText property of QueryInfo before<br />
exiting. If the showQuery value is true, this table will display itself, plus the query that<br />
generated it.<br />
<strong>Using</strong> <strong>Zen</strong> 79
<strong>Zen</strong> Tables<br />
Method CreateRS(Output tSC As %Status,<br />
pInfo As %ZEN.Auxiliary.QueryInfo) As %ResultSet<br />
{<br />
Set tRS = ""<br />
Set tSC = $$$OK<br />
Set tSELECT = "ID,Name,Title"<br />
Set tFROM = "MyApp.Employee"<br />
Set tORDERBY = pInfo.sortColumn<br />
Set tSORTORDER = pInfo.sortOrder<br />
Set tWHERE = ""<br />
// Build WHERE clause based on filters<br />
If ($GET(pInfo.filters("Name"))'="") {<br />
Set tWHERE = tWHERE _ $SELECT(tWHERE="":"",1:" AND ") _<br />
"Name %STARTSWITH '" _ pInfo.filters("Name") _ "'"<br />
}<br />
If ($GET(pInfo.filters("Title"))'="") {<br />
Set tWHERE = tWHERE _ $SELECT(tWHERE="":"",1:" AND ") _<br />
"Title %STARTSWITH '" _ pInfo.filters("Title") _ "'"<br />
}<br />
Set sql = "SELECT " _ tSELECT _ " FROM " _ tFROM<br />
Set:tWHERE'="" sql = sql _ " WHERE " _tWHERE<br />
Set:tORDERBY'="" sql =<br />
sql _ " ORDER BY " _tORDERBY _ $SELECT(tSORTORDER="desc":" desc",1:"")<br />
Set tRS = ##class(%ResultSet).%New()<br />
Set tSC = tRS.Prepare(sql)<br />
Set pInfo.queryText = sql<br />
}<br />
Quit tRS<br />
8.3 Query Parameters<br />
When you are working with SQL queries to generate the data for a <strong>Zen</strong> table, you sometimes need to<br />
provide values for query input parameters, defined as characters within the query. To do this, use<br />
elements within the element.<br />
Attribute<br />
value<br />
Description<br />
Specifies the parameter value:<br />
<br />
The value supplied for a parameter can be a literal string, or it can contain<br />
a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
Previous topics showed examples of using the element, including the following class<br />
query example:<br />
80 <strong>Using</strong> <strong>Zen</strong>
Table Columns<br />
<br />
<br />
<br />
<br />
When you work with %ZEN.Component.tablePane programmatically, you work with <br />
elements as members of the tablePane parameters property, a list collection. Each in the<br />
becomes a member of the parameters collection in tablePane, associated with an ordinal<br />
position: 1, 2, 3, etc.<br />
You can change the value of query parameters at runtime, from the client, by setting values in the<br />
parameters collection property of the tablePane object. The following example changes the value of<br />
the first parameter to Finance, re-executes the query on the server, and updates the contents of the<br />
tablePane to display the new results:<br />
Method changeParams() [ Language = javascript ]<br />
{<br />
// find the tablePane component<br />
var table = this.getComponentById('table');<br />
table.setProperty('parameters',1,'Finance');<br />
}<br />
8.4 Table Columns<br />
Previous topics explained that draws an HTML table based on an SQL query. Each row<br />
in the query resultset is displayed as a row in the table. A may also contain one or more<br />
elements. These select which of the columns in the query resultset should be displayed in<br />
the table. elements also specify layout, style, and behavior for each column.<br />
Previous topics showed several examples of using the element, including the following<br />
example, in which elements help <strong>Zen</strong> to automatically construct an SQL query:<br />
<br />
<br />
<br />
<br />
<br />
The element is the XML projection of the %ZEN.Auxiliary.column class. supports<br />
the general-purpose attributes described in the following table.<br />
<strong>Using</strong> <strong>Zen</strong> 81
<strong>Zen</strong> Tables<br />
Attribute<br />
cellTitle<br />
colExpression<br />
colName<br />
header<br />
hidden<br />
OnDrawCell<br />
seed<br />
Description<br />
Text specifying the tooltip message for any cell within the column.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
If the table is automatically constructing an SQL query, this is the SQL<br />
expression used to get the value of this column. For example:<br />
colExpression="Customer->Name"<br />
The name of the SQL data column that this column is associated with.<br />
The colName value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
If not specified, the column is displayed without a data value. Typically<br />
this technique is used to display a link action in a row.<br />
Text specifying the column header.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
The header value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
If true, this column is not be displayed. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
The hidden value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
The name of a server-side callback method that provides HTML content<br />
for cells within this column. If defined, this callback is invoked on the<br />
server when this component is drawn. It provides HTML content by using<br />
&html or the WRITE command.<br />
The OnDrawCell value must be the name of a server-only method defined<br />
in the page class whose XData Contents references the <br />
component.<br />
Allows you to pass some arbitrary value to the OnDrawCell callback.<br />
82 <strong>Using</strong> <strong>Zen</strong>
Table Style<br />
Attribute<br />
style<br />
title<br />
width<br />
Description<br />
CSS style value to be applied to the cells (HTML elements) within<br />
this column. For example: "color: red;"<br />
The style value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
Text specifying the tooltip displayed when the user moves the mouse<br />
over the column header.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
The HTML style value for <strong>Zen</strong> tables is "fixed". This means that each<br />
column has a specific width value in the generated HTML page. <strong>Zen</strong><br />
determines these values as follows:<br />
• You can specify a width value for any column.<br />
• If you do not specify a width, <strong>Zen</strong> assigns a width that is proportional<br />
to the size of the contents of that column (relative to other columns<br />
in the table).<br />
The width value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
also provides attributes that support dynamic filtering, linking, and sorting of the <strong>Zen</strong> table.<br />
Later topics describe these special-purpose attributes.<br />
When you work with %ZEN.Component.tablePane programmatically, you work with elements<br />
as members of the tablePane columns property, a list collection of %ZEN.Auxiliary.column objects.<br />
Each in the becomes a member of the columns collection in tablePane, associated<br />
with its ordinal position: 1, 2, 3, etc.<br />
8.5 Table Style<br />
offers the following attributes to control the general style of the table.<br />
<strong>Using</strong> <strong>Zen</strong> 83
<strong>Zen</strong> Tables<br />
Attribute<br />
caption<br />
extraColumnWidth<br />
fixedHeaders<br />
bodyHeight<br />
nowrap<br />
showRowNumbers<br />
showValueInTooltip<br />
Description<br />
Text specifying the caption to display for this table.<br />
Although you enter ordinary text for this attribute, it has the<br />
underlying data type %ZEN.Datatype.caption. This makes it easy to<br />
localize its text into other languages. See <strong>Zen</strong> Localization.<br />
The HTML width to allow for extra columns, such as when multiple<br />
rows are selected or row numbers are displayed in the tablePane.<br />
The default width for an extra column is 30.<br />
If true, the header of the table will stay in position when the body<br />
of the table is scrolled. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
If fixedHeaders is true, bodyHeight provides an HTML length value<br />
that specifies the height of the body section of the table. The<br />
default bodyHeight is "20.0em".<br />
If true, table cells disallow word wrapping. If false, they allow it.<br />
The default is true.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
If true, display a row number column on the left-side of the<br />
tablePane. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
If true, the tooltip (HTML title attribute) displayed for cells within<br />
the table consists of the current value of the cell. The default is<br />
false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
84 <strong>Using</strong> <strong>Zen</strong>
Conditional Style for Rows or Cells<br />
Attribute<br />
showZebra<br />
Description<br />
If true, use zebra striping (alternating dark and light rows) to display<br />
the tablePane. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
8.6 Conditional Style for Rows or Cells<br />
A may contain one or more elements. Each is a simple expression,<br />
based on the values of a given row, that controls the style of the row or of an individual cell within<br />
the row. For example:<br />
<br />
<br />
<br />
In the above example, every row in which the value of the Name column starts with “A” will be displayed<br />
with a plum background.<br />
Typically, the conditional style mechanism is used to highlight rows or cells containing special values<br />
(such as out-of-range or error cases). Adding conditions does increase the amount of processing needed<br />
to display a table, so use them sparingly.<br />
The element supports the following attributes.<br />
Attribute<br />
cellStyle<br />
Description<br />
CSS style to be applied to cells within the target column, for rows in which<br />
this condition evaluates true. For example:<br />
"color: red;"<br />
colName<br />
Required. The name of the column that provides the data value to be<br />
evaluated by the . colName can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
<strong>Using</strong> <strong>Zen</strong> 85
<strong>Zen</strong> Tables<br />
Attribute<br />
predicate<br />
rowStyle<br />
Description<br />
The logical operator used to evaluate the condition. predicate may be one<br />
of the following comparison operators: "", "GT", "EQ", "LT", "NEQ",<br />
"GTEQ", "LTEQ", "EXTEQ", "STARTSWITH", or "CONTAINS". The default<br />
predicate is "EQ". For details about each operator, see the next table.<br />
CSS style to apply to rows in which this condition evaluates to true. For<br />
example:<br />
"font-weight: bold;"<br />
targetCol<br />
value<br />
The name of the column that cellStyle applies to. If not specified, colName<br />
is used.<br />
targetCol can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
The literal value to be compared against the value in the column identified<br />
in colName. If enclosed within {} (for example, "{Title}") value is treated<br />
as the name of another column, and the value in that column is used.<br />
value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
When a table is displayed, all elements within the are evaluated individually<br />
for each row in the table. If a evaluates true, then the rowStyle or cellStyle for the condition<br />
is applied to the row or cell, respectively.<br />
The predicate attribute may have the following values.<br />
predicate Values<br />
Predicate<br />
CONTAINS<br />
EQ<br />
EXTEQ<br />
GT<br />
Description<br />
True if the value in the column identified by colName contains (as a<br />
substring) the value specified by value.<br />
True if the value in the column identified by colName is equal to the<br />
value specified by value.<br />
True if the filename in the column identified by colName has the file<br />
extension specified by value.<br />
True if the value in the column identified by colName is greater than<br />
the value specified by value.<br />
86 <strong>Using</strong> <strong>Zen</strong>
Snapshot Mode<br />
Predicate<br />
GTEQ<br />
LT<br />
LTEQ<br />
NEQ<br />
STARTSWITH<br />
Description<br />
True if the value in the column identified by colName is greater than<br />
or equal to the value specified by value.<br />
True if the value in the column identified by colName is less than the<br />
value specified by value.<br />
True if the value in the column identified by colName is less than or<br />
equal to the value specified by value.<br />
True if the value in the column identified by colName is not equal to<br />
the value specified by value.<br />
True if the value in the column identified by colName starts with the<br />
value specified by value.<br />
When you work with %ZEN.Component.tablePane programmatically, you work with <br />
elements as members of the tablePane conditions property, a list collection of %ZEN.Auxiliary.condition<br />
objects. Each in the becomes a member of the conditions collection in<br />
tablePane, associated with its ordinal position: 1, 2, 3, etc.<br />
8.7 Snapshot Mode<br />
A can operate in snapshot mode. In this mode, <strong>Zen</strong> runs the table query once and copies<br />
these results to a temporary location on the server. Subsequent screen refresh operations display data<br />
from this temporary location, rather than resubmitting the query. <strong>Zen</strong> automatically manages the creation<br />
and lifecycle of the temporary snapshot data. Snapshot mode is particularly useful for working with<br />
multipage tables, or with tables that the user can sort.<br />
The element supports the following attributes for snapshot mode.<br />
<strong>Using</strong> <strong>Zen</strong> 87
<strong>Zen</strong> Tables<br />
Attribute<br />
useSnapshot<br />
pageSize<br />
Description<br />
When true, this is in snapshot mode. This means that<br />
whenever data is fetched, it is copied into a server-side temporary<br />
location. Paging and sorting operations use this snapshot data and do<br />
not re-execute the query. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
For snapshot tables, this attribute specifies that you wish to display the<br />
data as multiple pages, and what the page size should be. 0, the default,<br />
means show all data on first page. This can only be set to a non-zero<br />
value when the table is in snapshot mode. Compare maxRows, which<br />
is the total number of rows to fetch in the query.<br />
Any of the query mechanisms described in the previous topics can be used with snapshot or direct<br />
(non-snapshot) mode. The following example specifies an SQL query to be used in snapshot mode:<br />
<br />
The following %ZEN.Component.tablePane properties are not available as XML attributes in the<br />
definition, but they can be useful for working with snapshot tables once the page has been<br />
created.<br />
Attribute<br />
clearSnapshot<br />
currPage<br />
Description<br />
A runtime flag that the client can set to true to force re-execution of<br />
the table query when <strong>Zen</strong> would otherwise use the stored snapshot.<br />
The default is false.<br />
For snapshot tables with multiple pages of data, this is the (1–based)<br />
index number of the currently displayed page of data.<br />
You can also programmatically adjust the values for useSnapshot and pageSize that were originally<br />
set by in XData Contents.<br />
8.7.1 Fetching Data From the Server<br />
The %ZEN.Component.tablePane class offers a getRowData method for tables in snapshot mode only.<br />
getRowData fetches the data values for a given row (0-based) from the server-side snapshot data.<br />
88 <strong>Using</strong> <strong>Zen</strong>
This data is packaged into a JavaScript object whose properties correspond to the names of the columns<br />
in the snapshot table; type conversion is handled appropriately. For non-snapshot tables or out-of-range<br />
row numbers, getRowData returns null.<br />
8.7.2 Navigating Snapshot Tables<br />
Snapshot Mode<br />
Several different options permit users to navigate multipage tables. The and<br />
components provide a basic navigation interface. is particularly<br />
useful for managing multipage tables. For details, see Navigation Buttons.<br />
If you wish to undertake additional programming, the %ZEN.Component.tablePane class provides a<br />
client-side JavaScript API that an application can use to implement the desired paging interface. These<br />
methods work only when the tablePane is in snapshot mode. They include:<br />
Method<br />
getPageCount()<br />
getProperty('currPage')<br />
getProperty('pageSize')<br />
getProperty('rowCount')<br />
Description<br />
Calculates and returns the current number of<br />
pages within the table.<br />
Returns the page number (1–based) of the<br />
current page displayed by the table.<br />
Returns the current page size.<br />
Returns the total number of rows within the<br />
table.<br />
Note that rowCount is a string, and not numeric,<br />
as its value might be "" or "100+". Any<br />
number of rows greater than 100 is represented<br />
as "100+". When testing rowCount<br />
from JavaScript, if you want to convert to a<br />
numeric value use parseInt for base 10:<br />
rowCount = parseInt(rowCount,10);<br />
setProperty('currPage',pageno)<br />
setProperty('pageSize',rows)<br />
Changes the current page displayed by the<br />
table to pageno.<br />
Changes the current page size used by the<br />
table to rows.<br />
<strong>Using</strong> <strong>Zen</strong> 89
<strong>Zen</strong> Tables<br />
8.8 Column Filters<br />
A <strong>Zen</strong> table can create a “filter” to place above the header for any column. A filter is a simple box<br />
with an input field where a user can enter one or more search criteria. When the user submits these<br />
changes, the query associated with the is re-executed using the new criteria. <strong>Zen</strong> updates<br />
the table and nothing else on the page changes.<br />
Filtering works only if the is using an automatically generated SQL statement or an<br />
OnCreateResultSet callback, and the callback generates the appropriate WHERE logic to implement<br />
the data filtering. When your table uses a generated SQL query, your page class can gather what the<br />
user enters; format it appropriately into the %ZEN.Component.tablePane properties groupByClause,<br />
orderByClause, and whereClause; then re-execute the table query.<br />
Important:<br />
If you do not provide a colName value with the element that specifies the<br />
filter, <strong>Zen</strong> does not create the filter.<br />
The element offers the following attributes for filters.<br />
Attribute<br />
filterEnum<br />
Description<br />
If filterType is "enum", filterEnum defines the set of enumerated values<br />
used by the filter as a comma-delimited list. For example:<br />
"red,green,blue"<br />
The enumerated values will be displayed within a combo box. The<br />
names supplied in the filterEnum list will appear as selections in the<br />
combo box unless filterEnumDisplay is defined.<br />
filterEnumDisplay<br />
filterLabel<br />
If filterType is "enum", and if filterEnumDisplay provides a commadelimited<br />
list of values, the combo box displays these values in place<br />
of the corresponding filterEnum values.<br />
The filterEnumDisplay attribute has its ZENLOCALIZE datatype<br />
parameter set to 1 (true). This means it is easy to localize its text into<br />
other languages. See <strong>Zen</strong> Localization.<br />
If specified, this is a label to display for the filter control. If there is a<br />
multipart filter control (such as a filterType of "range"), then<br />
filterLabel is assumed to contain a comma-delimited list of labels.<br />
90 <strong>Using</strong> <strong>Zen</strong>
Column Filters<br />
Attribute<br />
filterOp<br />
filterQuery<br />
filterTitle<br />
filterType<br />
filterValue<br />
Description<br />
If this column has a filter, filterOp is the name of the SQL operator<br />
that should be used in conjunction with the filter. Supported values<br />
are: "", "%STARTSWITH", "=", ">=", "", "
<strong>Zen</strong> Tables<br />
The following sample generates an SQL statement that displays the Name and Department<br />
of employees:<br />
<br />
<br />
<br />
<br />
<br />
This example uses the filterType attribute to specify that the Name column should display<br />
a column filter (“text” indicates that this filter displays a box in which the user may type text). If the<br />
user enters a value in the box (such as “A”) and presses Enter, the table will be updated to only show<br />
rows where the Name column starts with “A”. (If the does not specify a filterOp value, the<br />
default matching operation is %STARTSWITH.)<br />
For the Department column the example displays a more sophisticated filter: a combo box showing 3<br />
possible values. To do this, it sets the filterType to “enum” and sets filterEnum to a commadelimited<br />
list of possible values. It also specifies that an exact match is required, by setting the filterOp<br />
value to "=".<br />
A has filters active and enabled by default. You do not need to supply any <br />
attributes to enable filtering. However, should you want to override the default settings, <br />
offers the following attributes that control filtering for the table as a whole, not just for individual<br />
columns.<br />
Attribute<br />
autoExecute<br />
filtersDisabled<br />
Description<br />
If true, this attribute causes the table query to be executed whenever<br />
a filter value is changed. autoExecute is "true" by default. When false,<br />
a page must explicitly cause the to run its query by<br />
calling its executeQuery method.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
If true, disable column filters (if any). When true, column filters are<br />
still displayed, but they are inactive. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
92 <strong>Using</strong> <strong>Zen</strong>
Column Links<br />
Attribute<br />
headerLayout<br />
Description<br />
Controls how to display the table header when column filters are used.<br />
Possible values are:<br />
• "filtersOnTop" — Display column filters above column headers.<br />
This is the default.<br />
• "headersOnTop" — Display column headers above column filters.<br />
showFilters<br />
If true, display column filters (if any) above the column headers. If<br />
false, do not display filters. The default is true.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
8.9 Column Links<br />
Columns within a <strong>Zen</strong> table can display links, such as a link that takes the user to another page to edit<br />
the details of the object displayed within the current row. This link can either be displayed within a<br />
column that contains a data value (in this case, the data value is displayed as a link), or as an extra<br />
column in the table that contains the link.<br />
The element offers the following attributes for links.<br />
Attribute<br />
link<br />
Description<br />
If specified, this column is displayed as a link using the value of the link<br />
property as a URI. If you want to invoke a client-side JavaScript method<br />
in the link, start the URI with javascript: as in:<br />
link="javascript:zenPage.myMethod();"<br />
linkCaption<br />
If this column has a link defined and does not display a data value, the<br />
linkCaption specifies the text to use as the caption for the link.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
<strong>Using</strong> <strong>Zen</strong> 93
<strong>Zen</strong> Tables<br />
Attribute<br />
linkConfirm<br />
Description<br />
If specified and this column has a link defined, the linkConfirm text is<br />
displayed as a confirmation message before the link is executed.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
For example:<br />
<br />
<br />
<br />
<br />
<br />
This example does the following:<br />
1. The sql value specifies that this table will display information about the top 100 items<br />
in the MyApp.Inventory table ordered by price.<br />
2. The needs the value of the “ID” column (as part of the links) but there is no need to<br />
display this value. Therefore, the hidden value is true.<br />
3. The needs the “Item” column to contain a link to a page that displays information<br />
about a specific item. Therefore, the link value defines this link. The linkTitle<br />
value defines a tooltip message that will be displayed when the user moves the mouse over this<br />
link.<br />
4. The defines an extra column (with no data displayed within it) that contains an “Add<br />
to cart” link. This link invokes a client-side addToCart method when the user clicks on it. Specifying<br />
a value for the linkConfirm value indicates that the user will have a chance to<br />
confirm this choice before the link is executed.<br />
The two links used within this example make use of the <strong>Zen</strong> expression syntax to include the value of<br />
row-specific data within the link. See <strong>Zen</strong> Runtime Expressions. The following expression refers to<br />
the ID column within the current row of the table: #(%query.ID)#<br />
94 <strong>Using</strong> <strong>Zen</strong>
User Interactions<br />
8.10 User Interactions<br />
<strong>Zen</strong> tables provide built-in mechanisms to support basic user interactions such as navigating pages,<br />
sorting columns, and selecting rows in a table.<br />
8.10.1 Navigation Buttons<br />
The component automatically displays a set of buttons for moving through the pages<br />
of a . The has identical syntax, but displays extra buttons to help<br />
users navigate large, multipage tables.<br />
To use either component, place it anywhere on the same page as a and set its tablePaneId<br />
attribute value to match the id value from the . For example:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
8.10.2 Navigation Keys<br />
The can specify event handling for user key clicks as follows.<br />
Property<br />
onkeypress<br />
Description<br />
If useKeys is true, this client-side JavaScript expression runs<br />
whenever the user presses a key (Up, Down, Page Up, Page Down,<br />
Home, End) while focus is in the table.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the<br />
JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
<strong>Using</strong> <strong>Zen</strong> 95
<strong>Zen</strong> Tables<br />
Property<br />
useKeys<br />
Description<br />
If true, this tablePane captures user keystrokes (Up, Down, Page<br />
Up, Page Down, Home, End) and uses them for simple table navigation.<br />
The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
8.10.3 Sorting Tables<br />
The user can click on a column header and cause this action to sort the table according to the data in<br />
that column: First click, ascending order; second click, descending order; and so on. You can set an<br />
initial value for sortOrder when you add the to the page, but generally it takes its values<br />
at runtime, due to user interactions.<br />
Property<br />
sortOrder<br />
Description<br />
When the user clicks on a column header, <strong>Zen</strong> re-executes the table query<br />
(unless the table is in snapshot mode) and sorts the table based on the<br />
values in that column and the order specified by the sortOrder value.<br />
sortOrder toggles between its possible values "asc" (sort in ascending<br />
order) and "desc" (sort in descending order) as the user repeats clicks in<br />
that column header.<br />
sortOrder does not affect the query itself (it does not interact with the query<br />
ORDER BY setting). sortOrder simply controls the order in which the table<br />
displays the resultset returned by the query.<br />
The sortOrder value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
8.10.4 Selecting Rows and Columns<br />
The user can select rows or columns within a <strong>Zen</strong> table by clicking on them. <strong>Zen</strong> indicates the current<br />
row visually and notifies the application of the event by triggering the event handler provided by the<br />
onselectrow attribute.<br />
%ZEN.Component.tablePane supports a number of properties for row and column selection. Many of<br />
these properties can be set as attributes, but some of them can only take their values at<br />
runtime in response to user actions.<br />
96 <strong>Using</strong> <strong>Zen</strong>
User Interactions<br />
Property<br />
currColumn<br />
multiSelect<br />
ondblclick<br />
Description<br />
The colName of the column most recently selected by the user.<br />
You may allow user actions to provide a value for this property, or<br />
you can set it. The currColumn value can be a literal string, or it<br />
can contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
If true, the user can select multiple rows within the table. <strong>Zen</strong><br />
displays an extra column, containing check boxes, to indicate which<br />
rows are selected. The default is false. multiSelect and rowSelect<br />
can be true or false independently of each other.<br />
Client-side JavaScript expression that runs whenever the user<br />
double-clicks on a row within this table. Generally this expression<br />
invokes a client-side JavaScript method defined in the page class.<br />
This method becomes the “ondblclick event handler” for the<br />
.<br />
When providing a value for an event handler attribute such as<br />
ondblclick, use double quotes to enclose the value and single quotes<br />
(if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
onheaderClick<br />
onselectrow<br />
onmultiselect<br />
rowSelect<br />
selectedIndex<br />
Client-side JavaScript expression that runs whenever the user clicks<br />
on a column header within this table. <strong>Zen</strong> stores the name of this<br />
column in the currColumn property.<br />
If rowSelect is true, this is the client-side JavaScript expression that<br />
runs whenever the user selects a new row within this table. This<br />
will only happen if showRowSelector is true.<br />
If multiSelect is true, this is the client-side JavaScript expression<br />
that runs whenever the user changes the set of multiply-selected<br />
rows within this table.<br />
If true, the user can select a row within the table (one row at a time).<br />
The default is true. multiSelect and rowSelect can be true or false<br />
independently of each other.<br />
The (0–based) index number of the currently selected row. This<br />
value is relevant only if the showRowSelector property is true. For<br />
snapshot tables, this is row number within the current page.<br />
<strong>Using</strong> <strong>Zen</strong> 97
<strong>Zen</strong> Tables<br />
Property<br />
selectedRows<br />
showRowSelector<br />
value<br />
Description<br />
Read-only. For tables in which multiSelect is true, this string<br />
indicates which rows are currently selected.The string is in the form<br />
"1,,,1,,,1" with "1" indicating a selected row.<br />
If true, and if row(s) are selected, the table displays an extra column<br />
that indicates the selected row(s). The default is true.<br />
Read-only. This is the logical value used to determine which is the<br />
currently selected row. value works with valueColumn. The value<br />
may be empty ("").<br />
Do not access this value directly; use getProperty('value')<br />
instead.<br />
valueColumn<br />
A can have a logical value defined. Each time the<br />
table is refreshed, in each row <strong>Zen</strong> tests this logical value against<br />
the actual value that appears in the valueColumn in that row. <strong>Zen</strong><br />
selects any row(s) that contain value in valueColumn. This implies<br />
the following:<br />
• You can preset the value of a and the row(s) that<br />
match will be selected when the table is first displayed.<br />
• The current selection is preserved when you sort the rows in a<br />
table.<br />
8.11 Table Refresh<br />
When you refresh a table, only the table refreshes. It is not necessary for the entire <strong>Zen</strong> page to refresh<br />
itself in order to refresh a table.<br />
Typically, <strong>Zen</strong> refreshes the visible contents of the table automatically as needed. When you work<br />
with tables programmatically, you can also explicitly refresh table contents. The techniques are as<br />
follows:<br />
• Set the refreshRequired property of the %ZEN.Component.tablePane to true (1) from a server-side<br />
method. This forces the tablePane to re-execute its query.<br />
• Call the executeQuery method of the %ZEN.Component.tablePane. This causes the data query<br />
to be re-executed and updates the visible contents of the table to reflect the current values of<br />
tablePane properties.<br />
98 <strong>Using</strong> <strong>Zen</strong>
Table Touchups<br />
8.12 Table Touchups<br />
Any time you set an attribute value for in XData Contents, the corresponding property<br />
in the tablePane object automatically acquires this value. This might be just enough programming for<br />
your purposes. Nevetheless, %ZEN.Component.tablePane offers many more opportunities for programmatic<br />
interaction on the client or server sides, for example:<br />
• Touching up values set in XData Contents, just prior to display, by setting tablePane properties<br />
in the %OnAfterCreatePage callback of the page class.<br />
• Examining read-only properties of %ZEN.Component.tablePane such as lastUpdate and rowCount<br />
to determine the current state of the table. Note that rowCount is a string, and not numeric, as its<br />
value might be "" or "100+". Any number of rows greater than 100 is represented as "100+".<br />
• Resetting values of certain tablePane properties and then refreshing the table.<br />
<strong>Using</strong> <strong>Zen</strong> 99
9<br />
<strong>Zen</strong> and SVG<br />
Scalable Vector Graphics (SVG) is a language that allows you to describe two-dimensional vector<br />
graphics in XML format. The SVG language specification is available on the Web site<br />
www.w3.org/TR/SVG/.<br />
<strong>Zen</strong> uses SVG to display high-performance, data-driven charts and meters. You can use the built-in<br />
SVG components to define eye-catching corporate dashboards that update their statistics in real time.<br />
You can also define your own SVG components. An SVG component is any component that inherits<br />
from %ZEN.SVGComponent.svgComponent. These components render dynamic SVG images that<br />
change their appearance in response to data values.<br />
Note:<br />
If you want to display a static SVG file on the <strong>Zen</strong> page, use . If you want to use a<br />
static SVG file as the image for a button control, use . The conventions described<br />
in the following topics apply to dynamic SVG components only.<br />
This chapter describes how to place SVG components on the <strong>Zen</strong> page. Topics include:<br />
• Layout<br />
• Style<br />
• Meters<br />
• Charts<br />
• The radial navigator component<br />
• Drawing your own SVG<br />
<strong>Using</strong> <strong>Zen</strong> 101
<strong>Zen</strong> and SVG<br />
9.1 SVG Component Layout<br />
The following components allow you to place SVG components on a <strong>Zen</strong> page:<br />
• <br />
• <br />
• <br />
9.1.1 <br />
is a <strong>Zen</strong> component that creates a rectangular frame on the <strong>Zen</strong> page, into which you can<br />
place SVG components. Only SVG components may appear inside this frame. Any dynamic SVG<br />
component, such as a meter or chart, requires an to contain it.<br />
inherits from %ZEN.Component.component. This gives the usual component<br />
style attributes: height, width, label, etc. See <strong>Zen</strong> Style. This also allows to be placed<br />
within a (or contained within an or ) just like any other <strong>Zen</strong> component.<br />
See <strong>Zen</strong> Layout.<br />
The following figure shows a mix of <strong>Zen</strong> components and SVG components on a page. This is similar<br />
to the output provided by the sample class ZENDemo.Dashboard in the SAMPLES namespace.<br />
102 <strong>Using</strong> <strong>Zen</strong>
SVG Component Layout<br />
The following XData Contents block contains the components that produced the above figure. These<br />
are a mix of:<br />
• <strong>Zen</strong> components (,,, , , )<br />
• SVG components (, , , , ,<br />
)<br />
<strong>Using</strong> <strong>Zen</strong> 103
<strong>Zen</strong> and SVG<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
This is an example of a <strong>Zen</strong> Dashboard:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
An element may contain as many nested and elements as are<br />
required to achieve the desired layout. has the following attributes.<br />
104 <strong>Using</strong> <strong>Zen</strong>
SVG Component Layout<br />
Attribute<br />
<strong>Zen</strong> component<br />
attributes<br />
backgroundStyle<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong><br />
component. The previous chapter, <strong>Zen</strong> Style, describes them.<br />
SVG CSS style definition (Styles within SVG are CSS compliant, but<br />
there is a different set of styles available.) Specifies the background<br />
style for the frame.This style must include a fill value, or mouse events<br />
within this frame will not work correctly. The default backgroundStyle<br />
is:<br />
"fill: white;"<br />
disabled<br />
dragCanvas<br />
editMode<br />
If true, this frame and its children are disabled. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
If true, the user can use the pointing device (mouse) to drag the canvas<br />
of this frame. This updates he values of the offsetX and offsetY<br />
attributes and moves the shapes on the canvas. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Edit mode for this frame. Possible values are:<br />
• "none" — The user cannot edit the contents of this frame. This is<br />
the default.<br />
• "select" — The user can click on an SVG component to select it.<br />
• "drag" — The user can click on an SVG component, hold down<br />
the mouse button, and drag the SVG component to a new position.<br />
frameStyle<br />
CSS style definition that applies to this frame. For example, to produce<br />
the recessed, beveled border shown in the illustration above, you<br />
would use:<br />
frameStyle="border-style: inset;"<br />
gridX<br />
If snapToGrid is true, gridX defines the HTML width of each cell in the<br />
sizing grid. The default is 25.<br />
<strong>Using</strong> <strong>Zen</strong> 105
<strong>Zen</strong> and SVG<br />
Attribute<br />
gridY<br />
layout<br />
offsetX<br />
offsetY<br />
ondragCanvas<br />
Description<br />
If snapToGrid is true, gridY defines the HTML height of each cell in<br />
the sizing grid. The default is 25.<br />
Specifies how the SVG components within this frame should be laid<br />
out. Possible values are "horizontal" and "vertical".<br />
If layout is set to "none" or the empty value "", components may be<br />
placed using specific coordinates x and y. See the x and y attributes<br />
in the topic SVG Component Style.<br />
Offset, along the x-axis, of the coordinates of this frame from its upper,<br />
left-hand corner. The default is 0.<br />
Offset, along the y-axis, of the coordinates of this frame from its upper,<br />
left-hand corner. The default is 0.<br />
Client-side JavaScript expression that runs each time the user drags<br />
the background canvas using a pointing device. Generally this<br />
expression invokes a client-side JavaScript method defined in the<br />
page class. A boolean variable, done, is passed to this event handler<br />
to indicate if the operation is complete.<br />
As with all event handler expressions including onmouseWheel,<br />
onmoveItem, etc:<br />
• When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the<br />
JavaScript expression. For example:<br />
<br />
• The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
onmouseWheel<br />
onmoveItem<br />
Client-side JavaScript expression that runs whenever the user moves<br />
the mouse wheel over the background rectangle of this frame. Currently<br />
only available in FireFox.<br />
Client-side JavaScript expression that runs whenever this frame is in<br />
drag mode and the user moves one or more selected items. Refer to<br />
the selectedItems property for the list of items. A boolean variable,<br />
done, is passed to this event handler to indicate if the operation is<br />
complete.<br />
106 <strong>Using</strong> <strong>Zen</strong>
SVG Component Layout<br />
Attribute<br />
onresizeItem<br />
onselectItem<br />
onzoom<br />
snapToGrid<br />
svgAutoSize<br />
svgHeight<br />
Description<br />
Client-side JavaScript expression that runs whenever this frame is in<br />
drag mode and the user resizes one or more selected items. Refer to<br />
the selectedItems property for the list of items. A boolean variable,<br />
done, is passed to this event handler to indicate if the operation is<br />
complete.<br />
Client-side JavaScript expression that runs whenever the user changes<br />
the number of selected items in this frame (by selecting or unselecting<br />
an item). A variable, item, is passed to this event handler and refers<br />
to the item most recently selected or unselected.<br />
Client-side JavaScript expression that runs whenever the user changes<br />
the zoom level for this frame.<br />
If true, all mouse operations (sizing and dragging) are constrained to<br />
occur on the grid defined by gridX and gridY. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Controls the size of the SVG drawing canvas within the frame. If<br />
dragCanvas is true, the svgAutoSize property is ignored. Otherwise,<br />
if svgAutoSize is true, <strong>Zen</strong> calculates (and updates) the canvas size<br />
automatically based on the frame contents, with the minimum canvas<br />
size being svgWidth by svgHeight. If svgAutoSize is false, the canvas<br />
size is determined by the values of svgWidth and svgHeight.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Controls the size of the SVG drawing canvas within the frame.<br />
svgHeight gives the canvas height (using any valid SVG measurement<br />
units). If not specified, the default svgHeight is 100% of the height of<br />
the . If height is also not specified, the default height (and<br />
svgHeight) is 100.<br />
<strong>Using</strong> <strong>Zen</strong> 107
<strong>Zen</strong> and SVG<br />
Attribute<br />
svgPage<br />
Description<br />
(Optional) Identifies a specialized CSP page that serves SVG content,<br />
defining styles and colors for SVG components in the frame. If provided,<br />
the svgPage value must be the name of a class that extends<br />
%ZEN.SVGComponent.svgPage. Otherwise, the frame uses the base<br />
class %ZEN.SVGComponent.svgPage by default.<br />
When you provide a value for the svgPage attribute, you can also<br />
include elements within the . <strong>Zen</strong> passes<br />
the value strings from these elements to the svgPage<br />
class as URI parameters. For example:<br />
<br />
The value supplied for a can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
svgWidth<br />
zoom<br />
zoomLevels<br />
Controls the size of the SVG drawing canvas within the frame.<br />
svgWidth gives the canvas width (using any valid SVG measurement<br />
units). If not specified, the default svgWidth is 100% of the width of<br />
the . If width is also not specified, the default width (and<br />
svgWidth) is 300.<br />
Decimal value, at least 1.0 (the decimal portion of the number may<br />
be omitted). This value indicates the zoom factor for the frame. 100<br />
means no zoom; this is the default. Values larger than 100 increase<br />
image size, while smaller values decrease it.<br />
Comma-separated list of suggested zoom values. The default is:<br />
"10,25,50,75,100,125,150,175,200,300,400,500"<br />
zoomWithWheel<br />
If true, this frame automatically zooms in and out in response to mouse<br />
wheel events. The default is false. Currently only available in FireFox.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Important:<br />
It is not possible for to contain any component that inherits from<br />
%ZEN.Component.component, such as , , , ,<br />
, , , or any of the other <strong>Zen</strong> components discussed in this<br />
book. can contain SVG components only.<br />
108 <strong>Using</strong> <strong>Zen</strong>
SVG Component Layout<br />
9.1.2 <br />
is a special container designed to contain and lay out SVG components within .<br />
is not a <strong>Zen</strong> component (%ZEN.Component.component), nor is it a <strong>Zen</strong> group component<br />
(%ZEN.Component.group). is an <strong>Zen</strong> SVG component<br />
(%ZEN.SVGComponent.svgComponent) with the ability to contain other <strong>Zen</strong> SVG components.<br />
has the following attributes.<br />
Attribute<br />
SVG<br />
component<br />
attributes<br />
disabled<br />
layout<br />
Description<br />
has the same general-purpose attributes as any SVG<br />
component.<br />
If true, this group and its children are disabled (hidden).The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
Specifies how the SVG components within this group should be laid out.<br />
Possible values are "horizontal" and "vertical".<br />
If layout is set to "none" or the empty value "", components may be placed<br />
using specific coordinates x and y. See the x and y attributes in the topic<br />
SVG Component Style.<br />
9.1.3 <br />
The element is useful within containers. Use with a width value<br />
to inject additional space in a horizontal , or height for additional space within a vertical<br />
. supports all of the SVG component attributes.<br />
9.1.4 <br />
The <strong>Zen</strong> element draws a simple rectangle. This is not the same as the element defined<br />
by the SVG language specification. <strong>Zen</strong> is a built-in <strong>Zen</strong> SVG component that you can place<br />
within an or .<br />
The <strong>Zen</strong> element takes up space within an or , but in a different way<br />
than . The conceptual difference between and is that may<br />
have visible style attributes, such as a fill color.<br />
<strong>Using</strong> <strong>Zen</strong> 109
<strong>Zen</strong> and SVG<br />
Attribute<br />
SVG<br />
component<br />
attributes<br />
rx<br />
style<br />
Description<br />
has the same general-purpose attributes as any SVG component.<br />
Radius of curve for the corners (using any valid SVG measurement units).<br />
SVG CSS style definition. (Styles within SVG are CSS compliant, but there<br />
is a different set of styles available.)<br />
9.2 SVG Component Attributes<br />
All SVG components have the following style attributes. These are entirely distinct from the attributes<br />
supported by ordinary <strong>Zen</strong> components.<br />
SVG Component Attributes<br />
Attribute<br />
height<br />
hidden<br />
onclick<br />
Description<br />
Height of this component (using any valid SVG measurement<br />
units). The exact effect of setting this value depends on the<br />
component. In the case of built-in SVG components, the effect is<br />
usually straightforward. A height value larger than the height of<br />
the containing will cause the SVG component to<br />
appear cropped by the frame.<br />
If true, this component is disabled (hidden). The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
Client-side JavaScript expression that runs each time the user<br />
clicks the mouse on this shape. Generally this expression invokes<br />
a client-side JavaScript method defined in the page class.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the<br />
JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
110 <strong>Using</strong> <strong>Zen</strong>
SVG Component Attributes<br />
Attribute<br />
name<br />
id<br />
preserveAspectRatio<br />
viewBoxHeight<br />
viewBoxWidth<br />
width<br />
x<br />
y<br />
Description<br />
Specifies a name for the component.<br />
Name that can be used to select the SVG component so that its<br />
attributes can be updated. For example, displays that use meters<br />
might periodically update the value that the meter represents.<br />
By default, <strong>Zen</strong> preserves the aspect ratio (height relative to width)<br />
for any SVG component when you change its size. If you set<br />
preserveAspectRatio to "none", <strong>Zen</strong> does not preserve the aspect<br />
ratio and allows your height and width changes to operate<br />
independently of each other.<br />
Height of the view box for this component (using any valid SVG<br />
measurement units). If a viewBoxHeight attribute is provided, its<br />
value is used as the height of the view box. Otherwise, the height<br />
value for the component is used.<br />
Width of the view box for this component (using any valid SVG<br />
measurement units). If a viewBoxWidth attribute is provided, its<br />
value is used as the width of the view box. Otherwise, the width<br />
value for the component is used.<br />
Width of this component (using any valid SVG measurement units).<br />
The exact effect of setting this value depends on the component.<br />
In the case of built-in SVG components, the effect is usually<br />
straightforward. A width value larger than the width of the containing<br />
will cause the SVG component to appear cropped<br />
by the frame.<br />
x position of this component (using any valid SVG measurement<br />
units). The actual position of the component may depend on the<br />
layout of its enclosing . If the has vertical<br />
or horizontal layout, this x coordinate is ignored. However, if<br />
layout="" this x coordinate takes effect. x is a positive value<br />
relative to an origin of (0,0) at the top left corner of the .<br />
y position of this component.<br />
<strong>Using</strong> <strong>Zen</strong> 111
<strong>Zen</strong> and SVG<br />
9.3 Meters<br />
A meter is an SVG component that displays a graphical representation of a single numeric value. Each<br />
meter is a class derived from %ZEN.SVGComponent.meter that generates the SVG required to display<br />
itself.<br />
<strong>Zen</strong> provides several built-in meters. To place one of them on the <strong>Zen</strong> page, provide the corresponding<br />
meter element within an or :<br />
• <br />
• <br />
• <br />
• <br />
• <br />
• <br />
• To create your own style of meter, see Custom Components<br />
This topic describes how to supply a meter with a value, lists the attributes that all meters share in<br />
common, then describes the unique attributes for each type of meter listed above.<br />
9.3.1 Providing Data for Meters<br />
Your code can dynamically update the value displayed by a meter in one of two ways:<br />
• From a JavaScript method in the page class, set the meter’s value attribute using the meter class<br />
methods getComponentById and setValue as follows:<br />
this.getComponentById("myMeterID").setValue(myNewValue);<br />
Where myMeterID matches the id attribute value for the meter, and myNewValue is a variable that<br />
contains a single, numeric value.<br />
• Associate the meter with a data controller, as described in the chapter Model View Controller.<br />
For example, if your XData Contents block contains an reference that looks like<br />
this:<br />
<br />
And if the referenced modelClass myPackage.MyModel contains a property called Automobiles,<br />
then your XData Contents block can also contain a meter definition that looks like this:<br />
112 <strong>Using</strong> <strong>Zen</strong>
Meters<br />
<br />
This technique works when the meter’s controllerId value matches the id value,<br />
and the meter’s dataBinding value matches the name of a property defined in the <br />
modelClass.<br />
9.3.2 Meter Attributes<br />
All meters have the following attributes, which define their style and behavior.<br />
Meter Component Attributes<br />
Attribute<br />
SVG<br />
component<br />
attributes<br />
animate<br />
controllerId<br />
dataBinding<br />
label<br />
Description<br />
All meters have the same general-purpose attributes as any SVG<br />
component.<br />
Some of the built-in <strong>Zen</strong> meters provide animation. For example, if the<br />
meter uses a needle to indicate a value, animation causes the needle<br />
to “swing” from the previous value to the new value. If a meter supported<br />
animation, this attribute controls whether animation is on (true)<br />
or off (false). The default is "true".<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Identifies the data controller that provides the data for this meter. The<br />
controllerId value must match the id value provided for that<br />
component. See Model View Controller.<br />
If this meter is associated with a data controller, this attribute identifies<br />
the specific property within the modelClass that<br />
provides the value for this control. See Model View Controller.<br />
A text label for the meter.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
<strong>Using</strong> <strong>Zen</strong> 113
<strong>Zen</strong> and SVG<br />
Attribute<br />
labelStyle<br />
onnotifyView<br />
Description<br />
SVG CSS style definition. (Styles within SVG are CSS compliant, but<br />
there is a different set of styles available.) When <strong>Zen</strong> lays out this<br />
meter, it applies this style to the label text.<br />
This attribute applies if the meter is associated with a data controller.<br />
The onnotifyView value is a client-side JavaScript expression that is<br />
executed each time the data controller connected to this meter raises<br />
an event. Generally this expression invokes a client-side JavaScript<br />
method defined in the page class. This method becomes the<br />
“onnotifyView event handler” for the meter. See Model View Controller.<br />
When providing a value for this attribute, use double quotes to enclose<br />
the value and single quotes (if needed) within the JavaScript expression.<br />
For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
rangeLower<br />
rangeUpper<br />
scaleFactor<br />
thresholdLower<br />
thresholdUpper<br />
Integer or decimal value that defines the low end of the range for this<br />
meter. The default is 0.<br />
Integer or decimal value that defines the high end of the range for this<br />
meter. The default is 100.<br />
Integer or decimal factor used to scale the values provided to this<br />
meter. <strong>Zen</strong> scales the incoming values before comparing them with<br />
rangeLower, rangeUpper, and so on. The default is 1 (no scaling).<br />
Integer or decimal value that defines a threshold for meter behavior.<br />
The meter will do something when the meter value falls below this<br />
value. Typically, the thresholdLower value is greater than rangeLower<br />
and serves as a warning that the meter value is approaching<br />
rangeLower. The default is 0.<br />
Integer or decimal value that defines a threshold for meter behavior.<br />
The meter will do something when the meter value rises above this<br />
value. Typically, the thresholdUpper value is less than rangeUpper<br />
and serves as a warning that the meter value is approaching<br />
rangeUpper. The default is 90.<br />
114 <strong>Using</strong> <strong>Zen</strong>
Meters<br />
Attribute<br />
value<br />
Description<br />
The current integer or decimal value of the meter (actually stored as<br />
a string). Although you can set this value while placing the meter on<br />
the page, generally you do not do this. Instead, you use<br />
getComponentById and setValue, or associate the meter with a<br />
%ZEN.Auxiliary.dataController, as described in the paragraph prior to this<br />
table.<br />
9.3.3 <br />
The fuel gauge is a narrow, vertical gauge with a needle that moves from left to right to indicate a<br />
value within a specific range. The gauge distributes marks or “ticks” proportionally across its range.<br />
The meter attributes rangeLower and rangeUpper define the range, with the rangeLower value at left<br />
and the rangeUpper value at right.<br />
The fuel gauge displays its current value in a text box at the center of the gauge.<br />
You may specify warning lights to appear at the upper left or right of the gauge, above the ticks. These<br />
lights change color as the needle approaches them. The light at right changes color when the meter<br />
value rises to or above thresholdUpper. The light at left changes color when the meter value falls to<br />
or below thresholdLower.<br />
There is always a thresholdLower warning light with a default setting of 0. You must specify a<br />
thresholdUpper value if you want a warning light to appear at the top of the range as well.<br />
<strong>Using</strong> <strong>Zen</strong> 115
<strong>Zen</strong> and SVG<br />
Attribute<br />
Meter attributes<br />
highLampColor<br />
Description<br />
has the same general-purpose attributes as any meter.<br />
String containing a CSS color value. This is the color that the displays when its value exceeds thresholdUpper. The default<br />
is a pre-defined <strong>Zen</strong> color that produces a “glowing” effect through<br />
shading:<br />
url(#glow-red)<br />
Several glow colors are defined in the class<br />
%ZEN.SVGComponent.svgPage. always references this<br />
class, or some subclass of it, through its svgPage attribute, so these<br />
colors are always available to any SVG component in the frame.<br />
logo<br />
lowLampColor<br />
Text label for the face of the meter (similar to "<strong>Zen</strong>" in the illustration<br />
above).<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
String containing a CSS color value. This is the color that the displays when its value exceeds thresholdUpper. The default<br />
is a pre-defined <strong>Zen</strong> color:<br />
url(#glow-red)<br />
9.3.4 <br />
The indicator lamp is a rectangular bar that changes its fill pattern depending on the meter value.<br />
Essentially there are three possible states: above thresholdUpper, below thresholdLower, or between<br />
the two values.<br />
If the meter has a label attribute, this text appears in the middle of the indicator lamp with the style<br />
defined by labelStyle.<br />
116 <strong>Using</strong> <strong>Zen</strong>
Meters<br />
Attribute<br />
Meter<br />
attributes<br />
highStyle<br />
Description<br />
has the same general-purpose attributes as any meter,<br />
plus the attributes described in this table.<br />
SVG CSS style definition. Specifies the fill style for the <br />
when its value exceeds thresholdUpper. The highStyle must include a fill<br />
value, or mouse events within the shape will not work correctly.The default<br />
highStyle uses a pre-defined <strong>Zen</strong> color that produces a “glowing” effect<br />
through shading:<br />
"fill: url(#glow-green);"<br />
Several glow colors are defined in the class %ZEN.SVGComponent.svgPage.<br />
always references this class, or some subclass of it, through<br />
its svgPage attribute, so these colors are always available to any SVG<br />
component in the frame.<br />
lowStyle<br />
SVG CSS style definition. Specifies the fill style for the <br />
when its value falls below thresholdLower. The lowStyle must include a<br />
fill value, or mouse events within the shape will not work correctly. The<br />
default lowStyle uses a pre-defined <strong>Zen</strong> color:<br />
"fill: url(#glow-red);"<br />
normalStyle<br />
SVG CSS style definition. Specifies the fill style for the <br />
when its value is between thresholdLower and thresholdUpper. The<br />
normalStyle must include a fill value, or mouse events within the shape<br />
will not work correctly. The default normalStyle uses a pre-defined <strong>Zen</strong><br />
color:<br />
"fill: url(#glow-blue);"<br />
9.3.5 <br />
<strong>Using</strong> <strong>Zen</strong> 117
<strong>Zen</strong> and SVG<br />
The light bar provides a stack of lamps arranged in a vertical bar. The light bar is similar to the traffic<br />
light, but its larger number of lamps provide a sense of movement from one end of the scale to the<br />
other.<br />
The light bar is intended to appear “off” when the value is low, and fully lit when the value is high.<br />
The color of the bar shades from green (at the bottom of the scale) to yellow and red (at the top of the<br />
scale), implying that you should stop and address a problem when the value is high.<br />
Sometimes a low number indicates a condition that requires attention. If this is the case you can reverse<br />
the sense of a light bar by inverting the values for rangeLower and rangeUpper. Then the fully lit lamp<br />
indicates low values, and the “off” lamp indicates high values.<br />
Warning lights appear at the top or bottom left of the light bar. The top light changes color when the<br />
meter value rises to or above thresholdUpper. The bottom light changes color when the meter value<br />
falls to or below thresholdLower. You can specify what color you want to use for these lights. You<br />
cannot change the colors for the light bar itself (green, yellow, red).<br />
Note:<br />
When you reverse rangeLower and rangeUpper, do not at the same time reverse<br />
thresholdUpper and thresholdLower.<br />
Attribute<br />
Meter attributes<br />
highLampColor<br />
Description<br />
has the same general-purpose attributes as any meter, plus<br />
the attributes described in this table.<br />
String containing a CSS color value.This is the color that the <br />
displays when its value exceeds thresholdUpper. The default is a predefined<br />
<strong>Zen</strong> color that produces a “glowing” effect through shading:<br />
url(#glow-red)<br />
Several glow colors are defined in the class<br />
%ZEN.SVGComponent.svgPage. always references this<br />
class, or some subclass of it, through its svgPage attribute, so these<br />
colors are always available to any SVG component in the frame.<br />
lowLampColor<br />
String containing a CSS color value.This is the color that the <br />
displays when its value falls below thresholdLower. The default is a<br />
pre-defined <strong>Zen</strong> color: url(#glow-red)<br />
118 <strong>Using</strong> <strong>Zen</strong>
Meters<br />
9.3.6 <br />
The smiley is the familiar yellow circle with two eyes and a smile. The mouth line changes depending<br />
on the meter value. The mouth forms a smile when the meter value is near rangeUpper. The mouth is<br />
a horizontal line at the midpoint between rangeLower and rangeUpper. The mouth forms a frown<br />
when the meter value is near rangeLower. This is useful when a large number indicates a positive<br />
condition, and a small number indicates a negative condition.<br />
You can reverse the sense of a smiley by inverting the values for rangeLower and rangeUpper. Then<br />
the smile occurs at low values, and the frown at high values.<br />
has no unique attributes. It has the usual meter attributes. It ignores any threshold values.<br />
9.3.7 <br />
The speedometer is a circular gauge with a needle that moves from lower left, all the way around to<br />
lower right, to indicate a value within a specific range. The gauge distributes marks or “ticks” proportionally<br />
across its range. The meter attributes rangeLower and rangeUpper define the range, with the<br />
rangeLower value at left and the rangeUpper value at right.<br />
By default, the speedometer displays its current value in a text box at the center of the gauge. However,<br />
you can specify that this text box actually contains a different value that you control separately. Use<br />
the independentOdometer and odometerValue attributes for this.<br />
You may specify warning lights to appear at the lower left or lower right of the gauge. These lights<br />
change color as the needle approaches them. The light at right changes color when the meter value<br />
<strong>Using</strong> <strong>Zen</strong> 119
<strong>Zen</strong> and SVG<br />
rises to or above thresholdUpper. The light at left changes color when the meter value falls to or below<br />
thresholdLower.<br />
Attribute<br />
Meter attributes<br />
highLampColor<br />
Description<br />
has the same general-purpose attributes as<br />
any meter, plus the attributes described in this table.<br />
String containing a CSS color value. This is the color that the<br />
displays when its value exceeds<br />
thresholdUpper. The default is a pre-defined <strong>Zen</strong> color that<br />
produces a “glowing” effect through shading:<br />
url(#glow-red)<br />
Several glow colors are defined in the class<br />
%ZEN.SVGComponent.svgPage. always references<br />
this class, or some subclass of it, through its svgPage attribute,<br />
so these colors are always available to any SVG component in<br />
the frame.<br />
independentOdometer<br />
logo<br />
lowLampColor<br />
odometerValue<br />
If true, this meter can display an additional value independent<br />
of its needle value, in a text box at the center of the gauge. If<br />
false, the value in the text box is the same as the needle value.<br />
The default is false.<br />
This attribute has the underlying data type<br />
%ZEN.Datatype.boolean. It has the value "true" or "false" in XData<br />
Contents, 1 or 0 in server-side code, true or false in client-side<br />
code. See Datatype Classes.<br />
Text label for the face of the meter (similar to "<strong>Zen</strong>" in the illustration<br />
above).<br />
Although you enter ordinary text for this attribute, it has the<br />
underlying data type %ZEN.Datatype.caption. This makes it easy<br />
to localize its text into other languages. See <strong>Zen</strong> Localization.<br />
String containing a CSS color value. This is the color that the<br />
displays when its value falls below<br />
thresholdLower. The default is a pre-defined <strong>Zen</strong> color:<br />
url(#glow-red)<br />
If independentOdometer is true, this is the value to display in<br />
the text box at the center of the gauge.<br />
120 <strong>Using</strong> <strong>Zen</strong>
Charts<br />
9.3.8 <br />
The traffic light consists of three circular lamps in a vertical column. From top to bottom, the lamps<br />
are red, yellow, and green.<br />
When the meter value is at or below thresholdLower, the bottom lamp shows green. At values above<br />
thresholdLower but below thresholdUpper, the center lamp shows yellow. At values at or above<br />
thresholdUpper, the top lamp shows red. This is useful when a large number indicates a condition that<br />
requires attention.<br />
Sometimes a low number indicates a condition that requires attention. If this is the case you can reverse<br />
the sense of a traffic light by inverting the values for rangeLower and rangeUpper. Then the red lamp<br />
indicates low values, and the green lamp indicates high values.<br />
has no unique attributes. It has the usual meter attributes. looks best<br />
when width is half of height. You cannot change the colors for the traffic light (green, yellow, red).<br />
9.4 Charts<br />
Charts, or graphs, are SVG components that represent a series of data points. <strong>Zen</strong> provides several<br />
built-in chart types, including line charts, bar charts, and pie charts. As SVG components, charts have<br />
the layout and style characteristics described in this chapter. However, charts also have many unique<br />
attributes. For a complete explanation, see the next chapter, <strong>Zen</strong> Charts.<br />
<strong>Using</strong> <strong>Zen</strong> 121
<strong>Zen</strong> and SVG<br />
9.5 <br />
The radial navigator is a specialized SVG component that displays the relationship between a set of<br />
data items as a dynamic, radial diagram. There is a central circular hub surrounded by a set of evenly<br />
spaced nodes. As you click on a node at the outer rim of the diagram, it becomes the hub node and the<br />
nodes to which it connects are shown circling it.<br />
You define the nodes in the data set by providing elements inside<br />
the element. For example:<br />
122 <strong>Using</strong> <strong>Zen</strong>
<br />
<br />
<br />
<br />
<br />
Attribute<br />
SVG component<br />
attributes<br />
backgroundStyle<br />
hubStyle<br />
mainLabel<br />
mainLabelStyle<br />
nodeStyle<br />
onselectNode<br />
Description<br />
has the same general-purpose attributes as any<br />
SVG component.<br />
SVG CSS style definition for the background panel. (Styles within<br />
SVG are CSS compliant, but there is a different set of styles<br />
available.)<br />
SVG CSS style definition. Specifies the style for the central hub.This<br />
style must include a fill value, or mouse events within this shape will<br />
not work correctly.<br />
Label text for the central hub.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its<br />
text into other languages. See <strong>Zen</strong> Localization.<br />
SVG CSS style definition. Specifies the style for the mainLabel text.<br />
SVG CSS style definition. Specifies the style for the radial nodes.<br />
This style must include a fill value, or mouse events within this shape<br />
will not work correctly.<br />
Client-side JavaScript expression that runs whenever the user clicks<br />
the mouse on a node shape. Generally this expression invokes a<br />
client-side JavaScript method defined in the page class.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the JavaScript<br />
expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
selectedIndex<br />
When the onselectNode event is invoked, the selectedIndex contains<br />
the index (0-based) of the currently selected node. If the user clicks<br />
on the central hub node, selectedIndex is -1. When selectedIndex<br />
is –2, this means no node is selected.<br />
<strong>Using</strong> <strong>Zen</strong> 123
<strong>Zen</strong> and SVG<br />
Attribute<br />
title<br />
titleStyle<br />
Description<br />
Title text for the radial navigator.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its<br />
text into other languages. See <strong>Zen</strong> Localization.<br />
SVG CSS style definition. Specifies the style for the title text.<br />
The element is the XML projection of the %ZEN.Auxiliary.radialNode class. <br />
has the following attributes.<br />
Attribute<br />
caption<br />
onclick<br />
Description<br />
Text specifying the caption to display for this radial node.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
Client-side JavaScript expression that runs whenever the user clicks the<br />
mouse on the node shape. When providing a value for this attribute, use<br />
double quotes to enclose the value and single quotes (if needed) within<br />
the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
style<br />
value<br />
SVG CSS style definition for the node. The style must include a fill value,<br />
or mouse events within the node shape will not work correctly.<br />
(Optional) Value associated with this node. The value may be a decimal<br />
or integer number, but it is represented as a string.<br />
When you work with %ZEN.SVGComponent.radialNavigator programmatically, you work with <br />
elements as members of the radialNavigator nodes property, a list collection of<br />
%ZEN.Auxiliary.radialNode objects. Each in the becomes a member<br />
of the nodes collection in radialNavigator, associated with its ordinal position: 1, 2, 3, etc.<br />
124 <strong>Using</strong> <strong>Zen</strong>
9.6 <br />
is an empty SVG component whose contents are filled dynamically by invoking a<br />
runtime callback method that provides SVG content. has the following attributes.<br />
Attribute<br />
SVG<br />
component<br />
attributes<br />
onrender<br />
Description<br />
has the same general-purpose attributes as any SVG<br />
component.<br />
Client-side JavaScript expression. Generally this invokes a client-side<br />
JavaScript method defined in the page class. This method provides the<br />
statements that render the SVG component on the page.<br />
When providing a value for this attribute, use double quotes to enclose<br />
the value and single quotes (if needed) within the JavaScript expression.<br />
For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
The following is an example of an element:<br />
<br />
In the above example, the JavaScript expression invokes the page class doOwnerDraw method with<br />
the object as its argument. The expression represents the page with the built-in variable<br />
zenPage, and the object with the built-in variable zenThis. Elsewhere in the page<br />
class, the doOwnerDraw method could look like this:<br />
<strong>Using</strong> <strong>Zen</strong> 125
<strong>Zen</strong> and SVG<br />
Method doOwnerDraw(svg) [ Language = javascript ]<br />
{<br />
// clear contents of ownerDraw component<br />
}<br />
svg.unrender();<br />
// create a line; add it to the svg component<br />
for (var n = 0; n < 30; n++) {<br />
var line = svg.document.createElementNS(SVGNS,'line');<br />
line.setAttribute('x1',200);<br />
line.setAttribute('y1',100);<br />
line.setAttribute('x2',Math.random() * 400);<br />
line.setAttribute('y2',Math.random() * 200);<br />
line.setAttribute('style','stroke: blue; stroke-width: 2;');<br />
svg.svgGroup.appendChild(line);<br />
}<br />
The SAMPLES namespace offers examples in the page classes ZENDemo.SVGBrowser<br />
and ZENTest.SVGOwnerDrawTest.<br />
You can also create custom SVG components. See Custom Components.<br />
126 <strong>Using</strong> <strong>Zen</strong>
10<br />
<strong>Zen</strong> Charts<br />
This chapter explains how to place a chart on a <strong>Zen</strong> page. Charts represent series of data items by<br />
graphing them, usually across a grid defined by two axes. The following figure shows a line chart.<br />
<strong>Zen</strong> offers several built-in chart types: line charts, bar charts, pie charts, etc. Every chart is an SVG<br />
component as described in the previous chapter, <strong>Zen</strong> and SVG. This means that every chart is derived<br />
from the class %ZEN.SVGComponent.svgComponent. Charts follow the layout and style conventions<br />
for SVG components, but add specific behaviors of their own.<br />
<strong>Using</strong> <strong>Zen</strong> 127
<strong>Zen</strong> Charts<br />
The base chart class %ZEN.SVGComponent.chart defines the data, grid (axes and scales), styles, and<br />
legend used by charts. All charts are plotted onto a virtual coordinate space that measures 100 units<br />
by 100 units. The actual dimensions of this space are determined by the chart height and width values.<br />
Within this virtual space, there is a smaller plot area in which the chart appears. Margins fill the space<br />
around the plot area. Generally you use these margins as space in which to display the labels and legend<br />
for the chart.<br />
The following diagram gives some indication of how chart attributes affect the layout of a chart. The<br />
attributes shown in the diagram include some from the SVG component class<br />
%ZEN.SVGComponent.svgComponent (width, height) and some from the base chart class<br />
%ZEN.SVGComponent.chart (marginTop, bandUpper, legendX). If this were a line chart, there would<br />
also be attributes specific to line charts (chartFilled, chartPivot).<br />
Layout Conventions for <strong>Zen</strong> Charts<br />
The number and variety of chart attributes can seem overwhelming at first. That is why this chapter<br />
begins by introducing the various types of chart, so that you can look at some visual examples and<br />
think about the items you want to display on the <strong>Zen</strong> page, before reading the exact details of how to<br />
display them. Chapter topics appear in this order:<br />
128 <strong>Using</strong> <strong>Zen</strong>
Types of Chart<br />
• Types of Chart<br />
• Providing Data for Charts<br />
• Chart Attributes<br />
• Chart Axes<br />
10.1 Types of Chart<br />
This topic describes and illustrates several types of chart that you can place on the <strong>Zen</strong> page. Each<br />
description includes the unique attributes that define that type of chart. For attributes that all charts<br />
share in common, see the topic Chart Attributes.<br />
10.1.1 Line Charts<br />
A displays one or more data series as a set of lines across a grid. The beginning of this<br />
chapter displays a simple line chart. has the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 129
<strong>Zen</strong> Charts<br />
Attribute<br />
Chart<br />
attributes<br />
chartFilled<br />
chartPivot<br />
chartStacked<br />
Description<br />
has the same general-purpose attributes as any chart, plus<br />
the attributes described in this table.<br />
If true, the area under each line is filled (as in an area chart). If false, it<br />
is not filled (as in a line chart).<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
If true, pivot the chart (display categories vertically and values horizontally).<br />
If false, display the chart in typical fashion (categories on the<br />
horizontal axis and values on the vertical axis).<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
chartStacked comes into play if there are multiple data series. If true,<br />
the lines are stacked atop one another (values are additive). If false,<br />
the lines are superimposed (the values are independent). When<br />
chartStacked is true, negative values are ignored.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
130 <strong>Using</strong> <strong>Zen</strong>
Types of Chart<br />
10.1.2 Bar Charts<br />
A displays one or more data series as a set of vertical or horizontal bars. has<br />
the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 131
<strong>Zen</strong> Charts<br />
Attribute<br />
Chart<br />
attributes<br />
chartPivot<br />
chartStacked<br />
Description<br />
has the same general-purpose attributes as any chart, plus<br />
the attributes described in this table.<br />
The chart attribute plotToEdge is always treated as false for .<br />
The baseValue is used to plot the bottom of the bars; see Chart<br />
Axes.<br />
If true, pivot the chart (display categories vertically and values horizontally).<br />
If false, display the chart in typical fashion (categories on the<br />
horizontal axis and values on the vertical axis).<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
chartStacked comes into play if there are multiple data series. If true,<br />
the bars at each position along the category axis are stacked atop one<br />
another (values are additive). If "false" the bars appear side by side (the<br />
values are independent). When chartStacked is true, negative values<br />
are ignored.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
132 <strong>Using</strong> <strong>Zen</strong>
Types of Chart<br />
10.1.3 Difference Charts<br />
A is a specialized type of line chart that highlights the difference between two series:<br />
1. The first, reference data series shows ideal or projected values<br />
2. The second data series shows actual values<br />
The shades the area between the two series using the color of the actual data series. To<br />
further distinguish between the series, the chart draws a line representing the reference series across<br />
the shaded area of the chart. This line uses the reference series color; it can take additional styling<br />
from the refLineStyle attribute.<br />
<strong>Using</strong> <strong>Zen</strong> 133
<strong>Zen</strong> Charts<br />
Attribute<br />
Chart<br />
attributes<br />
refLineStyle<br />
Description<br />
has the same general-purpose attributes as any chart, plus<br />
the attributes described in this table.<br />
SVG CSS style definition for the reference line. By default, this line uses<br />
the color assigned to the reference (first) data series, but typically it also<br />
assigns some patterning using refLineStyle. The default is:<br />
stroke-dasharray: 1,1;<br />
The figure above shows:<br />
stroke-dasharray: 3,3; stroke-width: 2px;<br />
10.1.4 High/Low Charts<br />
134 <strong>Using</strong> <strong>Zen</strong>
A can be used to show stock market high-low-close values, or to trace a measured value<br />
along with its high and low ranges to indicate possible error margins. The chart displays a set of bars<br />
as established by three data series:<br />
1. A series of high values sets the top (right) limit of each bar.<br />
2. A series of low values sets the bottom (left) limit of each bar.<br />
3. (Optional) The “closing” values. The chart places a marker on each bar at these values.<br />
Types of Chart<br />
Each low value is assumed to be smaller than its corresponding high value. Each closing value is<br />
assumed to between its corresponding high and low values. The chart uses its first seriesColor value<br />
to plot all bars and marker. It ignores the colors provided for the other series.<br />
Attribute<br />
Chart<br />
attributes<br />
chartPivot<br />
Description<br />
has the same general-purpose attributes as any chart,<br />
plus the attributes described in this table.<br />
The chart attribute plotToEdge is always treated as false for<br />
.<br />
If true, display bars horizontally, as shown in the example above. If false,<br />
display the chart with vertical bars.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
<strong>Using</strong> <strong>Zen</strong> 135
<strong>Zen</strong> Charts<br />
10.1.5 Scatter Diagrams<br />
An plots two or more data series as (x,y) points. This type of chart is sometimes called a<br />
scatter diagram; it is intended to show the raw data distribution for the series. The represents<br />
its data series as follows:<br />
1. The first data series provides the x values<br />
2. The second data series provides correlated y values<br />
3. Any additional data series are plotted as y values correlated to the x values provided by the first<br />
series.<br />
The result is that an always displays one less plot than its number of data series.<br />
has no unique attributes. has the same chart attributes as any chart, except that<br />
markersVisible and plotToEdge are always set to true. Generally you need to manipulate some of the<br />
other chart attributes to produce the desired results. For example:<br />
136 <strong>Using</strong> <strong>Zen</strong>
• The seriesCount value must always be one more than the number of plots you want to display.<br />
This leaves room for the first, x-value series.<br />
• The first data series is not plotted, so the applies series settings beginning with the<br />
second series, not the first. For example:<br />
- The seriesColor list applies to the second, third, and successive series.<br />
- The seriesNames list applies to the second, third, and successive series.<br />
- The markerShapes list applies to the second, third, and successive series.<br />
• A scatter diagram does not appear “scattered” unless you hide the lines between the markers. To<br />
do this, set the plotStyle for an as follows:<br />
plotStyle="stroke-width: 0;"<br />
Types of Chart<br />
10.1.6 Pie Charts<br />
<strong>Using</strong> <strong>Zen</strong> 137
<strong>Zen</strong> Charts<br />
A displays a circle with radial slices representing one series of data values. The chart<br />
adjusts the size of each slice proportionally so that the full set of slices forms a complete circle. The<br />
does not support axes, or grids in the plot area, as for line charts or bar charts.<br />
Attribute<br />
Chart attributes<br />
pieScale<br />
plotBy<br />
showPercentage<br />
Description<br />
has the same general-purpose attributes as any chart,<br />
plus the attributes described in this table.<br />
Decimal value that specifies the scaling factor for the size of the pie<br />
within the chart. The default scaling value is 1.0. A value larger than<br />
1.0 makes the pie bigger relative to the plot area; a value smaller than<br />
1.0 makes the pie smaller.<br />
Specifies how the pie chart will plot its data. Possible values are<br />
"items", "series", or "both". The default is "items". The following topics<br />
describe all the details.<br />
If true, percentage values (rounded to nearest integer) are displayed<br />
as part of the label for each slice. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
The plotBy attribute controls how <strong>Zen</strong> generates a pie chart from the data provided. You<br />
may actually provide multiple series to the . The chart processes all the data series to create<br />
one series, and then displays that series as slices in the chart. plotBy options are as follows.<br />
• "items"<br />
• "series"<br />
• "both"<br />
10.1.6.1 Pie Charts by Item<br />
When the value of plotBy is "items", a plots one slice for every item within the data series.<br />
If you provide multiple data series to an "items" pie chart, each slice of the pie represents the total of<br />
a particular item, summed across all of the data series in the chart.<br />
The following conceptual figure shows how five data series, each containing eight items, would generate<br />
an eight-slice pie chart. Each slice represents the sum of the five values for that item in each<br />
series.<br />
138 <strong>Using</strong> <strong>Zen</strong>
Types of Chart<br />
How <strong>Zen</strong> Plots Pie Charts by Item<br />
When the value of plotBy is "items", labels for the slices are treated as labels. This means<br />
you cannot specify them directly using a chart attribute such as seriesNames. Labels are provided by<br />
a %ZEN.Auxiliary.dataController, if present, or you can provide an onGetLabelY event handler to get<br />
the label values.<br />
10.1.6.2 Pie Charts by Series<br />
When the value of plotBy is "series", multiple series are in use. The plots one slice for<br />
every data series, so the number of slices in the pie chart is seriesCount. Each slice represents the sum<br />
of all the items within one of the series. The seriesNames attribute provides the labels for the slices,<br />
and for the legend. The chart at the beginning of this topic has plotBy set to "series".<br />
The following conceptual figure shows how five data series, each containing eight items, would generate<br />
a five-slice pie chart. Each slice represents the sum of the eight items in that series.<br />
<strong>Using</strong> <strong>Zen</strong> 139
<strong>Zen</strong> Charts<br />
How <strong>Zen</strong> Plots Pie Charts by Series<br />
10.1.6.3 Pie Charts by Both Items and Series<br />
When the value of plotBy is "both", multiple series are in use. The plots one slice for every<br />
item in every data series, so there are seriesCount times seriesSize slices. The base color for each slice<br />
is the associated series color. Alternating slices use dark and normal shades of this color. The chart<br />
legend displays series names; the seriesNames attribute provides these labels. The slices display item<br />
names; the labels are provided by an onGetLabelY event handler, or a data controller.<br />
The following pie chart example compares three series (Products, Services, and Training), each of<br />
which has data items in four categories (America, Asia, Europe, and Africa). The chart has twelve<br />
slices.<br />
140 <strong>Using</strong> <strong>Zen</strong>
Providing Data for Charts<br />
<strong>Zen</strong> Pie Chart from Both Items and Series<br />
10.2 Providing Data for Charts<br />
The data for a chart consists of one or more data series. Each data series that you use for a chart is a<br />
simple array of numeric values. You can provide the data for a chart in one of two ways:<br />
• Invoke a JavaScript method in the page class, by setting the chart’s ongetData attribute.<br />
• Associate the chart with a data controller, by setting the chart’s controllerId attribute.<br />
<strong>Using</strong> <strong>Zen</strong> 141
<strong>Zen</strong> Charts<br />
This topic describes both techniques in detail. First it describes how to limit the data returned by either<br />
technique to the desired number and size of series.<br />
10.2.1 Limiting the Data Set<br />
The following attributes from the base class %ZEN.SVGComponent.chart tell the chart how many series<br />
to use, and how many of the items in each data series to use, when constructing the chart. All types of<br />
chart support these attributes.<br />
Attribute<br />
seriesCount<br />
seriesSize<br />
Description<br />
Positive integer specifying the number of series in the chart. Even if your<br />
data source actually provides a larger number of series, you can trim the<br />
number of displayed series by setting seriesCount to a smaller number.<br />
If the chart does not supply a seriesCount, <strong>Zen</strong> infers the number of<br />
series from the data, as shown in the following figure.<br />
Positive integer specifying the number of items within each data series<br />
to display on this chart. If "", then seriesSize is computed automatically<br />
based on the chart’s data source. Even if the data source actually<br />
provides a larger number of items, you can trim the number of displayed<br />
items by setting seriesSize to a smaller number. If the chart does not<br />
supply a seriesSize, <strong>Zen</strong> infers the size of the series from the data, as<br />
shown in the following figure.<br />
142 <strong>Using</strong> <strong>Zen</strong>
Providing Data for Charts<br />
Data Series Count and Size<br />
10.2.2 <strong>Using</strong> a JavaScript Method<br />
All charts support the ongetData attribute. The value of this attribute is a client-side JavaScript<br />
expression that <strong>Zen</strong> invokes whenever:<br />
• The chart is initially displayed<br />
• The chart’s updateChart method is invoked<br />
For example:<br />
ongetData="return zenPage.getChartData(series);"<br />
Generally the ongetData expression invokes a client-side JavaScript method defined in the page class.<br />
This method becomes the “ongetData event handler” for the chart. In the above example, this method<br />
is called getChartData. The ongetData event handler must accept a single argument, series, and must<br />
assume that this argument contains the 0-based ordinal number of the data series to be plotted. The<br />
method may consist of a switch statement based on the value of this input argument. It must return a<br />
simple array of numeric values for the specified data series.<br />
<strong>Using</strong> <strong>Zen</strong> 143
<strong>Zen</strong> Charts<br />
The following is a sample ongetData event handler that provides random values as a test. You can see<br />
this event handler in the SAMPLES namespace in the template page class ZENTest.SVGChartTest. It<br />
provides the data for charts drawn by page classes that extend the ZENTest.SVGChartTest template,<br />
such as SVGLineChartTest and SVGBarChartTest:<br />
Method getChartData(series) [ Language = javascript ]<br />
{<br />
var chart = zenPage.getComponentById('chart');<br />
var data = new Array(chart.seriesSize);<br />
var value = 50;<br />
}<br />
for (var i = 0; i < chart.seriesSize; i++) {<br />
if (Math.random() > 0.9) {<br />
value += (Math.random() * 50) - 35;<br />
}<br />
else {<br />
value += (Math.random() * 20) - 9;<br />
}<br />
data[i] = value;<br />
}<br />
return data;<br />
10.2.3 <strong>Using</strong> a Data Controller<br />
All charts support the following attributes, which associate the chart with a view on a data controller,<br />
as described in the chapter Model View Controller.<br />
Attribute<br />
controllerId<br />
onnotifyView<br />
Description<br />
Identifies the data controller that provides the data for this chart. The<br />
controllerId value must match the id value provided for that<br />
.<br />
This attribute applies if the chart is associated with a data controller. The<br />
onnotifyView value is a client-side JavaScript expression that is executed<br />
each time the data controller connected to this chart raises an event.<br />
Generally this expression invokes a client-side JavaScript method defined<br />
in the page class.This method becomes the “onnotifyView event handler”<br />
for the chart.<br />
When providing a value for this attribute, use double quotes to enclose<br />
the value and single quotes (if needed) within the JavaScript expression.<br />
For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
144 <strong>Using</strong> <strong>Zen</strong>
If your XData Contents block contains a reference that looks like this:<br />
<br />
Then your XData Contents block may also contain a chart definition that looks like this:<br />
<br />
<br />
Chart Attributes<br />
The chart’s controllerId value must match the id value. The chart takes its seriesSize<br />
from the number of properties in the modelClass.<br />
10.3 Chart Attributes<br />
The base class %ZEN.SVGComponent.chart offers a large number of attributes that you can apply to<br />
a <strong>Zen</strong> chart to control details such as:<br />
• Layout and style — The relative size and characteristics of the background<br />
• Plot area — The part of the chart that displays the data<br />
• Markers — Shapes that highlight the exact data points on a continuous plot<br />
• Legends — A key to the meaning of each plot on the chart<br />
• Titles — Text that labels the chart, and the items on the chart<br />
• User events — How the chart should respond to user actions, such as mouse clicks<br />
• Coordinate axes — Characteristics of the two axes that define most charts<br />
10.3.1 Layout and Style<br />
The following attributes from the base class %ZEN.SVGComponent.chart determine the background<br />
style and the position of the plot area within the chart. When setting values for these attributes, keep<br />
in mind that the chart occupies a virtual coordinate space that measures 100 units by 100 units.<br />
<strong>Using</strong> <strong>Zen</strong> 145
<strong>Zen</strong> Charts<br />
Chart Layout and Style Attributes<br />
Attribute<br />
SVG<br />
component<br />
attributes<br />
backgroundStyle<br />
marginBottom<br />
marginLeft<br />
marginRight<br />
marginTop<br />
Description<br />
A chart has the same general-purpose attributes as any SVG<br />
component. These attributes include the height and width shown in<br />
the above diagram.<br />
SVG CSS style definition. Specifies the style for the background panel.<br />
This is the area outside the plot area but inside the chart component’s<br />
height and width.<br />
Margin to allow from the bottom edge of the background to the bottom<br />
edge of the plot area. X-axis labels or the chart legend usually appear<br />
in this space. Provide an integer value. The default is 10 units.<br />
Margin to allow from the left edge of the background to the left edge<br />
of the plot area. Y-axis labels or the chart legend usually appear in<br />
this space. Provide an integer value. The default is 10 units.<br />
Margin to allow from the right edge of the background to the right edge<br />
of the plot area. Provide an integer value. The default is 2 units.<br />
Margin to allow from the top edge of the background to the top edge<br />
of the plot area. The table title usually appears in this space. Provide<br />
an integer value. The default is 6 units.<br />
10.3.2 Plot Area<br />
The following attributes from the base class %ZEN.SVGComponent.chart determine display conventions<br />
for graphs within the plot area and for the coordinate axes that border the plot area. Also see the next<br />
major topic, Chart Axes.<br />
Attribute<br />
bandLower<br />
bandLowerStyle<br />
bandUpper<br />
bandUpperStyle<br />
Description<br />
Decimal value. If defined, the chart displays a colored band on the<br />
plot area covering the range lower than this value. bandLowerStyle<br />
defines the style of this band.<br />
SVG CSS style definition for the band defined by bandLower.<br />
Decimal value. If defined, the chart displays a colored band on the<br />
plot area covering the range higher than this value. bandUpperStyle<br />
defines the style of this band.<br />
SVG CSS style definition for the band defined by bandUpper.<br />
146 <strong>Using</strong> <strong>Zen</strong>
Chart Attributes<br />
Attribute<br />
gridStyle<br />
labelStyle<br />
labelsVisible<br />
ongetLabelX<br />
Description<br />
SVG CSS style definition. Default style applied to all grid line elements<br />
within the plot area for this chart. If defined, gridStyle overrides any<br />
styles define in the CSS style definition for the page, but gridStyle is<br />
in turn overridden by any styles defined by a specific axis element in<br />
the chart.<br />
SVG CSS style definition. Default style applied to all label elements<br />
for this chart. If defined, labelStyle overrides any styles define in the<br />
CSS style definition for the page, but labelStyle is in turn overridden<br />
by any styles defined by a specific axis element in the chart.<br />
If true, display axis labels for this chart (or slice labels for a pie chart).<br />
If false, hide labels. The default is true.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Client-side JavaScript expression. If the chart provides an ongetLabelX<br />
value, then the ongetLabelX expression is executed to provide the<br />
text for labels on the x-axis.<br />
Generally the ongetLabelX expression invokes a client-side JavaScript<br />
method defined in the page class. This method becomes the<br />
“ongetLabelX event handler” for the chart. It must accept an argument,<br />
value, that contains the 0-based ordinal number of the data point<br />
whose text label is to be returned. It may consist of a switch statement<br />
based on the value of the input argument. It must return a text string.<br />
For example:<br />
ongetLabelX="return zenPage.getXLabels(value);"<br />
When providing a value for an event handler attribute such as<br />
ongetLabelX, use double quotes to enclose the value and single<br />
quotes (if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
ongetLabelY<br />
Client-side JavaScript expression, as for ongetLabelX.<br />
For pie charts, ongetLabelY is the attribute to use to set slice labels.<br />
<strong>Using</strong> <strong>Zen</strong> 147
<strong>Zen</strong> Charts<br />
Attribute<br />
onrenderPlotArea<br />
plotAreaStyle<br />
plotStyle<br />
plotToEdge<br />
Description<br />
Client-side JavaScript expression. If the chart provides an<br />
onrenderPlotArea value, then the onrenderPlotArea expression is<br />
called by the chart just after it displays its underlying plot area (and<br />
bands) but before it display grid lines and data.<br />
SVG CSS style definition for the plot area panel for this chart.<br />
Default SVG CSS style definition applied to the SVG elements that<br />
are used to plot data for this chart. These elements include the line<br />
in a line chart, or the bar in a bar chart.<br />
Specifies how values should be plotted along a category axis:<br />
• True— plot the first and last values on the edges of the plot area<br />
(as in a line chart)<br />
• False— plot values in the centers of each unit (as in a bar chart)<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
seriesColors<br />
Comma-delimited list of CSS color values to use for data series. The<br />
chart applies these colors to each data series in ordinal order (series<br />
0 gets the first color, series 1 the second color, and so on). If you omit<br />
seriesColors, the default color list is:<br />
"blue,red,green,yellow,orange,plum,purple"<br />
seriesNames<br />
Comma-delimited list of names to use for data series. The chart<br />
applies these names to each data series in ordinal order (series 0<br />
gets the first name, series 1 the second name, and so on). These<br />
names can appear as labels for the series in the legend chart.<br />
The seriesNames attribute has its ZENLOCALIZE datatype parameter<br />
set to 1 (true). This means it is easy to localize its text into other languages.<br />
See <strong>Zen</strong> Localization.The entire list of seriesNames is treated<br />
as one localized string.<br />
10.3.3 Markers<br />
Markers are shapes that are placed at each data point along the chart. If the chart has multiple series,<br />
each series in the chart can use a different shape for its marker. Marker attributes apply only to types<br />
148 <strong>Using</strong> <strong>Zen</strong>
Chart Attributes<br />
of chart that support markers (that is, line charts). The base class %ZEN.SVGComponent.chart offers<br />
the following marker attributes.<br />
Attribute<br />
markerScale<br />
markerShapes<br />
Description<br />
Decimal value that specifies the scaling for markers. A value of 1.0 (or<br />
"") displays markers with the default size. Use a larger value for larger<br />
markers, smaller for smaller markers.<br />
Comma-separated list of shapes to use for each series. It can be convenient<br />
to use a different shape for each series in the chart. This adds<br />
further distinction besides the color of each plot in the chart.The list can<br />
contain any of the following keywords in any order or combination:<br />
• "circle" — a circle<br />
• "down" — a triangle with point down<br />
• "square" — a square<br />
• "up" — a triangle with point up<br />
The default value for markerShapes is "circle,up,down,square"<br />
markerStyle<br />
markersVisible<br />
SVG CSS style definition. Style applied to all marker elements for this<br />
chart. The default is to outline the shape in the same color as the series<br />
plot, and fill the shape with white.<br />
If true, and this chart supports markers, markers will be displayed for<br />
the data points within the chart. If false, no markers are displayed, even<br />
if they are defined. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
10.3.4 Legends<br />
The following attributes from the base class %ZEN.SVGComponent.chart determine the style of the<br />
chart legend and whether or not it should display.<br />
Attribute<br />
legendHeight<br />
Description<br />
If this chart has a legend, this is the height of the legend box (within<br />
the chart coordinate space). If not specified, the chart uses a default<br />
height based on the number of data series.<br />
<strong>Using</strong> <strong>Zen</strong> 149
<strong>Zen</strong> Charts<br />
Attribute<br />
legendLabelStyle<br />
legendStyle<br />
legendVisible<br />
legendWidth<br />
legendX<br />
legendY<br />
Description<br />
SVG CSS style definition for label text within the legend box.<br />
SVG CSS style definition for the background of the legend box.<br />
If true, display a legend for this chart. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
If this chart has a legend, this is the width of the legend box (within<br />
the chart coordinate space). If not specified, the chart assigns a default<br />
width of 15 units.<br />
If this chart has a legend, this is the x-position of the legend box (within<br />
the chart coordinate space). If not specified, the default is 0 (left).<br />
If this chart has a legend, this is the y-position of the legend box (within<br />
the chart coordinate space). If not specified, the default is 0 (top).<br />
10.3.5 Titles<br />
The following attributes from the base class %ZEN.SVGComponent.chart determine the style and<br />
contents of the chart title.<br />
Attribute<br />
title<br />
titleStyle<br />
titleX<br />
titleY<br />
Description<br />
Title text for the chart. Generally you position a chart title outside the plot<br />
area but inside the chart background. See titleX and titleY.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
SVG CSS style definition. Specifies the style for the title text.<br />
If this chart has a title, this is the x-position of the center of the title text<br />
(within the chart coordinate space). If titleX is not specified, the default is<br />
50 (centered between 0 at left and 100 at right in the virtual space).<br />
If this chart has a title, this is the y-position of the bottom line for the title text<br />
(within the chart coordinate space). Descenders (for letters such as 'p' and<br />
'q') fall below this line. If titleY is not specified, the default is 5 (just below<br />
the top of the chart, within the default marginTop value of 6).<br />
150 <strong>Using</strong> <strong>Zen</strong>
Chart Attributes<br />
10.3.6 User Selections<br />
The following attributes control user interactions with the chart.<br />
Attribute<br />
onelementClick<br />
Description<br />
Client-side JavaScript expression that runs whenever the user clicks<br />
on a chart element (such as a marker in a line chart, or bar in a bar<br />
chart).<br />
Generally the onelementClick expression invokes a client-side<br />
JavaScript method defined in the page class. This method becomes<br />
the “onelementClick event handler” for the chart. It must accept an<br />
argument, chart, that represents this chart object. It then calls a<br />
method on this object to determine the identity of the currentlyselected<br />
data point (getSelectedItem) or data series<br />
(getSelectedSeries). Either method returns the 0–based ordinal<br />
number of the item that was selected, or -1 if nothing is currently<br />
selected. For example:<br />
onelementClick="zenPage.chartElementClick(chart);"<br />
If no onelementClick expression is provided, <strong>Zen</strong> uses its own handler<br />
to provide values for selectedItem and selectedSeries.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the JavaScript<br />
expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
selectedItem<br />
selectedItemStyle<br />
selectedSeries<br />
0–based ordinal number of the currently selected chart element (such<br />
as a marker in a line chart, or bar in a bar chart). This value is -1 if<br />
nothing is currently selected.<br />
SVG CSS style definition for the currently selected item in the chart.<br />
0–based ordinal number of the currently selected series in the chart,<br />
or -1 if no series is currently selected.<br />
<strong>Using</strong> <strong>Zen</strong> 151
<strong>Zen</strong> Charts<br />
10.4 Chart Axes<br />
Axes are essential for determining how chart data will be displayed. The range of axis values (minValue<br />
to maxValue) can be specified using or elements, or <strong>Zen</strong> can determine these values<br />
automatically based on the range of data values. With the exception of pie charts, all <strong>Zen</strong> charts are<br />
plotted using two axes as follows:<br />
• is the category axis; it names the categories in which data is being displayed.<br />
• is the value axis; it displays the value of the data in each category.<br />
In the following example, a element contains and definitions.<br />
<br />
<br />
<br />
<br />
The following attributes from the class %ZEN.Auxiliary.axis are available as attributes of either <br />
or within a chart definition. All of these attributes are optional; <strong>Zen</strong> provides reasonable<br />
defaults for each of them based on the data supplied to the chart.<br />
Chart Axis Attributes<br />
Attribute<br />
baseValue<br />
labelAngle<br />
labelStyle<br />
labelUnits<br />
Description<br />
For charts with filled regions (bar charts), baseValue is a decimal value<br />
that specifies where the base of the filled region should be plotted. If<br />
missing or blank (""), the base is the bottom of the plot area.<br />
Decimal value that specifies the number of degrees by which labels<br />
for this axis should be rotated. The default is 0 (the label text is<br />
horizontal).<br />
SVG CSS style definition for the text labels along this axis.<br />
Decimal value that specifies the amount of space between labels along<br />
this axis. If labelUnits is missing or blank (""), <strong>Zen</strong> automatically<br />
calculates a value based on the data series.<br />
152 <strong>Using</strong> <strong>Zen</strong>
Chart Axes<br />
Attribute<br />
majorGridLines<br />
majorGridStyle<br />
majorUnits<br />
maxValue<br />
minValue<br />
minorGridLines<br />
minorGridStyle<br />
minorUnits<br />
title<br />
Description<br />
If true, grid lines are displayed for each major unit on this axis. If false,<br />
major grid lines are not displayed. The default is true.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
SVG CSS style definition for the major grid lines along this axis.<br />
Decimal value that specifies the amount of space between major grid<br />
lines along this axis. If majorUnits is missing or blank (""), <strong>Zen</strong><br />
automatically calculates a value based on the data series.<br />
Decimal value that specifies the maximum data value along this axis.<br />
If maxValue is missing or blank (""), <strong>Zen</strong> automatically calculates a<br />
value based on the data series.<br />
Decimal value that specifies the minimum value along this axis. If<br />
minValue is missing or blank (""), <strong>Zen</strong> automatically calculates a value<br />
based on the data series.<br />
If true, grid lines are displayed for each minor unit on this axis. If false,<br />
minor grid lines are not displayed. The default is true.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
SVG CSS style definition for the minor grid lines along this axis.<br />
Decimal value that specifies the amount of space between minor grid<br />
lines along this axis. If minorUnits is missing or blank (""), <strong>Zen</strong><br />
automatically calculates a value based on the data series.<br />
Title text for the axis.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
When you work with %ZEN.SVGComponent.chart subclasses programmatically, you work with axes<br />
as the xAxis and yAxis properties of the chart object. Each of these properties is a %ZEN.Auxiliary.axis<br />
object with properties corresponding to the attributes listed above.<br />
<strong>Using</strong> <strong>Zen</strong> 153
11<br />
<strong>Zen</strong> Forms<br />
Forms permit the user to enter data. A <strong>Zen</strong> control is a component that displays application data and<br />
allows the user to edit this data. A <strong>Zen</strong> form is a specialized group component designed to contain<br />
control components. <strong>Zen</strong> forms have the same style and layout attributes as any <strong>Zen</strong> group. Also,<br />
because they are groups, forms may contain any other type of <strong>Zen</strong> component.<br />
Like all <strong>Zen</strong> components, a <strong>Zen</strong> form must be the child of a <strong>Zen</strong> page object. This means that if you<br />
want to provide a form for a <strong>Zen</strong> application, you must create a <strong>Zen</strong> page class that includes a form<br />
component inside the container. Two components are available:<br />
• — A <strong>Zen</strong> group that contains a specific list of control components. These controls may<br />
or may not take their values from a data controller, but their layout is entirely determined by the<br />
definition in XData Contents.<br />
• — An extension of that dynamically injects control components into a group<br />
(or groups) on the <strong>Zen</strong> page. The list of controls may be determined by the properties of an associated<br />
data controller, or by a callback method that generates a list of controls. Layout is automatic,<br />
determined by code internal to the .<br />
11.1 Forms and Controls<br />
The <strong>Zen</strong> library includes a number of controls for use in forms. Many of these controls are wrappers<br />
for the standard HTML controls, while others offer additional functionality. The following figure displays<br />
a form that contains a number of controls, including text fields and radio buttons. This is the<br />
sample form generated by the class ZENDemo.FormDemo in the SAMPLES namespace.<br />
<strong>Using</strong> <strong>Zen</strong> 155
<strong>Zen</strong> Forms<br />
The following figure lists the form and control components that <strong>Zen</strong> provides. Most of the classes<br />
shown in the figure are controls. All of the classes shown in the diagram are in the package<br />
%ZEN.Component, for example %ZEN.Component.form and %ZEN.Component.control. The diagram<br />
shows the inheritance relationships for these classes, and highlights the base classes most frequently<br />
discussed in this book.<br />
156 <strong>Using</strong> <strong>Zen</strong>
Forms and Controls<br />
Class Inheritance Among Form and Control Components<br />
For details about individual controls, see the next chapter, <strong>Zen</strong> Controls.<br />
<strong>Using</strong> <strong>Zen</strong> 157
<strong>Zen</strong> Forms<br />
11.2 User Interactions<br />
The basic interaction between a <strong>Zen</strong> application user and a <strong>Zen</strong> form is as follows:<br />
1. A user interacts with controls on the form<br />
2. <strong>Zen</strong> may validate the data as it is entered<br />
3. A user action indicates that it is time to submit the form<br />
4. <strong>Zen</strong> may validate the data prior to attempting the submit<br />
5. <strong>Zen</strong> interacts with the user to handle any errors it finds<br />
6. When all is well, <strong>Zen</strong> submits data from the form<br />
7. Any of the following might happen next:<br />
• Data from the form may be written to the server<br />
• The same <strong>Zen</strong> page may redisplay<br />
• A different <strong>Zen</strong> page may display<br />
• The same <strong>Zen</strong> page may display, but with components added or changed<br />
11.3 Defining a Form<br />
The <strong>Zen</strong> components and each support the following attributes for defining the<br />
characteristics of a form.<br />
Form Component Attributes<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
autoValidate<br />
Description<br />
A form has the same style and layout attributes as any <strong>Zen</strong> group.<br />
The chapter <strong>Zen</strong> Layout describes them.<br />
If true (the default), automatically invoke this form’s validate method<br />
whenever this form is submitted.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
158 <strong>Using</strong> <strong>Zen</strong>
Defining a Form<br />
Attribute<br />
controllerId<br />
enctype<br />
invalidMessage<br />
Description<br />
If this form is associated with a data controller, the controllerId<br />
attribute identifies the controller that provides the data for this form.<br />
The controllerId value must match the id value provided for that<br />
. See Model View Controller.<br />
(Optional) Specifies a HTML enctype for the form, such as<br />
"multipart/form-data"<br />
Message text that the form validate method displays in an alert box<br />
when the contents of this form are invalid. The default is:<br />
This form contains invalid values.<br />
Please correct the following field(s) and try again.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize<br />
its text into other languages. See <strong>Zen</strong> Localization.<br />
key<br />
nextPage<br />
onchange<br />
(Optional) Identifier used by the OnLoadForm method to load data<br />
for this form. If this form is connected to a dataController, this value<br />
is ignored. The key can be a literal string, or it can contain a <strong>Zen</strong><br />
#()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
URI of the page to display after this form is successfully submitted.<br />
This URI may be overwritten by a specific button on the<br />
form.<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the value<br />
of a control on this form is changed by the user or when the modified<br />
flags are cleared by a call to the form’s clearModified method.<br />
Generally this expression invokes a client-side JavaScript method.<br />
This method becomes the “onchange handler” for the form.<br />
When fired for a control, the onchange expression can use an<br />
argument called control to reference the modified control.<br />
When providing a value for an event handler attribute such as<br />
onchange, use double quotes to enclose the value and single quotes<br />
(if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
<strong>Using</strong> <strong>Zen</strong> 159
<strong>Zen</strong> Forms<br />
Attribute<br />
ondefault<br />
oninvalid<br />
OnLoadForm<br />
onnotifyView<br />
Description<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />
performs an action that triggers the default action for a form.<br />
Typically this is when the user presses the Enter key within a control<br />
within the form.<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when this form’s<br />
validate method determines that the contents of this form are invalid.<br />
This provides the application with a chance to display a custom<br />
message.<br />
(Optional) Name of a server-side method to call to get values for<br />
this form when it is first displayed. The OnLoadForm value must be<br />
the name of a server-only method in the page class that contains<br />
this form component.<br />
This attribute applies if the form is associated with a data controller.<br />
The onnotifyView value is a client-side JavaScript expression that<br />
is executed each time the data controller connected to this form<br />
raises an event. Generally this expression invokes a client-side<br />
JavaScript method defined in the page class.This method becomes<br />
the “onnotifyView event handler” for the form. See Model View<br />
Controller.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the JavaScript<br />
expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
onreset<br />
OnSubmitForm<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when this form<br />
is about to be reset. Generally this expression invokes a client-side<br />
JavaScript method.<br />
(Optional) Name of a server-side method to call when this form is<br />
submitted. The OnSubmitForm value must be the name of a<br />
server-only method in the page class that contains this form<br />
component. If no OnSubmitForm value is specified, then the page’s<br />
%OnSubmit method is called instead.<br />
160 <strong>Using</strong> <strong>Zen</strong>
Providing Values for a Form<br />
Attribute<br />
onsubmit<br />
onvalidate<br />
readOnlyMessage<br />
Description<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when this form<br />
is about to be submitted. Generally this expression invokes a<br />
client-side JavaScript method with a Boolean return value. Invoking<br />
this method gives <strong>Zen</strong> a chance to perform client-side validation of<br />
values within the form. If the method returns false, the pending<br />
submit operation will not occur. Note that unlike the HTML onsubmit<br />
event, the onsubmit callback is always called whenever the form is<br />
submitted.<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when this form’s<br />
validate method is called. Generally this expression invokes a<br />
client-side JavaScript method that performs validation.<br />
Message text that the form validate method displays in an alert box<br />
when the user makes an attempt to save a form bound to a readonly<br />
data model. The default readOnlyMessage text is:<br />
This data is read only.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize<br />
its text into other languages. See <strong>Zen</strong> Localization.<br />
11.4 Providing Values for a Form<br />
A form can initially display with blank fields, or you can provide data for some of the fields. Providing<br />
data for a field that the user sees means setting the value property for the associated <strong>Zen</strong> control component,<br />
before you ask <strong>Zen</strong> to display the form. There are several ways to do this:<br />
• Set the value attribute while adding each control to XData Contents.<br />
<br />
• Set the onLoadForm attribute while adding the form to XData Contents.<br />
<br />
• Set value properties from the page’s %OnAfterCreatePage method.<br />
Do ..%SetValueById("Doctor",$G(^formTest("Doctor")))<br />
• On the client side, call the setValue method for each control.<br />
Presumably, once the user begins editing the form, any initial values may change.<br />
<strong>Using</strong> <strong>Zen</strong> 161
<strong>Zen</strong> Forms<br />
11.5 Detecting Modifications to the Form<br />
A <strong>Zen</strong> form component tracks whether or not changes have occurred in any control on the form.<br />
%ZEN.Component.form and %ZEN.Component.control each offers a client-side method called isModified<br />
that tests this programmatically.<br />
A control’s isModified method returns true if the current logical value of the control (the value property)<br />
is different from its original logical value (the originalValue property). With each successive submit<br />
operation, the originalValue for each control acquires its previous value, so that this answer is always<br />
current with respect to the current state of the form.<br />
When you call a form’s isModified method, it invokes isModified for each control on the form, and<br />
if any control returns true, isModified returns true for the form.<br />
Note: The control returns an accurate isModified status when it contains fewer than 50<br />
characters. When the value contains 50 characters or more, the control does not<br />
compute an isModified status.<br />
11.6 Validating a Form<br />
Each <strong>Zen</strong> form has a validate method whose purpose is to validate the values of controls on the form.<br />
If the form’s autoValidate property is true, validate is called automatically each time the form is submitted.<br />
Otherwise, validate may be called explicitly by the application. validate does the following:<br />
1. Calls a form-specific onvalidate event handler, if defined. If this event returns false, <strong>Zen</strong> declares<br />
the form invalid and no further testing occurs.<br />
2. Resets the invalid property of all the form’s controls to false, then tests each control by calling the<br />
control’s validationHandler method. This method, in turn, does the following:<br />
• If the control’s readOnly or disabled properties are true, return true.<br />
• If the control’s required property is true and the control does not have a value (its value is ""),<br />
return false.<br />
• If the control defines an onvalidate event, execute it and returns its value. Otherwise, call the<br />
control’s isValid method. isValid can be overridden by subclasses that wish to provide builtin<br />
validation (such as the dateText control).<br />
3. As the validate method tests each control, the form builds a local array of invalid controls.<br />
4. After the validate method is finished testing the controls, it returns true if the form is valid.<br />
162 <strong>Using</strong> <strong>Zen</strong>
5. If the form contains one or more controls with invalid values, it is invalid. validate performs one<br />
of the following additional steps to handle this case:<br />
• If the form defines an oninvalid event handler:<br />
Execute the handler. This provides the form with a chance to handle the error conditions. The<br />
value returned by the oninvalid event is then returned by the form’s validate method. The<br />
oninvalid handler has an argument named invalidList that receives a JavaScript array containing<br />
the list of invalid controls. For example:<br />
<br />
Where the formInvalid method looks like this:<br />
Method formInvalid(form,list) [ Language = javascript ]<br />
{<br />
return false;<br />
}<br />
• When the form has no oninvalid event handler:<br />
Errors and Invalid Values<br />
validate sets the invalid property to true for each invalid control (which changes their style<br />
to zenInvalid); gives focus to the first invalid control; and displays an error message within<br />
an alert box. The message displayed in the alert box is built from a combination of the form’s<br />
invalidMessage property along with the value returned from each invalid control’s<br />
getInvalidReason method.<br />
11.7 Errors and Invalid Values<br />
Should an error occur while a form is being submitted, or should the form fail validation, <strong>Zen</strong> redisplays<br />
the page containing the form. The user has the opportunity to re-enter any incorrect values and submit<br />
the page again. All of this is extremely easy to set up when adding the or component<br />
to the <strong>Zen</strong> page.<br />
The SAMPLES namespace class ZENTest.FormTest allows you to experience error handling with <strong>Zen</strong><br />
forms as follows:<br />
1. Start your browser.<br />
2. Enter this URI:<br />
http://localhost:57772/csp/samples/ZENTest.FormTest.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
3. Ensure that the Name field is empty.<br />
4. Uncheck the Status box.<br />
<strong>Using</strong> <strong>Zen</strong> 163
<strong>Zen</strong> Forms<br />
5. Click Submit.<br />
6. The form’s validate method detects the invalid fields and highlights them with pink.<br />
7. The following alert message displays in the browser.<br />
To generate this message, the form has assembled the following snippets of text. <strong>Zen</strong> offers default<br />
values for these items, so there is no need for you to do anything for the default message to appear.<br />
However, if you wish you can customize them to any extent:<br />
• The message begins with the form’s invalidMessage text.<br />
• For each control that has its required attribute set to true, but contains no entry, the message<br />
lists the control’s label followed by the control’s requiredMessage text.<br />
• For each control that contains an invalid value, the message lists the control’s label followed<br />
by the control’s invalidMessage text.<br />
8. Click OK to dismiss the alert message box.<br />
9. The invalid controls remain highlighted until the user edits them and resubmits the form.<br />
11.8 Processing a Form Submit<br />
The request to submit the contents of a form can be triggered in one of two ways:<br />
• The user clicks a button placed within the form<br />
• The application calls the submit method of the form object in response to a user event:<br />
%form.submit<br />
When a form is submitted, the values of the controls in the form are sent to the server and the<br />
%OnSubmit callback method of the page containing the form is called. Note that the %OnSubmit<br />
callback method is that of the page that contains the form, not of the form itself or of any component<br />
on the form.<br />
%OnSubmit receives an instance of a special %ZEN.Submit object that contains all the submitted<br />
values (there is no page object available during submit processing). <strong>Zen</strong> automatically handles the full<br />
164 <strong>Using</strong> <strong>Zen</strong>
details of the submit operation, including invoking server callbacks and error processing. All forms<br />
are submitted using the HTTP POST submission method.<br />
If you are interested in details of how <strong>Zen</strong> executes a submit operation, the following table lists the<br />
internal events in sequence, organized by user viewpoint, browser-based execution, and server-side<br />
execution. Most of the communication details are handled by the CSP technology underlying <strong>Zen</strong>. For<br />
background information, see the chapter <strong>Zen</strong> Client and Server.<br />
Form Submit Sequence<br />
Processing a Form Submit<br />
User Viewpoint<br />
In the Browser<br />
On the Server<br />
1<br />
User clicks a button<br />
to invoke form<br />
submit<br />
2<br />
Post control values to the<br />
server via the HTTP POST<br />
mechanism<br />
3<br />
4<br />
5<br />
6<br />
7<br />
8<br />
Deserialize data from the<br />
client<br />
Reconstruct DOM based on<br />
new control values<br />
Run the server-side code for<br />
the page<br />
Update server-side DOM<br />
Generate new HTML page<br />
Send new HTML page as<br />
response to HTTP POST<br />
9<br />
10<br />
Render the HTML received<br />
in HTTP POST response<br />
Update client-side DOM to<br />
reflect changes made on<br />
the server<br />
11<br />
User sees new page<br />
<strong>Using</strong> <strong>Zen</strong> 165
<strong>Zen</strong> Forms<br />
11.9 User Login Forms<br />
An application login page presents a special case of a <strong>Zen</strong> form.<br />
See the chapter <strong>Zen</strong> Application Security, topic Controlling Access to Applications.<br />
11.10 Dynamic Forms<br />
A is a specialized type of form that dynamically injects control components into a group<br />
(or groups) on the <strong>Zen</strong> page. Layout is determined automatically by code internal to the .<br />
The list of controls may be determined by the properties of an associated data controller, or by a callback<br />
method that generates a list of controls.<br />
has the attributes listed in the following table.<br />
Attribute<br />
Form component<br />
attributes<br />
controllerId<br />
defaultGroupId<br />
OnGetPropertyInfo<br />
Description<br />
A has the same general-purpose attributes as any <strong>Zen</strong><br />
form. These attributes include the controllerId and onnotifyView<br />
attributes needed to work with a data controller.<br />
If this form is associated with a data controller, the controllerId<br />
attribute identifies the component that provides<br />
the data for this form.The controllerId value must match the id value<br />
for the .<br />
For full details about creating a that uses a data controller,<br />
see the Model View Controller chapter.<br />
(Optional) The id of a group in which to place the controls generated<br />
by this . This provides a way to control layout.<br />
Somewhere inside the , you must specify a group<br />
component (such as or ) with an id that matches<br />
the defaultGroupId. If no defaultGroupId is provided, controls are<br />
added directly to the without being contained in a<br />
group.<br />
(Optional) Name of a server-side method to call to get a list of the<br />
controls to provide on this form. OnGetPropertyInfo provides an<br />
alternative to using a data controller to generate the <br />
The OnGetPropertyInfo value must be the name of a server-only<br />
method in the page class that contains this .<br />
166 <strong>Using</strong> <strong>Zen</strong>
Dynamic Forms<br />
Attribute<br />
onnotifyView<br />
Description<br />
This attribute applies if the form is associated with a data controller.<br />
The onnotifyView value is a client-side JavaScript expression that<br />
is executed each time the data controller connected to this form<br />
raises an event. Generally this expression invokes a client-side<br />
JavaScript method defined in the page class.This method becomes<br />
the “onnotifyView event handler” for the form.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the JavaScript<br />
expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
For full details about creating a that uses a data controller,<br />
see the Model View Controller chapter.<br />
<strong>Using</strong> <strong>Zen</strong> 167
12<br />
<strong>Zen</strong> Controls<br />
<strong>Zen</strong> controls are the user input elements that you place on a <strong>Zen</strong> form. All controls are <strong>Zen</strong> components,<br />
but <strong>Zen</strong> controls also have unique characteristics derived from their parent class<br />
%ZEN.Component.control.<br />
Most importantly, each control has a value associated with it. value is a property that contains the<br />
current logical value of the control. Each control has the ability to display this value or keep it internally.<br />
<strong>Zen</strong> validates and submits all the control values for a form together, as a unit, according to the rules<br />
described in the previous chapter, <strong>Zen</strong> Forms.<br />
This chapter:<br />
• Describes characteristics shared by all <strong>Zen</strong> controls.<br />
• Identifies variations in layout, style, and behavior for different categories of control:<br />
- Buttons — , , <br />
- Text — , , , <br />
- Choices — , , , , <br />
- Lists — , , , , <br />
- Calendars — , <br />
- Hidden — <br />
- Spreadsheet — <br />
<strong>Using</strong> <strong>Zen</strong> 169
<strong>Zen</strong> Controls<br />
12.1 Control Attributes<br />
All <strong>Zen</strong> controls have the following attributes in common.<br />
Control Component Attributes<br />
Attribute<br />
<strong>Zen</strong> component<br />
attributes<br />
clientType<br />
Description<br />
A control has the same general-purpose attributes as any <strong>Zen</strong><br />
component. The chapter <strong>Zen</strong> Style describes them. The name<br />
attribute for a control has special significance: this name (and not the<br />
id) is associated with the control’s value when the form is submitted.<br />
Indicates the client-side (JavaScript) data type to expect for this<br />
control’s value. By default, a controls treats its value as a string with<br />
no client-side normalization. However, a control can set a value for<br />
clientType to indicate that it has a non-string value on the client side.<br />
Possible values are:<br />
• "string" — The client-side value is a string.<br />
• "boolean" — The client-side value is true or false.<br />
• "integer" — The client-side value is either an integer or '' to<br />
indicate an invalid integer.<br />
• "float" — The client-side value is either a float or '' to indicate<br />
an invalid float.<br />
controlClass<br />
controlStyle<br />
dataBinding<br />
disabled<br />
Name of a CSS style class. When <strong>Zen</strong> lays out this control, it assigns<br />
this value to the primary HTML element displayed for this control.<br />
String containing a CSS style definition. <strong>Zen</strong> applies this style to the<br />
primary HTML element displayed for this control.<br />
If this control is associated with a data controller, this attribute<br />
identifies the specific property within the modelClass<br />
that provides the value for this control. See Model View Controller.<br />
If true, this control is disabled; its appearance is unchanged, but it<br />
does not respond to user actions. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
170 <strong>Using</strong> <strong>Zen</strong>
Control Attributes<br />
Attribute<br />
invalid<br />
invalidMessage<br />
Description<br />
Set to true when the value of this control is known to be invalid. <strong>Zen</strong><br />
form validation logic does this so that <strong>Zen</strong> can display this control in<br />
a way that indicates its value is invalid. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Message text to provide when invalid is true. The default is:<br />
out-of-range or invalid value.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption.This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
—<br />
The next several attributes (names beginning with “on...”) identify<br />
event handlers for user actions relating to a control. In each case,<br />
the value of the attribute is a client-side JavaScript expression that<br />
<strong>Zen</strong> invokes when the related event occurs. Generally this expression<br />
invokes a client-side JavaScript method defined in the page class.<br />
This method becomes known as the “handler” for that specific event.<br />
When providing a value for an event handler attribute, use double<br />
quotes to enclose the value and single quotes (if needed) within the<br />
JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
onblur<br />
onchange<br />
onclick<br />
ondblclick<br />
onfocus<br />
Fired when the control loses focus.<br />
Fired when the value of the control changes. Note that controls fire<br />
this event indirectly; the actual onchange event is sent to a built-in<br />
handler that notifies the form that owns this control of the modification.<br />
Fired when the mouse is clicked on the control.<br />
Fired when the mouse is double-clicked on the control.<br />
Fired when the control is given focus.<br />
<strong>Using</strong> <strong>Zen</strong> 171
<strong>Zen</strong> Controls<br />
Attribute<br />
onkeydown<br />
onkeypress<br />
onkeyup<br />
onmousedown<br />
onmouseout<br />
onmouseover<br />
onmouseup<br />
onsubmit<br />
onvalidate<br />
—<br />
originalValue<br />
readOnly<br />
Description<br />
Fired when the user presses down on a key while this control has<br />
focus. There is a corresponding onkeyup for when the user releases<br />
the key.<br />
Fired after the user has pressed a key (that is, the user has pushed<br />
down and then released the key) while this control has focus.<br />
Fired when a key is released while this control has focus.<br />
Fired when a mouse button is released while within the area of the<br />
control.<br />
Fired when the mouse pointer leaves the area of the control.<br />
Fired when the mouse pointer enters the area of the control.<br />
Fired when a mouse button is pressed while within the area of the<br />
control.<br />
Fired when the form this control belongs to is submitted. This gives<br />
controls a chance to supply or modify the value they submit.<br />
Fired when this control’s value is validated by its parent form.<br />
(End of the list of attributes that identify event handlers.)<br />
Original value for this control before any user modification. It is used<br />
to detect which controls have been modified. This is a special value<br />
in that it is automatically initialized when a form is displayed.<br />
On the client side, do not access this property directly; instead use<br />
the getProperty and setProperty client-side methods. Note that<br />
setting the originalValue property on the client (via setProperty) will<br />
reset it to the current value of this control.<br />
If true, this control is read-only. The user cannot change the value of<br />
this control, but the control still submits its value when the form that<br />
contains it is submitted. The default readOnly value is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
172 <strong>Using</strong> <strong>Zen</strong>
Control Methods<br />
Attribute<br />
required<br />
requiredMessage<br />
Description<br />
If true, this control is required. That is, a user must supply a value for<br />
this control or the default form validation logic will fail.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Message text that the form validate method displays in an alert box<br />
when this control is required and does not have a value. The default<br />
requiredMessage text is:<br />
required.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption.This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
value<br />
Default value displayed within this control. This is a special value in<br />
that it is automatically initialized when a form is displayed. The value<br />
can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
On the client side, do not access this property directly; instead use<br />
the getValue and setValue client-side methods.<br />
12.2 Control Methods<br />
Each control has internal methods, which you can study in more detail by viewing the online class<br />
documentation for %ZEN.Component.control and its subclasses.<br />
The most important of these methods are those used to manipulate the value of the control. You can<br />
get and set the value property using the client-side getProperty and setProperty methods; getProperty<br />
and setProperty are available for you to work programmatically with any of the properties listed in<br />
the previous topic, not just value. Calling the setProperty method ensures that all actions relating to<br />
setting the property are also carries out, such as rendering the content within the control on the page.<br />
However, <strong>Zen</strong> controls also define the convenient client-side methods getValue and setValue, which<br />
work only on the value property and save the need to specify which property you wish to change.<br />
<strong>Using</strong> <strong>Zen</strong> 173
<strong>Zen</strong> Controls<br />
12.3 Buttons<br />
<strong>Zen</strong> offers the following button-style controls:<br />
• — The user clicks a button that can trigger further actions<br />
• — The user clicks an image that can trigger further actions<br />
• — The user clicks a button that submits a form<br />
12.3.1 <br />
The component is a simple wrapper for the HTML element.<br />
A <strong>Zen</strong> looks like this:<br />
has the following attributes:<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
caption<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These attributes include the onclick attribute, which determines what<br />
happens when a user clicks the button. If you want the form to be submitted<br />
when the user clicks this button, use the control instead of<br />
.<br />
Text displayed on this button. The above example uses:<br />
<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text into<br />
other languages. See <strong>Zen</strong> Localization.<br />
The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
12.3.2 <br />
The control displays a static image. can be used simply to display an image, or it<br />
can serve as a button if you specify an onclick event for it.<br />
174 <strong>Using</strong> <strong>Zen</strong>
Buttons<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
srcDisabled<br />
streamId<br />
src<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
However, has no associated value.<br />
(Optional) URI of the image to display when the src image is disabled.<br />
(Optional) Stream id of a binary stream object on the server that provides<br />
the data for this image. The streamId value overrides src if present.<br />
This attribute has ZENENCRYPT set to 1 (true) to specify that the streamId<br />
value will be encrypted (using the current session key) when it is sent to<br />
the client. If this value is returned to the server, it will be automatically<br />
decrypted. This makes it possible to place sensitive data on the client for<br />
future processing on the server without letting a user view this data.<br />
Identifies the pathname and filename of the image. The path is relative to<br />
the Caché installation directory. Typically this path identifies the images<br />
subdirectory for your <strong>Zen</strong> application, for example:<br />
<br />
12.3.3 <br />
is a special type of button that submits a form. has the following attributes.<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
caption<br />
action<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These attributes include the onclick attribute, which determines what<br />
happens when a user clicks the button.<br />
Text displayed on this button.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
(Optional) String giving the action code associated with this <br />
button. This value is passed along to the server-side %OnSubmit method<br />
of the page that contains the . If not provided, the default string<br />
is "submit".<br />
<strong>Using</strong> <strong>Zen</strong> 175
<strong>Zen</strong> Controls<br />
Attribute<br />
nextPage<br />
Description<br />
(Optional) URI of the page to display after this form is successfully<br />
submitted. If a button defines a nextPage value, it overrides the<br />
nextPage value for the form that contains the .<br />
12.4 Text<br />
<strong>Zen</strong> offers the following text-style controls:<br />
• — Displays a text label<br />
• — The user inputs text<br />
• — The user inputs multiple lines of text<br />
• — The user inputs a text password<br />
12.4.1 <br />
The control passively displays a static text value. <strong>Zen</strong> submits the along with other<br />
controls on the . has the same attributes as any <strong>Zen</strong> control.<br />
12.4.2 <br />
The <strong>Zen</strong> control is a wrapper around the HTML element. <strong>Zen</strong> <br />
displays a text input box like this:<br />
has the following attributes.<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
maxlength<br />
size<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.These<br />
include the value, a string of text.<br />
Maximum number of characters that the user may enter within this text<br />
control.<br />
Integer indicating the HTML width of the input area for this text control.<br />
The default size is 20.<br />
176 <strong>Using</strong> <strong>Zen</strong>
Text<br />
12.4.3 <br />
The <strong>Zen</strong> control is a wrapper around the HTML element. <strong>Zen</strong> <br />
displays a multi-line text input box, like this:<br />
has the following attributes.<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
cols<br />
rows<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include the value, a string of text that may or may not<br />
include line break characters, depending on what the user types.<br />
Keep in mind that many browsers do not cope well with long lines of<br />
unbroken text (greater than 4K characters with no white space).<br />
Number of columns in the control. The default is 19.<br />
Number of rows in the control. The default is 2.<br />
12.4.4 <br />
The <strong>Zen</strong> control is a wrapper around the HTML element.<br />
<strong>Zen</strong> displays a text input box for passwords. Any text that the user enters into the <br />
control is echoed as a dot instead of being displayed on the screen. For example:<br />
has the following attributes.<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
maxlength<br />
size<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include the value, a string of text.<br />
Maximum number of characters that the user may enter within this control.<br />
Integer indicating the HTML width of the input area for this control. The<br />
default size is 20.<br />
<strong>Using</strong> <strong>Zen</strong> 177
<strong>Zen</strong> Controls<br />
12.5 Simple Choices<br />
<strong>Zen</strong> offers the following simple choice controls:<br />
• — The user checks or unchecks a box<br />
• — The user browses to choose a file<br />
• — The user selects one color from a palette<br />
• — The user clicks one in a simple row of radio buttons<br />
• — Radio buttons might be placed anywhere on the page<br />
The difference between and is that is simpler to lay out. Use<br />
for a concise list of choices. Use when you want a more complex page<br />
layout that provides intervening information or images in between the radio button choices, or when<br />
you want to place radio buttons in a vertical group.<br />
12.5.1 <br />
The <strong>Zen</strong> control is a wrapper around the HTML element.<br />
The <strong>Zen</strong> control displays a caption next to the check box and detects user mouse clicks<br />
on the caption text as well as on the box. Unlike an HTML check box, the <strong>Zen</strong> control<br />
always submits a value. <strong>Zen</strong> looks like this:<br />
has the following attributes.<br />
178 <strong>Using</strong> <strong>Zen</strong>
Simple Choices<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
caption<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
has a clientType of "boolean" which means its value is<br />
expressed as "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, and true or false in client-side code. True means the <br />
is currently checked; false means it is unchecked.<br />
Text displayed to the right of the check box. The above example uses:<br />
<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text into<br />
other languages. See <strong>Zen</strong> Localization.<br />
The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
captionClass<br />
Name of a CSS style class to apply to the caption text. The default is:<br />
checkboxCaption<br />
12.5.2 <br />
The component is a simple wrapper for the HTML element.<br />
A <strong>Zen</strong> control looks like this. A user can enter a full pathname in the text field or click<br />
the Browse button to search for the file:<br />
has the following attributes:<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
maxlength<br />
size<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include the value, a string that is the full pathname of<br />
a file.<br />
Maximum number of characters that the user may enter within this control.<br />
Integer indicating the HTML width of the input area for this control. The<br />
default size is 20.<br />
<strong>Using</strong> <strong>Zen</strong> 179
<strong>Zen</strong> Controls<br />
12.5.3 <br />
The component displays a row of color choices. The user can click on a color to select<br />
it. offers a simple alternative to the complex palette in . A <strong>Zen</strong> <br />
looks like this:<br />
has the following attributes.<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
colorList<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include the value, a string that identifies the most<br />
recently selected CSS color value.<br />
Comma-separated list of CSS color values to display within the control,<br />
from left to right. The default colorList value is as shown in the example<br />
above:<br />
",black,gray,darkblue,darkred,darkgreen,blue,red,green,yellow,orange,plum,purple,white"<br />
12.5.4 <br />
The control displays a concise row of radio buttons to show a set of choices. A <strong>Zen</strong><br />
looks like this:<br />
12.5.4.1 Logical and Display Values<br />
The simplest way to define a is to provide a valueList for the user to choose from. You can<br />
also add a corresponding displayList for the user to see. These attributes are as follows.<br />
180 <strong>Using</strong> <strong>Zen</strong>
Simple Choices<br />
Attribute<br />
displayList<br />
valueList<br />
Description<br />
(Optional) A comma-separated list of choices to display for this .<br />
displayList applies only if a valueList is defined. Display values may differ<br />
from the actual logical values.<br />
The displayList attribute has its ZENLOCALIZE datatype parameter set to<br />
1 (true). This means it is easy to localize the text into other languages, but<br />
you must ensure that any translated displayList string remains a commaseparated<br />
list. See <strong>Zen</strong> Localization.<br />
Comma-separated list of logical values for the . One of these<br />
logical values becomes the value when the user clicks on the<br />
corresponding button.<br />
You could produce the above sample with the following statement in XData Contents:<br />
<br />
12.5.4.2 Query Attributes<br />
A can indicate a data source for its buttons via an SQL query. offers a number<br />
of attributes for this purpose. When you use this technique, the columns returned by the query determine<br />
what is displayed in the as follows:<br />
• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />
display values within the radioSet.<br />
• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />
value and the contents of the second column supply the display values.<br />
provides the following attributes to support using a query.<br />
<strong>Using</strong> <strong>Zen</strong> 181
<strong>Zen</strong> Controls<br />
Attribute<br />
maxRows<br />
queryClass<br />
queryName<br />
sql<br />
Description<br />
(Optional) If a query is used to provide data, this is the maximum number<br />
of items that will be displayed. The default is 500.<br />
(Optional) The name of the class containing the query. You must also<br />
provide a value for queryName.<br />
(Optional) The name of the class query that will provide the %ResultSet for<br />
this . You must also provide a value for queryClass.<br />
(Optional) Server-side SQL query to get contents of the .<br />
This attribute has the underlying data type %ZEN.Datatype.sql. This means<br />
it cannot be accessed from the client. Its value is encrypted (using the<br />
current session key) when it is sent to the client. If this value is returned to<br />
the server, it is automatically decrypted. This makes it possible to place<br />
sensitive data on the client for future processing on the server, without letting<br />
a user view this data.<br />
For additional details, plus examples, see the <strong>Zen</strong> Tables chapter as follows:<br />
• How to use query attributes with :<br />
- Data Sources (maxRows)<br />
- Specifying an SQL Query (sql)<br />
- Referencing a Class Query (queryClass, queryName)<br />
• How to provide elements within :<br />
- Query Parameters<br />
12.5.4.3 General Attributes<br />
has the following general-purpose attributes.<br />
182 <strong>Using</strong> <strong>Zen</strong>
Simple Choices<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
captionClass<br />
emptyCaption<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include the value, which is the logical value of the<br />
currently selected button in the set.<br />
(Optional) Name of the CSS style class to apply to captions for radio<br />
buttons within this . The default is the built-in CSS style class<br />
radioSetCaption.<br />
The default caption to use for any buttons within this that<br />
have no display value. If you do not specify an emptyCaption, the default<br />
caption is:<br />
None<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
titleList<br />
Comma-separated list of tooltip text strings for each radio button in the<br />
.<br />
The titleList attribute has its ZENLOCALIZE datatype parameter set to<br />
1 (true). This means it is easy to localize its text into other languages.<br />
See <strong>Zen</strong> Localization.<br />
12.5.5 <br />
The <strong>Zen</strong> control is a wrapper around the HTML element<br />
with some enhanced capabilities. The <strong>Zen</strong> control has the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 183
<strong>Zen</strong> Controls<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include:<br />
• name (not id) establishes the association between radio buttons.You<br />
create a set of associated radio buttons by adding <br />
elements to XData Contents and assigning the same name value to<br />
each that in the set.<br />
• At runtime, value always contains the optionValue of the button in the<br />
set that is currently selected. As soon as the user selects one of the<br />
buttons in the set, <strong>Zen</strong> resets the value of every button in this set to<br />
the optionValue of the selected button. This makes it very easy for<br />
you to determine which button in the set is currently selected, by<br />
programmatically checking the value property of any button in the set.<br />
caption<br />
captionClass<br />
optionValue<br />
The caption text for this . Each button in the set needs a<br />
caption so that the user can distinguish between the choices.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text into<br />
other languages. See <strong>Zen</strong> Localization.<br />
The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
(Optional) Name of the CSS style class to apply to the captions for this<br />
. The default is the built-in CSS style class<br />
radioButtonCaption.<br />
Defines a logical value to associate with this . The<br />
optionValue for each radio button in the set must be unique.<br />
The optionValue can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
12.6 Lists<br />
<strong>Zen</strong> offers the following list controls:<br />
• — You display a list box by using the <strong>Zen</strong> wrapper for HTML <br />
• — You define a <strong>Zen</strong> list box with fixed options for the user to choose<br />
184 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
• — <strong>Zen</strong> generates a list box for you, based on a runtime query<br />
• — You define a <strong>Zen</strong> combo box with fixed options for the user to choose<br />
• — <strong>Zen</strong> generates a combo box for you, based on a runtime query<br />
A list box offers a simple list of options, but a combo box has two parts:<br />
• A text control that displays the current value of the control<br />
• A dropdown list that displays a set of options for the user to select<br />
A combo box dropdown list may appear when activated by the user, for example when the user clicks<br />
the button beside the control. There are a number of ways to reveal the dropdown list. The user can<br />
click on an image or button, or the list can simply appear when the cursor has hovered over the control<br />
for some length of time. You can specify these details when you place a list control on a <strong>Zen</strong> form, or<br />
simply use the default characteristics that <strong>Zen</strong> provides.<br />
12.6.1 <br />
The <strong>Zen</strong> control is a wrapper around the HTML element. <strong>Zen</strong> produces a<br />
list from which the user can select an item.<br />
12.6.1.1 Logical and Display Values<br />
The simplest way to define a list is to provide a valueList for the user to choose from. You<br />
can also add a corresponding displayList for the user to see. These attributes are as follows.<br />
<strong>Using</strong> <strong>Zen</strong> 185
<strong>Zen</strong> Controls<br />
Attribute<br />
displayList<br />
showEmpty<br />
valueList<br />
Description<br />
(Optional) A comma-separated list of values to display for this list.<br />
displayList applies only if a valueList is defined. Display values may differ<br />
from the actual logical values.<br />
The displayList attribute has its ZENLOCALIZE datatype parameter set to<br />
1 (true). This means it is easy to localize the text into other languages, but<br />
you must ensure that any translated displayList string remains a commaseparated<br />
list. See <strong>Zen</strong> Localization.<br />
When true, provides an extra blank row (value "") at the top of its<br />
dropdown box. Typically, this is the desired behavior, so the default<br />
showEmpty value is true.<br />
showEmpty has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value "true" or "false" in XData Contents, 1 or 0 in server-side code, true or<br />
false in client-side code. See Datatype Classes.<br />
Comma-separated list of logical values for the list.<br />
12.6.1.2 Query Attributes<br />
A <strong>Zen</strong> control can indicate a data source for its list via an SQL query. <strong>Zen</strong> offers a<br />
number of attributes for this purpose. When you use this technique, the columns returned by the SQL<br />
query determine what is displayed within the list as follows:<br />
• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />
display values within the dropdown.<br />
• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />
value and the contents of the second column supply the display values.<br />
<strong>Zen</strong> provides the following attributes to support using a query.<br />
186 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
Attribute<br />
maxRows<br />
queryClass<br />
queryName<br />
sql<br />
Description<br />
(Optional) If a query is used to provide data, this is the maximum number<br />
of items that will be displayed. The default is 500.<br />
(Optional) The name of the class containing the query. You must also<br />
provide a value for queryName.<br />
(Optional) The name of the class query that will provide the %ResultSet for<br />
this list. You must also provide a value for queryClass.<br />
(Optional) Server-side SQL query to get contents of the list.<br />
This attribute has the underlying data type %ZEN.Datatype.sql. This means<br />
it cannot be accessed from the client. Its value is encrypted (using the<br />
current session key) when it is sent to the client. If this value is returned to<br />
the server, it is automatically decrypted. This makes it possible to place<br />
sensitive data on the client for future processing on the server, without letting<br />
a user view this data.<br />
For additional details, plus examples, see the <strong>Zen</strong> Tables chapter as follows:<br />
• How to use query attributes with :<br />
- Data Sources (maxRows)<br />
- Specifying an SQL Query (sql)<br />
- Referencing a Class Query (queryClass, queryName)<br />
• How to provide elements within :<br />
- Query Parameters<br />
12.6.1.3 General Attributes<br />
<strong>Zen</strong> has the following general-purpose attributes.<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
size<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.These<br />
include the value, a string indicating the user’s current choice from<br />
the list.<br />
Number of rows to display in the list.<br />
<strong>Using</strong> <strong>Zen</strong> 187
<strong>Zen</strong> Controls<br />
12.6.2 <br />
The <strong>Zen</strong> control displays a list box, whose options may be individually formatted.<br />
The <strong>Zen</strong> control is not a wrapper around HTML . The <strong>Zen</strong> is implemented<br />
using HTML primitives. This allows the to provide functionality not available with HTML<br />
, including:<br />
• Greater control over the contents of the list<br />
• Solutions to problems with Internet Explorer interoperating with CSS<br />
12.6.2.1 Options<br />
The simplest way to define a <strong>Zen</strong> list box is to provide a set of elements inside a <br />
component. The following statements produce the sample list box shown above:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The element is the XML projection of the %ZEN.Auxiliary.option class and supports the<br />
attributes described in the following table.<br />
188 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
Attribute<br />
style<br />
text<br />
value<br />
Description<br />
(Optional) CSS style to apply to this option.<br />
Display value. This is the text that the user sees in the list box.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
Logical value. This is the value that <strong>Zen</strong> submits for this control when it<br />
submits the form. You must always provide both text and value for each<br />
option in the list.<br />
When you work with %ZEN.Component.listBox programmatically, you work with elements<br />
as members of the options property, a list collection. Each in the becomes a<br />
member of the options collection, associated with an ordinal position: 1, 2, 3, etc.<br />
12.6.2.2 General Attributes<br />
and have the following attributes in common.<br />
List Box Component Attributes<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
listHeight<br />
listWidth<br />
selectedIndex<br />
text<br />
Description<br />
A list box has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These include the list box value, a string of text that represents the<br />
currently selected logical value of the control.<br />
CSS length value. If defined, listHeight overrides the default height of<br />
the list box window, which is 250px.<br />
CSS length value. If defined, listWidth overrides the default width of<br />
the list box window, which is 250px.<br />
0-based index of the currently selected option in the list box.The default<br />
selectedIndex is –1 (nothing is selected).<br />
The display text that corresponds to the currently selected item. Do not<br />
access the text value directly; use getProperty('text') instead.<br />
12.6.3 <br />
A is a specialized type of that presents the user with a list of options obtained<br />
at runtime via an SQL query. Unlike , does not allow you to specify <br />
elements or to set styles for individual options in the list. This is because uses a query<br />
<strong>Using</strong> <strong>Zen</strong> 189
<strong>Zen</strong> Controls<br />
to obtain a dynamic list of options. There are no statically defined options in a , so there<br />
are no elements.<br />
A with an item selected looks like this:<br />
12.6.3.1 Query Attributes<br />
The provides its list by creating, executing, and fetching from a %ResultSet object on<br />
the server. You can specify how to create this %ResultSet object using the attributes that the <br />
inherits from its parent class %ZEN.Auxiliary.QuerySource.<br />
The columns returned by the SQL query determine what is displayed within the list,<br />
as follows:<br />
• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />
display values within the dropdown.<br />
• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />
value and the contents of the second column supply the display values.<br />
The following topics in the chapter <strong>Zen</strong> Tables describe how to use QuerySource attributes:<br />
• How to indicate a data source for a :<br />
- Data Sources (maxRows)<br />
- Specifying an SQL Query (sql)<br />
- Generating an SQL Query ( groupByClause, orderByClause, tableName, whereClause)<br />
190 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
- Referencing a Class Query (queryClass, queryName)<br />
- <strong>Using</strong> a Callback Method (onCreateResultSet, onExecuteResultSet)<br />
• How to provide elements within :<br />
- Query Parameters<br />
12.6.3.2 Display and Logical Values<br />
has an sqlLookup attribute that works in the same way as for . See the<br />
discussion of logical and display values later in this chapter.<br />
12.6.3.3 General Attributes<br />
has the following general-purpose attributes.<br />
Attribute<br />
List box<br />
attributes<br />
Data source<br />
attributes<br />
OnDrawItem<br />
itemCount<br />
sqlLookup<br />
Description<br />
has the same general-purpose attributes as the<br />
component. cannot contain any <br />
elements.<br />
has the same attributes as for specifying<br />
a data source and query parameters.<br />
(Optional) Name of a server-side callback method that is called for<br />
each item in the list before it is displayed. This callback receives the<br />
logical and display values for the current item. It returns the HTML<br />
that is to be displayed within the cell for the given item. OnDrawItem<br />
must be the name of a server-only method in the page class that<br />
contains this list box.<br />
(Read-only) Number of options within the list. This is calculated when<br />
the query for this component is run.<br />
An optional SQL statement that is used under particular conditions.<br />
See the discussion of logical and display values later<br />
in this chapter.<br />
12.6.4 <br />
The <strong>Zen</strong> provides a text field with a dropdown list below it:<br />
<strong>Using</strong> <strong>Zen</strong> 191
<strong>Zen</strong> Controls<br />
The <strong>Zen</strong> control is not a wrapper around HTML . The <strong>Zen</strong> is<br />
implemented using HTML primitives. This allows the to provide functionality not<br />
available with HTML , including:<br />
• The ability to edit values in the text box<br />
• Greater control over the contents of the list<br />
• Solutions to problems with Internet Explorer interoperating with CSS<br />
12.6.4.1 Logical and Display Values<br />
The simplest way to define a is to provide a valueList for the user to choose from. You<br />
can also add a corresponding displayList for the user to see. These attributes are as follows.<br />
Attribute<br />
displayList<br />
valueList<br />
Description<br />
A comma-separated list of values to display for the list in this combo box.<br />
displayList applies only if a valueList is defined. Display values may differ<br />
from the actual logical values.<br />
The displayList attribute has its ZENLOCALIZE datatype parameter set to<br />
1 (true). This means it is easy to localize the text into other languages, but<br />
you must ensure that any translated displayList string remains a commaseparated<br />
list. See <strong>Zen</strong> Localization.<br />
valueList overrides any elements provided within the <br />
(see the discussion following this table).The valueList is a comma-separated<br />
list of logical values for the dropdown list in this . If you provide<br />
a valueList, you must also provide a displayList.<br />
12.6.4.2 Options<br />
Alternatively, you can define a by providing a set of elements inside a <br />
component. is more flexible than a valueList and displayList because it allows you<br />
to apply a CSS style to each of the list entries individually. For example:<br />
192 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
<br />
<br />
<br />
<br />
The element is the XML projection of the %ZEN.Auxiliary.option class and supports the<br />
attributes described in the following table.<br />
Attribute<br />
style<br />
text<br />
value<br />
Description<br />
(Optional) CSS style to apply to this option.<br />
Display value. This is the text that the user sees in the combo box.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
Logical value. This is the value that <strong>Zen</strong> submits for this control when it<br />
submits the form. You must always provide both text and value for each<br />
option in the combo box.<br />
When you work with %ZEN.Component.combobox programmatically, you work with elements<br />
as members of the options property, a list collection. Each in the becomes a<br />
member of the options collection, associated with an ordinal position: 1, 2, 3, etc.<br />
12.6.4.3 General Attributes<br />
and have the following attributes in common.<br />
Combo Box Component Attributes<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
buttonCaption<br />
buttonImage<br />
buttonImageDown<br />
Description<br />
A combo box has the same general-purpose attributes as any <strong>Zen</strong><br />
control. These include the combo box value, a string of text that<br />
represents the currently selected logical value of the control.<br />
Caption used for the button when the comboType is "button".<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its<br />
text into other languages. See <strong>Zen</strong> Localization.<br />
URI of the image to display for the combo button in its normal state.<br />
URI of image to display for the combo button in its down (pressed)<br />
state.<br />
<strong>Using</strong> <strong>Zen</strong> 193
<strong>Zen</strong> Controls<br />
Attribute<br />
buttonTitle<br />
comboType<br />
Description<br />
Popup title used for the dropdown button when comboType is "button"<br />
or "image".<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its<br />
text into other languages. See <strong>Zen</strong> Localization.<br />
How the dropdown box is activated for the combobox:<br />
• "image" indicates that a user-clickable image should be displayed<br />
next to the combo box text box. This is the default.<br />
• "button" indicates that a button should be displayed next to the<br />
combo box text box.<br />
• "timer" indicates that the dropdown should appear shortly after<br />
the user enters a value within the combo box text box.<br />
delay<br />
dropdownHeight<br />
dropdownWidth<br />
editable<br />
maxlength<br />
scrollIntoView<br />
When comboType is "timer", delay specifies how many milliseconds<br />
to wait after user finishes typing before showing the dropdown. The<br />
default is 250 milliseconds.<br />
CSS length value. If defined, dropdownHeight overrides the default<br />
height of the dropdown window, which is 250px.<br />
CSS length value. If defined, dropdownHeight overrides the default<br />
width of the dropdown window, which is 250px.<br />
If true, a user can directly edit the value within the input box as if it<br />
were a text field. The default is false.<br />
editable has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
Maximum number of characters that the user may enter within this<br />
control.<br />
If true, <strong>Zen</strong> uses the JavaScript scrollIntoView function to try and<br />
make visible the currently selected item within the dropdown.<br />
scrollIntoView has the underlying data type %ZEN.Datatype.boolean.<br />
It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
194 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
Attribute<br />
selectedIndex<br />
size<br />
unrestricted<br />
Description<br />
0-based index of the currently selected option in the dropdown list.<br />
The default selectedIndex is –1 (nothing is selected).<br />
HTML width of the text input area for this control. The default size is<br />
20.<br />
If true, and if editable is also true, values entered by the user may<br />
be used as the value of the control. If false, the value is restricted to<br />
one of the choices within the dropdown list. The default is false.<br />
unrestricted has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
%ZEN.Component.combobox is a subclass of the %ZEN.Component.text control. This means you can<br />
use the various methods defined by the text control to manipulate the text box portion of a <br />
or .<br />
12.6.5 <br />
A is a specialized type of that presents the user with a list of options<br />
obtained at runtime via an SQL query. Unlike , does not allow you to<br />
specify elements or to set styles for individual options in the list. This is because <br />
uses a query to obtain a dynamic list of options. There are no statically defined options in a , so there are no elements.<br />
A with text entered for a search looks like this:<br />
<strong>Using</strong> <strong>Zen</strong> 195
<strong>Zen</strong> Controls<br />
12.6.5.1 Query Attributes<br />
The provides its list by creating, executing, and fetching from a %ResultSet object on<br />
the server. You can specify how to create this %ResultSet object using the attributes that the inherits from its parent class %ZEN.Auxiliary.QuerySource.<br />
The columns returned by the SQL query determine what is displayed within the list, as<br />
follows:<br />
• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />
display values within the dropdown list.<br />
• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />
value and the contents of the second column supply the display values. You can change which<br />
columns are used to provide the logical and display values using the valueColumn and<br />
choiceColumn attributes.<br />
• If the %ResultSet has more than two columns, you can use the displayColumns and columnHeaders<br />
attributes to specify that the dropdown should display multiple columns.<br />
The following topics in the chapter <strong>Zen</strong> Tables describe how to use QuerySource attributes:<br />
• How to indicate a data source for a :<br />
- Data Sources (maxRows)<br />
- Specifying an SQL Query (sql)<br />
- Generating an SQL Query ( groupByClause, orderByClause, tableName, whereClause)<br />
- Referencing a Class Query (queryClass, queryName)<br />
- <strong>Using</strong> a Callback Method (onCreateResultSet, onExecuteResultSet)<br />
• How to provide elements within :<br />
- Query Parameters<br />
12.6.5.2 Query Parameters<br />
The query used to provide the contents of the dropdown list may contain one or more<br />
runtime parameters, such as:<br />
WHERE Name %STARTSWITH <br />
Values for query parameters can be provided in one of the following ways:<br />
• The can define a list, as described in the <strong>Zen</strong> Tables topic Query<br />
Parameters. It is possible to modify the values of these parameters programmatically from the<br />
196 <strong>Using</strong> <strong>Zen</strong>
client; if so, be sure to call the %ZEN.Component.dataCombo method clearCache so that the<br />
dropdown query is re-executed with the new values.<br />
Lists<br />
• If searchKeyLen is set to a non-zero value, and editable is true, then the first searchKeyLen<br />
number of characters in the current contents of the combo input box are used as the value for the<br />
first query parameter. In this case, the first member of the parameters list is ignored. Any additional<br />
query parameters are provided from the parameters list, with one exception: if any parameter value<br />
is equal to "", then the current search key value (that is, the value used for the first parameter)<br />
will also be used for this query parameter.<br />
12.6.5.3 Logical and Display Values<br />
Any list box or combo box has two current values:<br />
• Logical value — its actual stored value as returned by the getValue method<br />
• Display value — the value that the user views and selects in the dropdown list<br />
The <strong>Zen</strong> controls , , and provide a fixed list of logical and display<br />
values. When an application sets the value of one of these controls, it is simple for the control to<br />
identify which display value is associated with the new logical value.<br />
and acquire their values dynamically, so additional steps are needed to<br />
achieve the same result. When an application sets the local value of a control, internally<br />
the tries to find the display value that best matches this logical value. This works differently<br />
on the server and client:<br />
• On the server, executes the SQL statement defined by its sqlLookup attribute<br />
• On the client, the first looks for a match for a given logical value within its dropdown<br />
cache. If it does not find a match, it calls a server method to execute the sqlLookup query.<br />
For example, suppose you want to define a to show a set of Customer names; the display<br />
value will be Name while the logical value will be the ID of the Customer. To do this you define a<br />
with two SQL statements, as follows:<br />
<br />
This definition has the following effects:<br />
1. The query defined by sql is called whenever the dropdown list is displayed. It provides a set of<br />
logical (ID) and display (Name) values. The parameter gets its value from the contents of the<br />
text field at the time when the dropdown appears; the value of searchKeyLen<br />
<strong>Using</strong> <strong>Zen</strong> 197
<strong>Zen</strong> Controls<br />
indicates that up to the first 10 characters will be used. The remembers the results<br />
of the last query in a local cache.<br />
2. The query defined by sqlLookup is used to find a specific display value for a specific logical value.<br />
When this query is executed, the logical value of the control is provided as a query input parameter<br />
(a within the SQL statement). This query must return a single row containing a display value.<br />
3. The sqlLookup query is also executed when the application tries to set the logical value of this<br />
at runtime, and the answer is not in the cache from item 1.<br />
The sqlLookup attribute has the underlying data type %ZEN.Datatype.sql. This means it cannot be<br />
accessed from the client. Its value is encrypted (using the current session key) when it is sent to the<br />
client. If this value is returned to the server, it is automatically decrypted. This makes it possible to<br />
place sensitive data on the client for future processing on the server, without letting a user view this<br />
data.<br />
12.6.5.4 General Attributes<br />
has the following general-purpose attributes.<br />
Attribute<br />
Combo box<br />
attributes<br />
Data source<br />
attributes<br />
auxColumn<br />
choiceColumn<br />
Description<br />
has the same general-purpose attributes as the<br />
component. There can be no statically defined options,<br />
so does not support the displayList and valueList<br />
attributes. A also cannot contain any elements.<br />
has the same attributes as for specifying<br />
a data source and query parameters.<br />
If there are multiple data columns displayed in the dropdown list,<br />
auxColumn is the 1-based column number of the column that will<br />
provide an additional auxiliary value for this control. auxColumn<br />
provides a way to supply an additional value that is not the display or<br />
logical value. If the auxColumn value is not a valid column number,<br />
no auxiliary data is provided. The default auxColumn value is 0.<br />
If there are multiple data columns displayed within the dropdown list,<br />
choiceColumn is the 1-based column number of the column that will<br />
provide the display value for this control. The default choiceColumn<br />
value is 2. If the supplied choiceColumn value is greater than the<br />
number of columns in the query, the second column is used.<br />
198 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
Attribute<br />
columnHeaders<br />
displayColumns<br />
loadingMessage<br />
Description<br />
If defined, columnHeaders is a comma-separated list of column<br />
headers to display in the dropdown list.<br />
The columnHeaders attribute has its ZENLOCALIZE datatype<br />
parameter set to 1 (true). This means it is easy to localize its text into<br />
other languages. See <strong>Zen</strong> Localization.<br />
(Optional) If there are multiple data columns in the %ResultSet for the<br />
, displayColumns can provide a comma-separated list<br />
of 1–based column numbers. This list identifies which columns out of<br />
the %ResultSet should be displayed.<br />
This message is temporarily displayed while a server-side query is<br />
running to populate the list. The default is:<br />
$$$Text("Loading...","%ZEN");<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
multiColumn<br />
searchKeyLen<br />
showEmpty<br />
If true, and if the result set contains more than 2 columns, display<br />
multiple columns in the dropdown box. The default is true.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
If non-zero, searchKeyLen is the maximum number of search<br />
characters for <strong>Zen</strong> to take from the combo input box and pass as a<br />
parameter to the SQL query that provides the contents of the dropdown<br />
list. If zero, the contents of the input box are not used as a query<br />
parameter. The default is 0.<br />
When true, the outputs an extra blank row (value "") at<br />
the top of its dropdown box. Typically, this is the desired behavior, so<br />
the default showEmpty value is true. Regardless of the showEmpty<br />
value, this blank row does not display when the has its<br />
control component attribute required set to true.<br />
showEmpty has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />
code, true or false in client-side code. See Datatype Classes.<br />
<strong>Using</strong> <strong>Zen</strong> 199
<strong>Zen</strong> Controls<br />
Attribute<br />
sqlLookup<br />
valueColumn<br />
Description<br />
An optional SQL statement that is used under particular conditions.<br />
See Logical and Display Values, above.<br />
(Optional) If there are multiple data columns in the %ResultSet for the<br />
, valueColumn identifies the 1-based column number<br />
of the column that will provide the logical value for this control. The<br />
default valueColumn is 1. If the supplied valueColumn value is greater<br />
than the number of columns in the query, the first column is used.<br />
12.6.5.5 Display Sequence<br />
If you are interested in details of how <strong>Zen</strong> displays the , the following table lists the<br />
internal events in sequence, organized by user viewpoint, browser-based execution, and server-side<br />
execution. Most of the communication details are handled by the CSP technology underlying <strong>Zen</strong>. For<br />
background information, see the chapter <strong>Zen</strong> Client and Server.<br />
200 <strong>Using</strong> <strong>Zen</strong>
Lists<br />
Display Sequence<br />
User Viewpoint<br />
In the Browser<br />
On the Server<br />
1<br />
Select the dropdown<br />
2<br />
3<br />
Dropdown is activated<br />
Send hyperevent to the<br />
server to execute SQL<br />
4<br />
5<br />
Receive hyperevent to<br />
execute SQL<br />
Send hyperevent response<br />
(consisting of JavaScript code)<br />
to populate the dropdown unit<br />
6<br />
Server fills the dropdown<br />
list<br />
7<br />
8<br />
List fills with items<br />
User selects an item<br />
9<br />
10<br />
11<br />
Dropdown item is selected<br />
Call client-side select event<br />
handler<br />
Send hyperevent to the<br />
server to start a<br />
<strong>Zen</strong>Method<br />
12<br />
13<br />
14<br />
Receive hyperevent to start<br />
<strong>Zen</strong>Method<br />
Update server-side DOM<br />
Send hyperevent response<br />
(consisting of JavaScript code)<br />
to synchronize client DOM<br />
with server DOM<br />
15<br />
Update client-side DOM to<br />
reflect changes made on<br />
the server during the<br />
<strong>Zen</strong>Method<br />
<strong>Using</strong> <strong>Zen</strong> 201
<strong>Zen</strong> Controls<br />
16<br />
User Viewpoint<br />
In the Browser<br />
Update visual presentation<br />
of DOM-bound<br />
components to match new<br />
client-side DOM<br />
On the Server<br />
17<br />
Form fields get filled<br />
in based on the<br />
selection<br />
12.7 Calendars<br />
<strong>Zen</strong> offers the following date selection controls:<br />
• — The user selects dates from a popup calendar<br />
• — The user can enter text or select a date<br />
12.7.1 <br />
The component displays a navigable calendar, one month at a time. The user can view and<br />
select dates from this calendar. A initially displays with the current date highlighted in<br />
bold (7 in the example below) and the currently selected date in bold with a yellow background color<br />
(14 in the example below). A <strong>Zen</strong> looks like this:<br />
has the following attributes.<br />
202 <strong>Using</strong> <strong>Zen</strong>
Calendars<br />
Attribute<br />
Control<br />
component<br />
attributes<br />
dayList<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> control.<br />
These attributes include the value, a string in the format<br />
YYYY-MM-DD (it has the datatype %Timestamp on the server).<br />
Comma-separated list of day abbreviations to show at the top of the<br />
calendar. The default value is:<br />
$$$Text("S,M,T,W,T,F,S");<br />
The dayList attribute has its ZENLOCALIZE datatype parameter set to<br />
1 (true). This means it is easy to localize its text into other languages<br />
and permits use of the $$$Text macro as shown in the default dayList<br />
value. See <strong>Zen</strong> Localization.<br />
endYear<br />
firstDayOfWeek<br />
fixedMonth<br />
gapWidth<br />
maxDate<br />
Four-digit end year number for the year selector in the calendar. If not<br />
defined, the default is the year portion of maxDate, if defined. Otherwise,<br />
the default endYear is 30 years from now.<br />
Number (Sunday=0, Saturday=6) that specifies which day of the week<br />
is displayed as the starting day of the week. The default is 0 (Sunday).<br />
If true, this calendar displays a single month and provides no way for<br />
the user to change month and year. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
HTML length value giving the size of the gap between the month and<br />
year indicators at the top of the calendar. Setting this provides a way<br />
to adjust the width of the calendar.The above example uses the default<br />
of 40px.<br />
(Optional) String in the format YYYY-MM-DD (datatype %Timestamp on<br />
the server). If specified, this is the latest date that the will<br />
accept as its value. The maxDate value does not affect which years<br />
are displayed by the calendar unless endYear is omitted.<br />
The value supplied for maxDate can be a literal string, or it can contain<br />
a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
<strong>Using</strong> <strong>Zen</strong> 203
<strong>Zen</strong> Controls<br />
Attribute<br />
minDate<br />
month<br />
monthList<br />
Description<br />
(Optional) String in the format YYYY-MM-DD (datatype %Timestamp on<br />
the server). If specified, this is the earliest date that the will<br />
accept as its value. The minDate value does not affect which years are<br />
displayed by the calendar unless startYear is omitted.<br />
The value supplied for minDate can be a literal string, or it can contain<br />
a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
Number (January=1, December=12) that specifies which month of the<br />
year is currently displayed by the calendar. This is not the same as the<br />
current value, which includes a day and year, which can<br />
include time, and whose month may be different.<br />
Comma-separated list of month names to display in the list of months<br />
that the user can choose from the calendar. The default value is:<br />
$$$Text("January,February,March,April,May,June,July,August,September,October,November,December");<br />
monthList has its ZENLOCALIZE datatype parameter set to 1 (true).<br />
This means it is easy to localize its text into other languages and permits<br />
use of the $$$Text macro as shown in the default monthList value. See<br />
<strong>Zen</strong> Localization.<br />
showTime<br />
startYear<br />
If true, this component displays a text entry field below the main calendar.<br />
In the example above, showTime is true. The default is false.<br />
The user can enter a time of day in the showTime field using the 24–hour<br />
time format HH:MM:SS. When the form is submitted, the <br />
value accepts both date and time values in the following ODBC/JDBC<br />
timestamp format: YYYY-MM-DD HH:MM:SS<br />
showTime has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
Four-digit start year number for the year selector in the calendar. If not<br />
defined, the default is the year portion of minDate, if defined. Otherwise,<br />
the default startYear is 10 years ago.<br />
204 <strong>Using</strong> <strong>Zen</strong>
Calendars<br />
Attribute<br />
timeCaption<br />
Description<br />
Caption text for the showTime field. The default value is shown in the<br />
example above:<br />
$$$Text("Time:");<br />
timeCaption has its ZENLOCALIZE datatype parameter set to 1 (true).<br />
This means it is easy to localize its text into other languages and permits<br />
use of the $$$Text macro as shown in the default timeCaption value.<br />
See <strong>Zen</strong> Localization.<br />
year<br />
Four-digit number that specifies which year is currently displayed by<br />
the calendar. This is not the same as the current value,<br />
which includes a day and month, which can include time, and whose<br />
year may be different.<br />
12.7.2 <br />
The control is essentially a combo box. It displays a text box as well as a button that, when<br />
pressed, displays a popup calendar. When the user enters a value into the text area of this control, <strong>Zen</strong><br />
either converts this value into the closest matching date value, or it displays an invalid date message.<br />
Note:<br />
always normalizes the date format to YYYY-MM-DD. There is no alternate<br />
format for this built-in control.<br />
A <strong>Zen</strong> component looks like this:<br />
has the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 205
<strong>Zen</strong> Controls<br />
Attribute<br />
Control component<br />
attributes<br />
invalidDateMessage<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong><br />
control. These attributes include the value, a string in<br />
the format YYYY-MM-DD (it has the datatype %Timestamp on the<br />
server).<br />
Message displayed by control when the date entered by the user<br />
fails validation. The default is:<br />
$$$Text("Invalid Date","%ZEN");<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption.This makes it easy to localize<br />
its text into other languages. See <strong>Zen</strong> Localization.<br />
maxDate<br />
minDate<br />
showTime<br />
(Optional) String in the format YYYY-MM-DD (datatype %Timestamp<br />
on the server). If specified, this is the latest date that the <br />
will accept as its value. The maxDate value does not affect which<br />
years are displayed by the calendar unless endYear is omitted.<br />
The value supplied for maxDate can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
(Optional) String in the format YYYY-MM-DD (datatype %Timestamp<br />
on the server). If specified, this is the earliest date that the <br />
will accept as its value. The minDate value does not affect<br />
which years are displayed by the calendar unless startYear is<br />
omitted.<br />
The value supplied for minDate can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
If true, this component displays a text entry field below the main<br />
calendar. In the example above, showTime is true. The default is<br />
false.<br />
The user can enter a time of day in the showTime field using the<br />
24–hour time format HH:MM:SS. When the form is submitted, the<br />
value accepts both date and time values in the following<br />
ODBC/JDBC timestamp format: YYYY-MM-DD HH:MM:SS<br />
showTime has the underlying data type %ZEN.Datatype.boolean. It<br />
has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />
code, true or false in client-side code. See Datatype Classes.<br />
206 <strong>Using</strong> <strong>Zen</strong>
Hidden Items<br />
Attribute<br />
size<br />
Description<br />
HTML width of the text input area for this control. The default is 15.<br />
Note:<br />
When you set the value property of a dateText control programmatically, this bypasses the<br />
date matching function that <strong>Zen</strong> provides when the user sets the date by typing text in the<br />
input field.<br />
12.8 Hidden Items<br />
The <strong>Zen</strong> control is a wrapper around the HTML element. The<br />
control is present in the form, and has a value associated with it, but is never visible to the<br />
user. The value can be changed programmatically on the client or server side. When the form is submitted,<br />
the values of any controls are submitted along with all the others.<br />
has the same general-purpose attributes as any <strong>Zen</strong> control. It has no additional attributes.<br />
12.9 Spreadsheet<br />
The control displays a two-dimensional, editable grid, similar to a spreadsheet. When the<br />
user clicks in a cell, an edit control appears in the cell and the user can edit the cell contents. The user<br />
presses Enter to save changes. A with a newly-edited cell looks like this:<br />
You can create a in one of the following ways:<br />
• Specify a data set, rows, and columns as described below<br />
• Associate the with a Model View Controller<br />
<strong>Using</strong> <strong>Zen</strong> 207
<strong>Zen</strong> Controls<br />
12.9.1 Data Set<br />
The data displayed within the is supplied by a %ZEN.Auxiliary.dataSet object. dataSet is<br />
a special data container object that is used to define one-, two-, or three-dimensional data in a form<br />
that can be easily transported between the server and client.<br />
When a object is first created, it automatically creates a two–dimensional dataSet object<br />
with the number of rows (dimension 1) and columns (dimension 2) specified by the number of<br />
and entries within the definition in XData Contents. The following<br />
example specifies four rows and four columns for the initial dataSet object:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
An application can change the size and contents of the initial dataSet object by defining a server-side<br />
callback method. You can specify the name of this callback method using the <br />
OnCreateDataSet attribute, as in the example above. The OnCreateDataSet value must be the name<br />
of a server-side callback method defined within the page class that contains the control.<br />
In the above example, this method name is CreateDS. The OnCreateDataSet callback method is called<br />
once, when the object is first created on the server and before the is first<br />
displayed.<br />
The signature of the OnCreateDataSet callback method must look like this:<br />
Method CreateDS(<br />
pGrid As %ZEN.Component.dynaGrid,<br />
pDataSet As %ZEN.Auxiliary.dataSet) As %Status<br />
Where:<br />
• pGrid is the dynaGrid object that is invoking the callback.<br />
• pDataSet is the dataSet object associated with the dynaGrid object.<br />
• The method returns a %Status value indicating success or failure.<br />
Typically a OnCreateDataSet callback method looks like this:<br />
208 <strong>Using</strong> <strong>Zen</strong>
Spreadsheet<br />
Method CreateDS(<br />
pGrid As %ZEN.Component.dynaGrid,<br />
pDataSet As %ZEN.Auxiliary.dataSet) As %Status<br />
{<br />
// make sure dataSet is cleared out<br />
Do pDataSet.%Clear()<br />
// fill in contents of dataSet<br />
// This is a 2-D data structure<br />
// row labels (dimension 1)<br />
Do pDataSet.%SetLabel("Boston",1,1)<br />
Do pDataSet.%SetLabel("New York",2,1)<br />
Do pDataSet.%SetLabel("Chicago",3,1)<br />
Do pDataSet.%SetLabel("Miami",4,1)<br />
// column labels (dimension 2)<br />
Do pDataSet.%SetLabel("Cars",1,2)<br />
Do pDataSet.%SetLabel("Trucks",2,2)<br />
Do pDataSet.%SetLabel("Trains",3,2)<br />
Do pDataSet.%SetLabel("Planes",4,2)<br />
// get size of dataSet<br />
Set rows = pDataSet.%GetDimSize(1)<br />
Set cols = pDataSet.%GetDimSize(2)<br />
// fill in initial data values<br />
For r=1:1:rows {<br />
For c=1:1:cols {<br />
Set value = 0<br />
Do pDataSet.%SetValue(value,r,c)<br />
}<br />
}<br />
}<br />
Quit $$$OK<br />
The above example defines a two–dimensional dataSet object with four rows and four columns. It<br />
supplies labels for the rows and columns and then loops over the cells to provide initial values for the<br />
cells.<br />
If the OnCreateDataSet callback changes the dataSet object to contain three dimensions, this gives<br />
the the ability to move among “pages” of data. Each page is displayed as a two-dimensional<br />
grid that represents the currently visible “page.” The following figure illustrates this data model.<br />
Note:<br />
The next several topics provide details regarding the label attributes shown in the figure. See<br />
, , and Dynamic Grid Attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 209
<strong>Zen</strong> Controls<br />
Data Model for the Dynamic Grid Control<br />
If there are pages in the , the gridLabel cell provides navigation information as follows.<br />
Click on the > symbol for the next page. The number indicates<br />
which page you are currently viewing:<br />
12.9.2 Methods<br />
Since the dataSet object is designed to work on either the server or the client, it provides local APIs<br />
for both environments. The following table lists the server-side (ObjectScript) methods. For further<br />
details, and to see the list of client-side (JavaScript) methods, see the class documentation for<br />
%ZEN.Auxiliary.dataSet.<br />
210 <strong>Using</strong> <strong>Zen</strong>
Spreadsheet<br />
Note:<br />
When you work with %ZEN.Component.dynaGrid programmatically, on the server side you<br />
can access the dataSet object via the dataSet property of the dynaGrid object. On the client,<br />
you cannot access the dataSet directly; you must the dynaGrid object’s getDataSet method<br />
to get the dataSet object.<br />
Server Method<br />
%Clear<br />
%GetArray<br />
%GetDimensions<br />
%GetDimSize<br />
%GetLabel<br />
Description<br />
Clear the contents of the dataSet (set every cell to "") without<br />
changing its size or number of dimensions.<br />
Gets the contents of the dataSet as a multidimensional array,<br />
subscripted by the 1–based dimensional addresses of the cells<br />
(row, column, page). This array is passed to %GetArray by<br />
reference.<br />
Returns the number of dimensions within the dataSet.<br />
Receives a 1–based number identifying a dimension (row, column,<br />
page) and returns the number of cells in that dimension.<br />
Receives two numbers:<br />
• 1–based number identifying a cell position within a dimension<br />
• 1–based number identifying the dimension (row, column, page)<br />
%GetLabel returns the value of the label at the specified position.<br />
%GetValue<br />
%SetArray<br />
Receives up to three 1–based numbers identifying a specific cell<br />
in the grid (row, column, page). Gets the value of the cell at that<br />
position.<br />
Receives up to four arguments:<br />
• A multidimensional array, passed by reference, and subscripted<br />
by the 1–based dimensional addresses of the cells (row, column,<br />
page).The local array must have the same dimensionality<br />
as the dataSet and must have the correct number and type of<br />
subscripts.<br />
• Up to three 1–based numbers identifying the number of cells<br />
in each dimension of the grid (row, column, page).<br />
%SetArray copies the contents of the array into the dataSet.<br />
%SetDimensions<br />
Sets the number of dimensions within the dataSet to 1, 2, or 3.<br />
<strong>Using</strong> <strong>Zen</strong> 211
<strong>Zen</strong> Controls<br />
Server Method<br />
%SetLabel<br />
Description<br />
Receives three arguments:<br />
• String that specifies a label.<br />
• 1–based number identifying a cell position within a dimension<br />
• 1–based number identifying the dimension (row, column, page)<br />
%SetLabel copies the string to the label at the specified position.<br />
%SetValue<br />
Receives up to four arguments:<br />
• String that specifies a value.<br />
• Up to three 1–based numbers identifying a specific cell in the<br />
grid (row, column, page).<br />
%SetValue sets the value of the cell at the indicated position.<br />
%SetValue also updates the dimension size, if needed.<br />
12.9.3 <br />
A with dimensions greater than zero must contain one or more and <br />
elements to define the initial dimensions of the grid. defines dimension 1 of a one-<br />
, two-, or three-dimensional .<br />
The element is the XML projection of the %ZEN.Auxiliary.gridRow class. <br />
supports the attributes described in the following table.<br />
Attribute<br />
height<br />
hidden<br />
label<br />
Description<br />
HTML height value to apply to this row, such as 0.3in or 3%.<br />
If true, this row is not displayed. The default is false.<br />
hidden has the underlying data type %ZEN.Datatype.boolean. It has the value<br />
"true" or "false" in XData Contents, 1 or 0 in server-side code, true or false<br />
in client-side code. See Datatype Classes.<br />
Default text label for the row.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
212 <strong>Using</strong> <strong>Zen</strong>
Spreadsheet<br />
Attribute<br />
readOnly<br />
rowName<br />
style<br />
Description<br />
If true, cells in this row are read-only; the user cannot edit them.The default<br />
is false.<br />
readOnly has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />
or false in client-side code. See Datatype Classes.<br />
Logical name of the row.<br />
CSS style to apply to cells in this row, for example:<br />
color: red;<br />
If there is a column style and a row style active for a given cell, the row<br />
style is applied before the column style.This means the column style might<br />
override the row style.<br />
title<br />
Help text displayed when mouse hovers over this row. If there is a row title<br />
and a column title active for a given cell, the column title overrides the row<br />
title.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
When you work with %ZEN.Component.dynaGrid programmatically, you work with elements<br />
as members of the dynaGrid property called rows. This is a list collection of %ZEN.Auxiliary.gridRow<br />
objects. Each provided in the original definition in XData Contents becomes<br />
a member of the rows collection, associated with its ordinal position in the : 1, 2, 3, etc.<br />
12.9.4 <br />
A with dimensions greater than zero must contain one or more and <br />
elements to define the initial dimensions of the grid. defines dimension 2 of a<br />
two- or three-dimensional .<br />
The element is the XML projection of the %ZEN.Auxiliary.gridColumn class. <br />
supports the attributes described in the following table.<br />
<strong>Using</strong> <strong>Zen</strong> 213
<strong>Zen</strong> Controls<br />
Attribute<br />
columnName<br />
hidden<br />
label<br />
readOnly<br />
style<br />
Description<br />
Logical name of the column.<br />
If true, this column is not displayed. The default is false.<br />
hidden has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />
or false in client-side code. See Datatype Classes.<br />
Default text label for the column.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
If true, cells in this column are read-only; the user cannot edit them.The<br />
default is false.<br />
readOnly has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />
or false in client-side code. See Datatype Classes.<br />
CSS style to apply to cells in this column, for example:<br />
color: red;<br />
If there is a row style and a column style active for a given cell, the row<br />
style is applied before the column style. This means the column style<br />
might override the row style.<br />
title<br />
width<br />
Help text displayed when mouse hovers over this column. If there is a<br />
row title and a column title active for a given cell, the column title overrides<br />
the row title.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
HTML width value to apply to this column, such as 0.3in or 3%.<br />
When you work with %ZEN.Component.dynaGrid programmatically, you work with <br />
elements as members of the dynaGrid property called columns. This is a list collection of<br />
%ZEN.Auxiliary.gridColumn objects. Each provided in the original definition<br />
in XData Contents becomes a member of the columns collection, associated with its ordinal position<br />
in the : 1, 2, 3, etc.<br />
214 <strong>Using</strong> <strong>Zen</strong>
Spreadsheet<br />
12.9.5 Attributes<br />
When you place a element within an XData Contents block, you can assign it the following<br />
attributes. When working with the programmatically, these attributes are available as<br />
properties of the dynaGrid object.<br />
Attribute<br />
Control component<br />
attributes<br />
controllerId<br />
currColumn<br />
currPage<br />
currRow<br />
gridLabel<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong><br />
control. However, unlike most other controls it does not have a<br />
single value.<br />
If this is associated with a data controller, the<br />
controllerId attribute identifies the controller that provides the data<br />
for this .The controllerId value must match the id value<br />
provided for that . See Model View Controller.<br />
The 1–based column number of the currently selected cell in the<br />
grid. The default (until the user makes selections) is 1.<br />
The 1–based page number of the data currently displayed in the<br />
grid. If the data set associated with this grid contains<br />
three–dimensional data, currPage indicates which page (along<br />
the third dimension) is currently displayed. The default is 1.<br />
The 1–based row number of the currently selected cell in the grid.<br />
The default (until the user makes selections) is 1.<br />
Caption to display in the upper-left corner cell.<br />
Although you enter ordinary text for this attribute, it has the<br />
underlying data type %ZEN.Datatype.caption. This makes it easy to<br />
localize its text into other languages. See <strong>Zen</strong> Localization.<br />
<strong>Using</strong> <strong>Zen</strong> 215
<strong>Zen</strong> Controls<br />
Attribute<br />
onchangecell<br />
Description<br />
(Optional) Client-side JavaScript expression that is executed<br />
whenever the user changes the contents of a cell. Generally this<br />
expression invokes a client-side JavaScript method defined in the<br />
page class. This method becomes the “onchangecell event handler”<br />
for the .<br />
If you omit the onchangecell attribute, the default behavior is to<br />
assign the user-entered value to the cell.<br />
When providing a value for an event handler attribute such as<br />
onchangecell, use double quotes to enclose the value and single<br />
quotes (if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
onclickcolumn<br />
onclickrow<br />
OnCreateDataSet<br />
ondrawcell<br />
oneditcell<br />
(Optional) Client-side JavaScript expression that is executed<br />
whenever the user clicks on a column header cell (at the top of a<br />
column).<br />
(Optional) Client-side JavaScript expression that is executed<br />
whenever the user clicks on a row header cell (at the left of a row).<br />
As described in the topic Data Set, the<br />
OnCreateDataSet value is the name of a server-side callback<br />
method that provides the data set associated with this .<br />
(Optional) Client-side JavaScript expression that is executed when<br />
the is about to draw a cell. If this event handler returns<br />
a value, this value is used as DHTML to render the cell contents.<br />
This convention provides a way to display custom cell formatting<br />
within a .<br />
(Optional) Client-side JavaScript expression that is executed when<br />
the is ready to accept user input in one of its cells. If<br />
the oneditcell event handler returns a value, this value is used as<br />
DHTML to render the editor used for the cell. oneditcell provides<br />
a way to display a custom cell editor within a . The<br />
default behavior is to place an HTML input control over that region<br />
of the grid to permit the user to enter data. There is no need to<br />
override this default, but you may.<br />
216 <strong>Using</strong> <strong>Zen</strong>
Spreadsheet<br />
Attribute<br />
onnotifyView<br />
Description<br />
This attribute applies if the is associated with a data<br />
controller. The onnotifyView value is a client-side JavaScript<br />
expression that is executed each time the data controller connected<br />
to this raises an event. Generally this<br />
expression invokes a client-side JavaScript method defined in the<br />
page class.This method becomes the “onnotifyView event handler”<br />
for the . See Model View Controller.<br />
When providing a value for this attribute, use double quotes to<br />
enclose the value and single quotes (if needed) within the<br />
JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
rowLabelWidth<br />
showColumnLabels<br />
showRowLabels<br />
HTML width value, such as 3 or 0.3in or 3%. rowLabelWidth<br />
applies to the column of row labels. The default width is 100.<br />
If true, column labels are displayed in a row along the top of the<br />
grid. The default is true.<br />
showColumnLabels has the underlying data type<br />
%ZEN.Datatype.boolean. It has the value "true" or "false" in XData<br />
Contents, 1 or 0 in server-side code, true or false in client-side<br />
code. See Datatype Classes.<br />
If true, row labels are displayed in a column along the left side of<br />
the grid. The default is true.<br />
showRowLabels has the underlying data type<br />
%ZEN.Datatype.boolean. It has the value "true" or "false" in XData<br />
Contents, 1 or 0 in server-side code, true or false in client-side<br />
code. See Datatype Classes.<br />
<strong>Using</strong> <strong>Zen</strong> 217
13<br />
Model View Controller<br />
To simplify the flow of data from a data source to a <strong>Zen</strong> page, <strong>Zen</strong> provides a set of classes that let<br />
you define a data model (the model) and connect it to a set of <strong>Zen</strong> components (the view) via an<br />
intermediate object (the controller). The name for this mechanism is Model View Controller, or<br />
MVC. The following are some typical uses of MVC:<br />
• Create a form that displays a set of properties, loaded from a persistent object within the database.<br />
The form automatically displays controls appropriate to the data type of each property.<br />
• Display a chart based on values within a form. The chart automatically updates its display whenever<br />
the user submits any changes to the form.<br />
• Display meters representing values calculated on the server. When the page is refreshed, these<br />
meters automatically update themselves with current values from the server.<br />
13.1 Architecture<br />
The following figure shows the three parts of the MVC architecture — model, view, and controller<br />
— and indicates where these objects execute their code. The controller and its associated views are<br />
<strong>Zen</strong> components, placed on the <strong>Zen</strong> page. The controller component is hidden from view, but view<br />
components are user-visible. The view components display data values, which they obtain by<br />
requesting them from the controller. The controller resides on the client, but has the ability to execute<br />
code on the server. The model resides entirely on the server. It draws its data values from a source on<br />
the server and can respond to requests for data from the controller.<br />
<strong>Using</strong> <strong>Zen</strong> 219
Model View Controller<br />
Model View Controller Architecture<br />
13.1.1 Data Model<br />
A data model is any subclass of %ZEN.DataModel.DataModel. A data model can:<br />
1. Retrieve data values from one or more sources, such as:<br />
• A persistent Caché object<br />
• An external database (ODBC or JDBC) via the Caché SQL Gateway<br />
• A Caché global<br />
• An Ensemble business service<br />
2. Place these values into its own properties.<br />
3. Make these properties available to be consumed by a data controller.<br />
There are two variations on a data model class. Typically you will choose one of these as your parent<br />
class when you create a new data model. The variations are closely related, but serve different purposes.<br />
The available data model subclasses are %ZEN.DataModel.ObjectDataModel and<br />
%ZEN.DataModel.Adaptor, as shown in the following figure.<br />
220 <strong>Using</strong> <strong>Zen</strong>
Architecture<br />
Data Model Classes<br />
13.1.1.1 %ZEN.DataModel.ObjectDataModel<br />
A subclass of %ZEN.DataModel.ObjectDataModel is called an object data model. It defines one or<br />
more properties that a data controller component can consume. Each of these properties is correlated<br />
with a value from the data source class. Not every value in the data source needs to be exposed in the<br />
model. This convention allows you to expose in the data model only those values that you wish to.<br />
An example of this might be a patient record, which contains confidential information that not every<br />
application should expose. Keep in mind that when you use this option, the developer of the object<br />
data model class is responsible for implementing methods to load values from a source into data model<br />
properties, store values back to a source, and validate values. This is in contrast to the adaptor data<br />
model, where <strong>Zen</strong> takes care of these details. However, this is not such a difficult procedure, as the<br />
next major topic, Building a Form, will explain.<br />
<strong>Using</strong> <strong>Zen</strong> 221
Model View Controller<br />
For examples, use Studio to view the classes ZENMVC.FormDataModel and ZENMVC.FormDataModel2<br />
in the SAMPLES namespace.<br />
13.1.1.2 %ZEN.DataModel.Adaptor<br />
There are many times where it is convenient to use a persistent object as a data model object. To make<br />
this easy to accomplish, <strong>Zen</strong> provides the %ZEN.DataModel.Adaptor interface. Adding this an additional<br />
superclass to a persistent class will make it possible to use the persistent class as a data model. This<br />
data model makes available to a data controller any and all properties that it contains. This option is<br />
useful when you want to expose every property in an existing class.<br />
An example of this might be a class that you are using in an inventory or parts control application,<br />
wherein each product might be described by a class with a large number of properties. If you want to<br />
place all of these properties onto a form automatically without writing another class, you can simply<br />
cause the product class to extend %ZEN.DataModel.Adaptor. Following that, <strong>Zen</strong> simply generates the<br />
form for you, as later topics will explain.<br />
The drawback of this choice is that your data and form are very closely linked. If you want some<br />
flexibility, you should subclass the object data model class and implement the internal interface. This<br />
is the classic trade-off of convenience versus flexibility.<br />
For examples, use Studio to view the classes ZENMVC.Address and ZENMVC.Person in the SAMPLES<br />
namespace.<br />
13.1.2 Data Controller<br />
A data controller is any subclass of %ZEN.Auxiliary.dataController. Through class inheritance, every<br />
data controller is also a <strong>Zen</strong> component, as the following figure shows. This convention permits you<br />
to place a data controller on a <strong>Zen</strong> page.<br />
222 <strong>Using</strong> <strong>Zen</strong>
Architecture<br />
Data Controller and Data View Classes<br />
A data controller manages the communication between a data model and a data view. The <br />
component appears in the page description along with other components, but it is not visible<br />
on the output page. Its role is as an intermediary between a data model and one or more data views.<br />
13.1.2.1 Data Controller Attributes<br />
When you place a within a <strong>Zen</strong> , you can assign it the following attributes.<br />
Attribute<br />
<strong>Zen</strong> component<br />
attributes<br />
defaultSeries<br />
modelClass<br />
Description<br />
A has the same general-purpose attributes as any<br />
<strong>Zen</strong> component. The chapter <strong>Zen</strong> Style describes them. The id<br />
attribute is required for . name and condition may<br />
also apply. A is not visible, so visual style attributes<br />
do not apply.<br />
Optional. If a data model has multiple data series, defaultSeries is<br />
a 1-based number that specifies which series should be used to<br />
provide values to data views that can only display values from one<br />
data series (such as a form). The default is 1.<br />
Package and class name of the data model class that provides data<br />
for this . Changing the modelClass value causes<br />
the controller to abandon the previous model and load data from the<br />
new model.<br />
The modelClass value can be a literal string, or it can contain a <strong>Zen</strong><br />
#()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
<strong>Using</strong> <strong>Zen</strong> 223
Model View Controller<br />
Attribute<br />
modelId<br />
oncreate<br />
Description<br />
String that identifies a specific instance of a data model object. The<br />
form and possible values of the modelId string are determined by<br />
the developer of the data model class. Changing the modelId value<br />
causes the controller to load a new record, and to update its associated<br />
views.<br />
The modelId value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
Client-side JavaScript expression that runs each time the<br />
createNewObject method is called. Generally this expression<br />
invokes a client-side JavaScript method. This method becomes the<br />
“oncreate event handler” for the .<br />
When providing a value for an event handler attribute such as<br />
oncreate, use double quotes to enclose the value and single quotes<br />
(if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
ondelete<br />
onerror<br />
onnotifyController<br />
onsave<br />
Client-side JavaScript expression that runs each time the deleteId<br />
method is called. The parameter id is passed to the event handler<br />
and contains the modelId of the deleted object.<br />
Client-side JavaScript expression that runs each time the data controller<br />
attempts to open an instance of a data model object and<br />
encounters an error.<br />
When you work with a %ZEN.Auxiliary.dataController programmatically,<br />
you can obtain the most recent error message reported by the data<br />
model object associated with this data controller, by examining the<br />
modelError property of the dataController object. This property is not<br />
available as an XML attribute when adding the to<br />
the <strong>Zen</strong> page.<br />
Client-side JavaScript expression that runs each time a data view<br />
connected to this data controller raises an event.<br />
Client-side JavaScript expression that runs each time the save<br />
method is called. The parameter id is passed to the event handler<br />
and contains the current modelId.<br />
224 <strong>Using</strong> <strong>Zen</strong>
Architecture<br />
Attribute<br />
autoRefresh<br />
Description<br />
Setting autoRefresh to a non-zero value turns on automatic refresh<br />
mode for this data controller. In this mode, the data controller reloads<br />
its data from the server at the periodic interval specified by<br />
autoRefresh (in milliseconds). autoRefresh is provided as a<br />
convenience for data controller used to drive meters or charts; it is<br />
of limited use for forms. Setting autoRefresh to 0 disables automatic<br />
refresh mode.<br />
13.1.2.2 Data Controller Changes<br />
The following data controller attributes can be changed to affects what is seen on screen:<br />
• modelClass — Cause the data controller to look at a different data model<br />
• modelId — Cause the data controller to look at a different data record within the same model<br />
• defaultSeries — Cause the data controller to look at a different data series within the same data<br />
record and model<br />
The SAMPLES namespace class ZENMVC.MVCForm allows you to experience changes in these data<br />
controller attributes. Try entering the following URI in the browser:<br />
http://localhost:57772/csp/samples/ZENMVC.MVCForm.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché. To change the model<br />
ID, click the Previous and Next buttons. to change the model class, click the Change Model button.<br />
You can use Studio to view the class code.<br />
13.1.3 Data View<br />
A data view is any <strong>Zen</strong> component that implements the %ZEN.Component.dataView interface. As<br />
shown in the previous figure, this includes:<br />
• <br />
• All forms<br />
• All charts<br />
• All meters<br />
A data view component connects to its associated data controller at runtime, and uses it to get and set<br />
values from the associated data model. A data view points to its data controller; more than one data<br />
view can point to the same data controller.<br />
<strong>Using</strong> <strong>Zen</strong> 225
Model View Controller<br />
13.1.3.1 Data View Attributes<br />
Data view components support the usual <strong>Zen</strong> component attributes, plus any specialized attributes that<br />
are typical of the specific type of component. Additionally, all data view components support the following<br />
attributes, which relate specifically to the component’s role as a data view.<br />
Attribute<br />
controllerId<br />
dataBinding<br />
Description<br />
Identifies the data controller for this data view (). The controllerId value<br />
must match the id value provided for that component.<br />
Identifies the data model property that is bound to this component. This<br />
property provides the value that the component displays:<br />
• If the dataBinding value is a simple property name, this is assumed<br />
to be a property within the data model class identified by the modelClass attribute.<br />
• Alternatively, dataBinding can provide a full package, class, and<br />
property name.<br />
dataBinding is suitable only for components that display a single value<br />
(meters or controls). Each meter on a <strong>Zen</strong> page must supply a controllerId<br />
and a dataBinding. Controls do not support the data view interface, so<br />
cannot supply a controllerId, but if the form that contains the controls<br />
has an associated data controller, each control within the form can<br />
supply a dataBinding attribute that identifies which property it displays.<br />
onnotifyView<br />
Client-side JavaScript expression that is executed each time the data<br />
controller associated with this data view raises an event. Generally this<br />
expression invokes a client-side JavaScript method defined in the page<br />
class. This method becomes the “onnotifyView event handler” for the<br />
data view component.<br />
When providing a value for this attribute, use double quotes to enclose<br />
the value and single quotes (if needed) within the JavaScript expression.<br />
For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
226 <strong>Using</strong> <strong>Zen</strong>
Architecture<br />
13.1.3.2 The Controller Object<br />
When you work with a data view component programmatically, you can obtain a reference to the<br />
associated %ZEN.Auxiliary.dataController object via the following properties of the<br />
%ZEN.Component.dataView interface:<br />
• controller — Use in JavaScript code that runs on the client side<br />
• %controller — Use in ObjectScript or Basic code that runs on the server side<br />
13.1.3.3 Multiple Data Views<br />
Whenever a user modifies a value within one of the controls that is bound to a data controller, the data<br />
controller is notified. It is common for data views to share a controller; for example, different types<br />
of chart on the same page could share the same data controller to display different visualizations of<br />
the same data, as in the following figure. If there are multiple data view components connected to the<br />
same data controller, they are all notified of any change to a bound control.<br />
For examples of shared data controllers, use Studio to view the classes ZENMVC.MVCChart and<br />
ZENMVC.MVCMeters. The class ZENMVC.MVCMeters uses the same data controller to provide values<br />
for a and several meters. The class ZENMVC.MVCChart provides a and three<br />
charts that all use the same data controller. Try entering the following URIs in the browser:<br />
http://localhost:57772/csp/samples/ZENMVC.MVCChart.cls<br />
http://localhost:57772/csp/samples/ZENMVC.MVCMeters.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
When you change a value in one of these pages by editing it in the and pressing Enter,<br />
this change affects the corresponding value in all the charts (or meters) on the same page, because all<br />
of them share the same data controller. In the following figure, the user has just modified the Trucks<br />
field in the for ZENMVC.MVCChart.<br />
<strong>Using</strong> <strong>Zen</strong> 227
Model View Controller<br />
13.2 Constructing a Model<br />
This topic provides the first in a series of exercises that show how to use the Model View Controller<br />
to create a form. The topics are:<br />
• Constructing a Model<br />
• Binding a to an Object Data Model<br />
• Adding Behavior to the <br />
• with an Object Data Model<br />
• with an Adaptor Data Model<br />
If you have a new Caché installation, before you begin these exercises you must first generate data<br />
records for the SAMPLES namespace. You only need to do this once per Caché installation. Enter the<br />
following URI in the browser:<br />
http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
13.2.1 Step 1:Type of Model<br />
There are two basic choices when generating a form using the Model View Controller:<br />
• %ZEN.DataModel.ObjectDataModel or %ZEN.DataModel.Adaptor<br />
An object data model takes more work to code. An object data model gives you explicit control<br />
over which properties end up in the model, so it makes more sense for cases when you want to<br />
shield certain properties from display or when you want to display charts, which require very fine<br />
data control. The choice of adaptor data model is simple and convenient, but it imposes a burden<br />
on the original persistent object, in that you must change its class code to allow it to become an<br />
adaptor data model.<br />
• or <br />
A is a good choice for the key forms that are critical to the success of your application.<br />
A requires more work to encode, but provides as fine a level of control as you need to<br />
perfect the results. A provides automatic results and automatically updates its layout<br />
if you change the underlying data model. This is useful to generate forms for large volumes of<br />
detailed information such as system administration, inventory, or maintenance requests.<br />
For this exercise we choose an object data model and a .<br />
228 <strong>Using</strong> <strong>Zen</strong>
Constructing a Model<br />
13.2.2 Step 2: Object Data Model<br />
Suppose a persistent object called Patient contains a patient record. This object may have hundreds of<br />
properties. Suppose you want to create a simple page that only displays demographic information, in<br />
this case the patient’s name and city of residence. This is a clear case for using<br />
%ZEN.DataModel.ObjectDataModel.<br />
First, define an object data model class called PatientModel that knows how to load and store properties<br />
from the Patient object:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4.<br />
Choose File > New or Ctrl-N or the<br />
5. Click the General tab.<br />
6. Click the Caché Class Definition icon.<br />
icon.<br />
7. Click OK.<br />
8. For Package Name enter:<br />
MyApp<br />
9. In the Class Name field, type:<br />
PatientModel<br />
10. Click Next.<br />
11. Choose Extends<br />
12. Click Next and enter (or browse to) this class name:<br />
%ZEN.DataModel.ObjectDataModel<br />
13. Click Finish.<br />
Studio creates and displays a skeletal object data model class:<br />
Class MyApp.PatientModel Extends %ZEN.DataModel.ObjectDataModel<br />
{<br />
}<br />
14. Add properties and methods to complete the class as shown in the following code example. This<br />
example defines two properties for the data model (Name and City). It also overrides several of<br />
the server-side methods in the %ZEN.DataModel.ObjectDataModel interface. For documentation<br />
of these methods, refer to the topic Object Data Model Callback Methods, later in this chapter.<br />
<strong>Using</strong> <strong>Zen</strong> 229
Model View Controller<br />
Class MyApp.PatientModel Extends %ZEN.DataModel.ObjectDataModel<br />
{<br />
Property Name As %String;<br />
Property City As %String;<br />
/// Load an instance of a new (unsaved) source object for this DataModel.<br />
Method %OnNewSource(Output pSC As %Status = {$$$OK}) As %RegisteredObject<br />
{<br />
Quit ##class(ZENDemo.Data.Patient).%New()<br />
}<br />
/// Load an instance of the source object for this DataModel.<br />
Method %OnSaveSource(pSource As ZENDemo.Data.Patient) As %Status<br />
{<br />
Set tSC=pSource.%Save()<br />
If $$$ISOK(tSC) Set ..%id=pSource.%Id()<br />
Quit tSC<br />
}<br />
/// Load an instance of the source object for this DataModel.<br />
Method %OnOpenSource(pID As %String, pConcurrency As %Integer = -1,<br />
Output pSC As %Status = {$$$OK}) As %RegisteredObject<br />
{<br />
Quit ##class(ZENDemo.Data.Patient).%OpenId(pID,pConcurrency,.pSC)<br />
}<br />
/// Delete instance of associated source object.<br />
ClassMethod %OnDeleteSource(pID As %String) As %Status<br />
{<br />
Quit ##class(ZENDemo.Data.Patient).%DeleteId(pID)<br />
}<br />
}<br />
/// Do the actual work of loading values from the source object.<br />
Method %OnLoadModel(pSource As ZENDemo.Data.Patient) As %Status<br />
{<br />
Set ..Name = pSource.Name<br />
}<br />
Set ..City = pSource.Home.City<br />
Quit $$$OK<br />
/// Do the actual work of storing values into the source object.<br />
Method %OnStoreModel(pSource As ZENDemo.Data.Patient) As %Status<br />
{<br />
Set pSource.Name = ..Name<br />
Set pSource.Home.City = ..City<br />
Quit $$$OK<br />
}<br />
15.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
icon.<br />
13.3 Binding a to an Object Data Model<br />
This exercise creates a data controller based on the object data model from the previous exercise. It<br />
then binds a form to this data controller.<br />
230 <strong>Using</strong> <strong>Zen</strong>
Binding a to an Object Data Model<br />
13.3.1 Step 1: Data Controller<br />
If you do not already have a simple <strong>Zen</strong> application and page class available from previous exercises,<br />
create them now using instructions from the <strong>Zen</strong> Tutorial chapter:<br />
• Creating a <strong>Zen</strong> Application — Create the class MyApp.MyNewApp.<br />
• Creating a <strong>Zen</strong> Page — Create the class MyApp.MyNewPage. You only need to complete the steps<br />
in the first section, Step 1: New Page Wizard.<br />
Now place a data controller component on the <strong>Zen</strong> page by adding a element in the<br />
MyApp.MyNewPage class XData Contents block, inside the container, as follows:<br />
<br />
Where:<br />
• id is the unique identifier of the data controller on the <strong>Zen</strong> page. A data view (such as a form) will<br />
specify its data controller using this id.<br />
• modelClass is package and class name of the data model class. The previous exercise created the<br />
class MyApp.PatientModel which is an object data model that represents objects of the<br />
ZENDemo.Data.Patient class.<br />
• modelId is a number that identifies the record to initially load from the data source. In this case,<br />
it is the identifier of a specific ZENDemo.Data.Patient object.<br />
Note:<br />
The component is not visible on the page.<br />
13.3.2 Step 2: Data View<br />
Now create a form and connect it to the data controller, as follows:<br />
1. Place a component inside the container.<br />
Bind the form to the data controller from the previous topic by setting the controllerId<br />
to match the id value. For example:<br />
<br />
<br />
The id attribute does not affect the binding but becomes useful in a future step, when we will save<br />
the form.<br />
2. Within the add two controls.<br />
<strong>Using</strong> <strong>Zen</strong> 231
Model View Controller<br />
Bind each control to a property of the data model by providing a dataBinding attribute that<br />
identifies a property within the modelClass of the . Also provide a label for each<br />
control. For example:<br />
<br />
<br />
<br />
<br />
The label attribute does not have any purpose relative to the Model View Controller, but it is<br />
necessary if we want our controls to have a meaningful labels on the <strong>Zen</strong> page.<br />
13.3.3 Step 3: Initial Results<br />
View your initial results as follows:<br />
1. Open your <strong>Zen</strong> page class in Studio.<br />
2.<br />
3.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the<br />
icon.<br />
icon.<br />
The data controller component creates a MyApp.PatientModel object on the server, and asks it to<br />
load data from data source record number 1 (identified by the modelId attribute)<br />
into its own properties. The data controller places these data values into the appropriate controls<br />
within the form. The dataBinding attribute for each control identifies which property provides the<br />
value for that control, Name or City.<br />
The following figure shows our form with the current values from record 1.<br />
13.3.4 Step 4: Saving the Form<br />
Suppose you want the user to be able to edit the values in this form, and to save changes. To save the<br />
values in a form associated with a data controller, your application must call the form’s save method.<br />
Typically you would enable this as follows:<br />
1. Add a client-side method to the page class as follows:<br />
232 <strong>Using</strong> <strong>Zen</strong>
Method save() [ Language = javascript ]<br />
{<br />
var form = zenPage.getComponentById('MyForm');<br />
Binding a to an Object Data Model<br />
}<br />
form.save();<br />
Now you can see why it was important to define an id for our . The method<br />
getComponentById needs this id to get a reference for the form so that we can call its save<br />
method.<br />
2. Add to your page a that calls this method to save the form.<br />
The entire definition now looks something like this:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
3. Try editing the data and clicking Save.<br />
Each time the user clicks the Save button, the form save method calls back to the server and saves the<br />
data by calling the appropriate methods of the data model class. During this process, the form ask the<br />
data controller to assist with data validation of the various properties. The source of this validation<br />
logic is the data model class.<br />
The data controller also has a save method we can use. There is a difference between saving the form<br />
and saving the controller. Calling the save method of the form triggers the form validation logic, after<br />
which the form instructs the controller to save data by calling the appropriate methods of the data<br />
model class. Saving the controller skips form validation.<br />
You can try out basic form validation in step 3 of this example as follows: If you empty the Patient<br />
Name field entirely and click Save, a validation error occurs. This is because the Patient property is<br />
marked as Required in the ZENDemo.Data.Patient class that serves as our data source. However, if<br />
you change the Patient Name or Patient City to any non-empty value, the form saves correctly. It will<br />
be easier to prove this to yourself once you have extended the form to allow you to easily view more<br />
than one data record. Then you can switch back and forth between records to see that they in fact<br />
contain your changes.<br />
Note:<br />
For further validation examples, try using and viewing the <strong>Zen</strong> page class ZENMVC.MVCForm<br />
in the SAMPLES namespace. Try entering the following URI in the browser:<br />
http://localhost:57772/csp/samples/ZENMVC.MVCForm.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché. Edit values<br />
in one of the forms shown on the page, and click a Submit button. You can use Studio to<br />
view the class code.<br />
<strong>Using</strong> <strong>Zen</strong> 233
Model View Controller<br />
Rather than wait for server-side validation, we can add client-side validation to the data model class<br />
by defining a property-specific IsValidJS method. This is a JavaScript class method that uses the<br />
naming convention propertyIsValidJS and returns an error message if the value of the given property<br />
is invalid or '' (an empty string) if the value is OK. This method can be defined within the data model<br />
class, or you can define a datatype class that defines a propertyIsValidJS method.<br />
Adding the following method to the MyApp.PatientModel class causes the data controller to automatically<br />
apply this validation to the City property on the client each time its save method is called:<br />
ClassMethod CityIsValidJS(value) [Language = javascript]<br />
{<br />
return ('Boston' == value) 'Invalid City Name' : '';<br />
}<br />
13.4 Adding Behavior to the <br />
The %ZEN.Auxiliary.dataController class offers several useful methods. Suppose you want to enhance<br />
your page from the previous exercise so that it can open new records, create new records, delete existent<br />
records, or reset the current record to a particular model ID. This topic explain how to accomplish<br />
these tasks using dataController methods such as getModelId and setModelId.<br />
13.4.1 Step 1: Opening a New Record<br />
When you ask the browser to display the page you have been building during these exercises, it always<br />
displays the same data record. This is because you have configured the modelId property of your<br />
element with the value of 1. You can see what happens if you change this property<br />
to other values, such as 2, 3, or 4, up to 1000.<br />
However, you must remember that these values represent real ID values of existing instances of the<br />
ZENDemo.Data.Patient class. These instances exist because all of the classes in ZENDemo.Data are<br />
populated automatically when you first run the <strong>Zen</strong> Demo as described in the first chapter, Introducing<br />
<strong>Zen</strong>.<br />
Suppose you want to give the user the option of choosing which record to view. There are several<br />
options, including:<br />
• Add a text field that allows the user to enter an ID<br />
• Add a combo box that allows the user to choose the record by one of its properties, such as a<br />
patient name<br />
• Add a table that allows the user to click on a patient name and see the details on a form below<br />
It does not matter which option you choose for user input. The key task is for your page to be able to<br />
tell the data controller to load the record. You can accomplish this as follows:<br />
234 <strong>Using</strong> <strong>Zen</strong>
Adding Behavior to the <br />
1. Open your <strong>Zen</strong> page class in Studio.<br />
2. Add a new text field to the :<br />
<br />
<br />
<br />
<br />
<br />
3. Add a corresponding client-side method:<br />
Method loadRecord(id) [ Language = javascript ]<br />
{<br />
var controller = zenPage.getComponentById('patientData');<br />
}<br />
controller.setModelId(id);<br />
The onblur event calls a client-side method loadRecord that first gets a pointer to the data controller<br />
using its id value "patientData", then uses whatever the user has entered in the field as a<br />
modelId to load the desired record from the data model. To actually load the record, loadRecord<br />
uses the data controller method setModelId.<br />
Also observe that this example binds the ID field to the %id property of the data model, so that<br />
this field will always show you the ID of the current record. This is not necessary for setModelId<br />
to work, but it will be very useful in the next topic.<br />
4.<br />
5.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the icon.<br />
The following figure shows the form.<br />
icon.<br />
6. Try the onblur functionality as follows:<br />
• Enter 2 (or any other number) in the ID field.<br />
<strong>Using</strong> <strong>Zen</strong> 235
Model View Controller<br />
• Press the Tab key to move out of the ID field.<br />
• The alternate record should display.<br />
7. In Binding a to an Object Data Model, Step 4: Saving the Form, you added Save functionality<br />
without the ability to easily test it. Try it now, as follows:<br />
• Note the number of the current record.<br />
• Make a significant change to the Name or City field.<br />
• Click Save.<br />
• Enter a different number in the ID field.<br />
• Press the Tab key to move out of the ID field.<br />
• The alternate record should display.<br />
• Enter the number for the record that you saved in the ID field.<br />
• Press the Tab key to move out of the ID field.<br />
• Your saved changes should be visible on the form.<br />
13.4.2 Step 2: Creating and Deleting Records<br />
Creating and deleting records are also simple tasks. Modify your page to add the necessary buttons<br />
and client side code as follows.<br />
1. Open your <strong>Zen</strong> page class in Studio.<br />
2. After the and before the closing , replace the single Save button with the following<br />
:<br />
<br />
<br />
<br />
<br />
<br />
<br />
These statements add the buttons to an so that they will appear on the screen in a row.<br />
Each button defines its onclick method as a different client-side method.<br />
3. Add the corresponding new client-side methods to the page class:<br />
Method newRecord() [ Language = javascript ]<br />
{<br />
var controller = zenPage.getComponentById('patientData');<br />
}<br />
controller.createNewObject();<br />
And:<br />
236 <strong>Using</strong> <strong>Zen</strong>
Method updateRecord() [ Language = javascript ]<br />
{<br />
var controller = zenPage.getComponentById('patientData');<br />
Adding Behavior to the <br />
}<br />
controller.update();<br />
And:<br />
Method deleteRecord() [ Language = javascript ]<br />
{<br />
var controller = zenPage.getComponentById('patientData');<br />
controller.deleteId(controller.getModelId());<br />
controller.createNewObject();<br />
}<br />
Each of these methods uses a different dataController method to achieve its purposes.<br />
4.<br />
5.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the icon.<br />
The following figure shows the form.<br />
icon.<br />
13.4.2.1 New<br />
Suppose the user clicks New. Calling createNewObject immediately creates a new empty model. In<br />
the browser, every time the user clicks New the form is emptied. After that, if the user completes the<br />
empty form and clicks Save, this invokes the form’s save method. This (eventually) leads to a call to<br />
the data model’s %OnSaveSource method on the server.<br />
In Binding a to an Object Data Model, Step 4: Saving the Form, you added Save functionality<br />
by causing the %OnSaveSource method to set the %id property of the model to the ID of the saved<br />
object, as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 237
Model View Controller<br />
Method %OnSaveSource(pSource As ZENDemo.Data.Patient) As %Status<br />
{<br />
Set tSC=pSource.%Save()<br />
If $$$ISOK(tSC) Set ..%id=pSource.%Id()<br />
Quit tSC<br />
}<br />
As a result, every time the user clicks New, enters values, then clicks Save, the form shows the newlyassigned<br />
ID to the user (thanks to the dataBinding on that field). Of course, this only works if the data<br />
entered in the form passes validation. Name is a required field, so if no Name is entered, the record is<br />
not saved.<br />
13.4.2.2 Delete<br />
Suppose the user clicks Delete. The data controller’s deleteId method expects to recieve the ID for<br />
the record to be deleted. Therefore, when the user clicks Delete, the page uses the data controller’s<br />
getModelId method to determine the ID of the record the user is currently viewing. It passes this ID<br />
on to deleteId. This (eventually) leads to a call to the data model’s %OnDeleteSource method on the<br />
server. The source object is deleted, and since there will be no source object anymore, the page calls<br />
the data controller’s createNewObject method to empty the form and prepare it for new input.<br />
Important:<br />
If, while using this exercise, you delete a record with a specific ID, this object no<br />
longer exists. You cannot view or create a record with this ID again.<br />
13.4.2.3 Update<br />
Before clicking Update, the user must enter an ID number (between 1 and 1000) in the ID field. The<br />
page updates the form fields with data from that record. This fails only if you have previously deleted<br />
a record with that ID.<br />
13.5 with an Object Data Model<br />
This topic explains how to use with a data controller. In this case the data model is an<br />
object data model.<br />
13.5.1 Step 1: is Easy<br />
You may create your first very easily as follows:<br />
1. Create a new <strong>Zen</strong> page class. Use the steps in Creating a <strong>Zen</strong> Page, Step 1: New Page Wizard.<br />
Call your new class anything you like, but keep it in the MyApp package. Be careful not to overwrite<br />
your previous work.<br />
2. In XData Contents, place a and inside :<br />
238 <strong>Using</strong> <strong>Zen</strong>
<br />
<br />
<br />
with an Object Data Model<br />
3.<br />
4.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the<br />
icon.<br />
icon.<br />
The form displays two fields that contain the current Name and City values for the record whose<br />
modelId you entered in the statement. Perhaps you have changed these values,<br />
or deleted this record, during previous exercises. Whatever data is now available for that modelId<br />
displays.<br />
The label for each control is determined by the corresponding property name in MyApp.PatientModel.<br />
These labels are different from the text you assigned to the caption attribute when you used <br />
and components to lay out the form. In all other respects, this display is identical to the<br />
display you first saw in Building a Form, Step 3: Initial Results. Later steps show how to set specific<br />
labels for the controls in a .<br />
13.5.2 Step 2: Converting to <br />
Now you are ready to recreate the example from previous exercises as a . To do<br />
this, you will need to rewrite your MyApp.MyNewPage XData Contents block so that it looks like this:<br />
<strong>Using</strong> <strong>Zen</strong> 239
Model View Controller<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
That is:<br />
1. In Studio, return to your existing sample page, MyApp.MyNewPage.<br />
2. Remove or comment out this , which specifies each control individually:<br />
<br />
<br />
<br />
<br />
<br />
3. Add this , which relies on the data controller to supply it with any control definitions<br />
that can be generated based on properties in the data model:<br />
<br />
<br />
<br />
<br />
Where:<br />
• controllerId identifies the data controller.<br />
• defaultGroupId identifies the group, on the form, that will contain the controls generated by<br />
that data controller.<br />
• defaultGroupId is optional; but if it appears in the then somewhere inside the<br />
, you must specify a group with an id that matches the defaultGroupId, in this<br />
case a .<br />
240 <strong>Using</strong> <strong>Zen</strong>
with an Object Data Model<br />
• If you want controls to appear on the form that do not depend on the data controller, such as<br />
the control whose value is based on the %id variable, you must place them explicitly, as<br />
shown.<br />
4.<br />
5.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
Choose View > Web Page or the icon.<br />
The following displays:<br />
icon.<br />
6. You may assign specific labels to the generated controls on the as follows:<br />
• In Studio, open the object data model class, MyApp.PatientModel.<br />
• Edit the properties to add the ZENLABEL parameter to each of them:<br />
Property Name As %String(ZENLABEL = "Patient Name");<br />
And:<br />
Property City As %String(ZENLABEL = "Patient City");<br />
•<br />
Choose Build > Compile or Ctrl-F7 or the<br />
icon to compile the data model.<br />
7. Refresh your <strong>Zen</strong> page MyApp.MyNewPage in the browser.<br />
Your and now produce identical results.<br />
13.5.3 Step 3: Automatic Control Selection<br />
When you use instead of , it is no longer necessary to add data view components<br />
(controls) to the form, item by item, as in the first example of building a form. This information is now<br />
extracted automatically from the data model. determines which type of control to assign<br />
to each property in the model based on its data type.<br />
<strong>Using</strong> <strong>Zen</strong> 241
Model View Controller<br />
The following exercise demonstrates this by adapting your existing page class to use a different data<br />
model. When you complete the exercise and display the page, a new form will appear whose controls<br />
are clearly different from those we previously used:<br />
1. Return to Studio in the SAMPLES namespace.<br />
2. Choose Tools > Copy Class.<br />
3. The Class Copy dialog displays. Enter:<br />
• Copy Class — MyApp.PatientModel<br />
• To — MyApp.EmployeeModel<br />
• Check the Replace Instances of Class Name box.<br />
• Click OK.<br />
The new class definition for MyApp.EmployeeModel displays in Studio.<br />
4. Edit MyApp.EmployeeModel so that it has the following three properties only:<br />
Property Name As %String;<br />
Property Salary As %Numeric;<br />
Property Active As %Boolean;<br />
5. Edit the methods inside MyApp.EmployeeModel to work with the new properties:<br />
Method %OnLoadModel(pSource As ZENDemo.Data.Employee) As %Status<br />
{<br />
Set ..Name = pSource.Name<br />
}<br />
Set ..Salary = pSource.Salary<br />
Set ..Active = pSource.Active<br />
Quit $$$OK<br />
And:<br />
Method %OnStoreModel(pSource As ZENDemo.Data.Employee) As %Status<br />
{<br />
Set pSource.Name = ..Name<br />
}<br />
Set pSource.Salary = ..Salary<br />
Set pSource.Active = ..Active<br />
Quit $$$OK<br />
6.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
icon.<br />
7. Choose Tools > Copy Class.<br />
8. The Class Copy dialog displays. Enter:<br />
• Copy Class — MyApp.MyNewPage<br />
• To — MyApp.MyOtherPage<br />
• Check the Replace Instances of Class Name box.<br />
242 <strong>Using</strong> <strong>Zen</strong>
with an Object Data Model<br />
• Click OK.<br />
The new class definition for MyApp.MyOtherPage displays in Studio.<br />
9. Take a shortcut by leaving the id as "patientData".<br />
You may ignore this shortcut by globally replacing "patientData" with a more meaningful id, for<br />
example "employeeData". However, make sure you change all the instances of this id string in<br />
the class, or you will encounter errors at runtime.<br />
10. Change the modelClass to "MyApp.EmployeeModel".<br />
11.<br />
12.<br />
Choose Build > Compile or Ctrl-F7 or the icon.<br />
Choose View > Web Page or the icon.<br />
The following figure shows the resulting form, with the values for record 5.<br />
has chosen controls for this form as follows:<br />
• for the Name, which is a %String<br />
• for the Salary, which is %Numeric<br />
• for the Active status, which is a %Boolean<br />
<strong>Using</strong> <strong>Zen</strong> 243
Model View Controller<br />
Property Type<br />
Boolean<br />
Date<br />
Date<br />
Enumerated<br />
Enumerated<br />
Numeric<br />
Object reference<br />
Stream<br />
Stream<br />
String<br />
String<br />
Public properties<br />
Private properties<br />
Controls Based on Property Types<br />
Details<br />
—<br />
In YYYY-MM-DD format<br />
In other formats<br />
<strong>Using</strong> a VALUELIST with 4 or fewer values<br />
<strong>Using</strong> a VALUELIST with more than 4 values<br />
—<br />
generates an SQL query<br />
Character<br />
Binary<br />
With MAXLEN over 250<br />
With MAXLEN between 1 and 250<br />
All types not listed above<br />
Any properties marked private<br />
Control<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Not displayed<br />
If you do not like the choices that makes, you can switch to and bind each control<br />
to a property individually, using the dataBinding attribute.<br />
13.6 with an Adaptor Data Model<br />
This topic explains how to use with a data controller when the data model is an adaptor<br />
data model. This approach is particularly convenient when you have an existing class with a large<br />
number of properties that you need to display on a form. In that case it would be extremely time-consuming<br />
to add these properties one by one to a subclass of %ZEN.DataModel.ObjectDataModel, as<br />
demonstrated in the previous topics. can save coding time, especially when you use it in<br />
combination with a subclass of %ZEN.DataModel.Adaptor. All you need to do then is to create a <strong>Zen</strong><br />
page class whose contains a and a . Your subclass of<br />
%ZEN.DataModel.Adaptor becomes the model, the view, and the controller, all in one. All of its properties<br />
become controls on the resulting . <strong>Zen</strong> generates the appropriate control type for<br />
property automatically.<br />
244 <strong>Using</strong> <strong>Zen</strong>
with an Adaptor Data Model<br />
13.6.1 Step 1: Generating the Form<br />
The basic outline for using with an adaptor data model is as follows:<br />
Note:<br />
This example is based on the <strong>Zen</strong> classes ZENMVC.MVCDynaForm, ZENMVC.Person, and<br />
ZENMVC.Address in the SAMPLES namespace.<br />
1. Edit a persistent class so that it also extends %ZEN.DataModel.Adaptor, for example:<br />
Class ZENMVC.Person Extends (%Persistent, %ZEN.DataModel.Adaptor)<br />
{<br />
Property Name As %String [ Required ];<br />
}<br />
Property SSN As %String;<br />
Property Salary As %Numeric;<br />
Property Active As %Boolean;<br />
Property Home As Address;<br />
Property Business As Address;<br />
The Person class includes properties defined by another class, Address, which must also extend<br />
%ZEN.DataModel.Adaptor but which need not be persistent, for example:<br />
Class ZENMVC.Address Extends (%SerialObject, %ZEN.DataModel.Adaptor)<br />
{<br />
Property City As %String(MAXLEN = 50);<br />
Property State As %String(MAXLEN = 2);<br />
Property Zip As %String(MAXLEN = 15);<br />
}<br />
2. Compile both data model classes.<br />
3. Create a new <strong>Zen</strong> page class.<br />
4. In XData Contents, place a and inside :<br />
<br />
<br />
<br />
<br />
5. Compile the <strong>Zen</strong> page class.<br />
6.<br />
Choose View > Web Page or the<br />
icon.<br />
generates the appropriate controls and displays the form, for example:<br />
<strong>Using</strong> <strong>Zen</strong> 245
Model View Controller<br />
13.6.2 Step 2: Property Parameters<br />
Once you have the basics in place, you may refine the form by assigning data model parameters to the<br />
properties in the persistent class that you are using as an adaptor data model. For example:<br />
1. Open the data model class Person from the previous exercise.<br />
2. Add data model parameters to the properties as shown below:<br />
Class ZENMVC.Person Extends (%Persistent, %ZEN.DataModel.Adaptor)<br />
{<br />
Property Name As %String (ZENLABEL = "Employee Name") [ Required ];<br />
Property SSN As %String (ZENREADONLY = 1);<br />
Property Salary As %Numeric (ZENHIDDEN = 1);<br />
Property Active As %Boolean (ZENLABEL = "Is this person working");<br />
Property Home As Address;<br />
Property Business As Address;<br />
}<br />
3. Compile the <strong>Zen</strong> page class.<br />
4.<br />
Choose View > Web Page or the<br />
icon.<br />
generates the appropriate controls and displays the form, for example:<br />
246 <strong>Using</strong> <strong>Zen</strong>
with an Adaptor Data Model<br />
The data model parameters have the following effects:<br />
• ZENHIDDEN hides the control associated with that property.<br />
• ZENLABEL replaces the default label (the property name) with a custom string.<br />
• ZENREADONLY displays the control but prevents the user from editing its contents.<br />
Note:<br />
A full list of parameters is available at the end of this chapter, in the topic Data Model Classes,<br />
subtopic Data Model Property Parameters.<br />
13.6.3 Step 3: Adding Behavior to the <br />
Adding behavior to a is quite similar to the steps outlined in the earlier topic, Adding<br />
Behavior to the :<br />
1. Open the <strong>Zen</strong> page class from the previous exercise.<br />
2. Add a control to display the current model ID value, and buttons to permit Update, New,<br />
and Save operations, as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 247
Model View Controller<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
3. Add the corresponding new client-side methods to the page class:<br />
Method loadRecord(id) [ Language = javascript ]<br />
{<br />
var controller = zenPage.getComponentById('source');<br />
}<br />
controller.setModelId(id);<br />
And:<br />
Method showRecord() [ Language = javascript ]<br />
{<br />
var controller = zenPage.getComponentById('source');<br />
}<br />
controller.update();<br />
And:<br />
Method newRecord() [ Language = javascript ]<br />
{<br />
var text = zenPage.getComponentById('idText');<br />
text.setValue("");<br />
var controller = zenPage.getComponentById('source');<br />
controller.createNewObject();<br />
}<br />
And:<br />
Method save() [ Language = javascript ]<br />
{<br />
var form = zenPage.getComponentById('MyForm');<br />
}<br />
form.save();<br />
4. Compile the <strong>Zen</strong> page class.<br />
5.<br />
Choose View > Web Page or the icon.<br />
6. Click the New button.<br />
7. Enter data in the fields (except ID) and click Save.<br />
8. Click the New button again, just to clear the fields.<br />
248 <strong>Using</strong> <strong>Zen</strong>
with an Adaptor Data Model<br />
9. Enter the number 1 in the ID field and click Update. The corresponding record displays. For<br />
example:<br />
Since you have provided no special format for model ID values in the Person class, the default<br />
prevails. This means each new record you add gets a sequential number starting at 1. You may<br />
add more records by repeating steps 6 and 7. The numbers increment automatically.<br />
If you try to view a record by entering an ID number that does not exist, the displays<br />
with all of its fields disabled. You may click New to redisplay an active form in which to enter<br />
data for a new record.<br />
13.6.4 Step 4: Virtual Properties<br />
If you want to interject changes in a data model before using it, you can override the<br />
%OnGetPropertyInfo method in the data model class. This is the way to add virtual properties that<br />
you want to use in the model, but that do not exist in the class that you began with. You can use<br />
%OnGetPropertyInfo with either type of data model, but it makes the most sense for an adaptor data<br />
model because in that case you are using an existing class as a data model.<br />
<strong>Using</strong> <strong>Zen</strong> 249
Model View Controller<br />
This exercise adds a %OnGetPropertyInfo method to the adaptor data model class Person from the<br />
previous exercises.<br />
1. Open the Person class in Studio.<br />
2. Choose Class > Override.<br />
3. Select %OnGetPropertyInfo and click OK.<br />
Studio adds a skeleton %OnGetPropertyInfo method to the class.<br />
4. Edit the method as follows:<br />
These statements add a and a to any generated by the model.<br />
ClassMethod %OnGetPropertyInfo(pIndex As %Integer,<br />
ByRef pInfo As %String,<br />
pExtended As %Boolean = 0) As %Status<br />
{<br />
#; Increment past the 3 embedded properties from the last Address object.<br />
#; This is not necessary when the last property in the Person object<br />
#; is a simple data type such as %String or %Boolean or %Numeric.<br />
Set pIndex = pIndex + 3<br />
#; add a field at the end of the form<br />
Set pInfo("Extra") = pIndex<br />
Set pInfo("Extra","%type") = "checkbox"<br />
Set pInfo("Extra","caption") = "Extra!"<br />
Set pInfo("Extra","label") = "This is an extra checkbox."<br />
Set pIndex = pIndex + 1<br />
#; add another field at the end of the form<br />
Set pInfo("Comments") = pIndex<br />
Set pInfo("Comments","%type") = "textarea"<br />
Set pInfo("Comments","caption") = "Please enter additional comments:"<br />
Set pIndex = pIndex + 1<br />
}<br />
Quit $$$OK<br />
5. Recompile the Person class.<br />
6. There is no need to recompile the Address class or the <strong>Zen</strong> page class.<br />
7. View the <strong>Zen</strong> page that contains the associated , it generates the appropriate controls<br />
and displays the form, for example:<br />
250 <strong>Using</strong> <strong>Zen</strong>
Data Model Classes<br />
13.7 Data Model Classes<br />
The basic behavior of data models comes from the base class %ZEN.DataModel.DataModel. This class<br />
defines the basic data model interface which is, in turn, implemented by subclasses. A data model<br />
class can be one of the following types:<br />
• The data model class serves as a wrapper for an independent data source. The data model object<br />
provides the interface and the source object (or objects) provide the actual data. In this case the<br />
data model class must implement the additional callback methods related to the data source object.<br />
Our form examples followed this convention by subclassing %ZEN.DataModel.ObjectDataModel<br />
and overriding several server-side callback methods.<br />
• The data model class is also the data source object. The data model object provides both the data<br />
and the interface. In this case, there is no need to override the callback methods related to the data<br />
source object. All you need to do is to make your data source class implement the<br />
<strong>Using</strong> <strong>Zen</strong> 251
Model View Controller<br />
%ZEN.DataModel.Adaptor interface. Then you can use the resulting class directly as the modelClass<br />
for the component in your page class.<br />
13.7.1 Data Model Class Properties<br />
The %ZEN.DataModel.DataModel class provides the following properties:<br />
• String that identifies the currently active instance of the data model object, also known as the<br />
model ID. This value can be initially set by providing a modelId attribute in the <br />
definition. The exact form and possible values of the model ID are up to the developer of a specific<br />
data model class. The property names are:<br />
- id — Use in JavaScript code that runs on the client side<br />
- %id — Use in ObjectScript or Basic code that runs on the server side<br />
For examples, see the exercises in Adding Behavior to the .<br />
• Array of strings that provide display names for the data series in the model. Each string labels one<br />
data series. The array is subscripted by series number (1–based). The property names are:<br />
- seriesNames — Use in JavaScript code that runs on the client side<br />
- %seriesNames — Use in ObjectScript or Basic code that runs on the server side<br />
• Number of data series contained within the data model. The property names are:<br />
- seriesCount — Use in JavaScript code that runs on the client side<br />
- %seriesCount — Use in ObjectScript or Basic code that runs on the server side<br />
For details about series, see Data Model Series, later in this topic.<br />
13.7.2 Data Model Class Parameters<br />
Data model classes provide class parameters that determine the type of data model. The following<br />
table lists them.<br />
252 <strong>Using</strong> <strong>Zen</strong>
Data Model Classes<br />
Data Model Class Parameters<br />
Property Parameter<br />
READONLYMODEL<br />
DYNAMICPROPERTIES<br />
Description<br />
1 (true) or 0 (false). If true, indicates that this is a read-only<br />
model. It can be used to display data but not to generate<br />
editable forms. The default is 0 (false).<br />
1 (true) or 0 (false). If true, indicates that this model supports<br />
virtual properties as described in the exercise <br />
with an Adaptor Data Model, Step 4: Virtual Properties, and<br />
in the later topic Virtual Properties. The default is:<br />
• 1 (true) for %ZEN.DataModel.ObjectDataModel<br />
• 0 (false) for %ZEN.DataModel.Adaptor<br />
13.7.3 Data Model Property Parameters<br />
The %ZEN.DataModel.DataModel class provides property parameters that you can apply to the data<br />
model properties that you wish to use as controls on a form. These parameters let you provide more<br />
specific control over the properties of the data model class. The utility class<br />
%ZEN.DataModel.objectModelParameters defines these parameters; the following table lists them.<br />
Note:<br />
For examples, use Studio to view the classes ZENMVC.FormDataModel and<br />
ZENMVC.FormDataModel2 in the SAMPLES namespace. Also see the exercises in<br />
with an Adaptor Data Model.<br />
Data Model Property Parameters<br />
Property Parameter<br />
ZENATTRS<br />
Description<br />
List of additional attributes to apply to the control used for this<br />
property. This string should have the following form:<br />
"attribute:value|attribute:value"<br />
ZENCONTROL<br />
ZENDISPLAYCOLUMN<br />
Type of control used to display this property within a form; If<br />
not defined, <strong>Zen</strong> chooses the control type based on the data<br />
type of the property.<br />
If defined, this is the name of the column used to provide a<br />
display value for SQL statements automatically generated for<br />
this property.<br />
<strong>Using</strong> <strong>Zen</strong> 253
Model View Controller<br />
Property Parameter<br />
ZENGROUP<br />
ZENHIDDEN<br />
ZENLABEL<br />
ZENREADONLY<br />
ZENSIZE<br />
ZENSQL<br />
ZENSQLLOOKUP<br />
ZENTAB<br />
ZENTITLE<br />
Description<br />
The id of a group component that the control used for this<br />
property should be added to. This provides a way to control<br />
layout. If not defined, the control is added directly to the form.<br />
1 (true) or 0 (false). If true, indicates that this is a hidden field.<br />
When the value of this field is sent to the client, it is not<br />
displayed. The default is 0 (false).<br />
Label used for this property within a form.<br />
1 (true) or 0 (false). If true, this is a read-only field and cannot<br />
be edited by the user. The default for is 0 (false).<br />
If specified, this overrides the default size of the control used<br />
to display the property within a form.<br />
If defined, this is an SQL statement used to find possible values<br />
for this property.This parameter corresponds to the sql property<br />
of the various data-driven <strong>Zen</strong> components. For details, see<br />
the chapter <strong>Zen</strong> Tables, topic Specifying an SQL Query.<br />
If defined, this is an SQL statement used to find the appropriate<br />
display value for a given logical value. This parameter<br />
corresponds to the sqlLookup property of the various data-driven<br />
<strong>Zen</strong> components. For details, see the chapter <strong>Zen</strong> Controls,<br />
topic Lists, subtopic Logical and Display Values.<br />
A positive integer. If specified, this will override the (1–based)<br />
default tab order of the control used to display the property<br />
within a form. All controls with ZENTAB specified are placed<br />
before controls that do not define it.<br />
Optional popup title string displayed for this property within a<br />
form.<br />
13.7.4 Object Data Model Callback Methods<br />
When you create an object data model, you subclass %ZEN.DataModel.ObjectDataModel and provide<br />
implementations for its server-side callback methods. The following table describes these methods in<br />
detail. You first encountered several of these methods in the exercise topic Constructing a Model, Step<br />
2: Object Data Model; the Example column indicates these.<br />
254 <strong>Using</strong> <strong>Zen</strong>
Data Model Classes<br />
Object Data Model Callback Methods<br />
Method<br />
%OnDeleteModel<br />
%OnDeleteSource<br />
%OnGetPropertyInfo<br />
%OnInvokeAction<br />
%OnLoadModel<br />
%OnNewSource<br />
%OnOpenSource<br />
%OnSaveSource<br />
%OnStoreModel<br />
Example<br />
—<br />
Yes<br />
—<br />
—<br />
Yes<br />
Yes<br />
Yes<br />
Yes<br />
Yes<br />
This Callback Method is Invoked When...<br />
The data model is deleted. This method is<br />
implemented by the subclasses of the data model<br />
class, if they exist.<br />
The data model is deleted. If implemented, it is<br />
responsible for deleting the object that has the given<br />
id and returning the status code resulting from that<br />
operation.<br />
The %GetPropertyInfo method invokes it. See the<br />
discussion following this table.<br />
A user-defined, named action is invoked on this<br />
model object. See the discussion following this table.<br />
This method is implemented by the subclasses of<br />
the data model class, if they exist.<br />
<strong>Zen</strong> does the actual work of loading values from the<br />
data source into the data model object.The only data<br />
to load is the data that is actually seen by the user.<br />
This is the place to perform any aggregation or other<br />
operations on the data before storing it.<br />
A data model needs a new instance. If implemented,<br />
it opens a new (unsaved) instance of the data source<br />
object used by the data model, and return its<br />
reference.<br />
A data model is opened. If implemented, it opens an<br />
instance of the data source object used by the data<br />
model, and returns its reference<br />
The data model is saved. If implemented, it is<br />
responsible for saving changes to the data source.<br />
It saves the given source object and return the status<br />
code resulting from that operation. Before returning<br />
the status code, it sets the data model’s %id property<br />
to the identifier for the source object.<br />
<strong>Zen</strong> does the actual work of copying values from the<br />
data model to the data source. This method loads<br />
data from the model (probably changed by the user<br />
through a form) back into the source object.<br />
<strong>Using</strong> <strong>Zen</strong> 255
Model View Controller<br />
Method<br />
%OnSubmit<br />
Example<br />
—<br />
This Callback Method is Invoked When...<br />
A form connected to this data model is submitted.<br />
The contents of this data model will be filled in from<br />
the submitted values before this callback is invoked.<br />
Implementing this callback is optional.<br />
13.7.5 Virtual Properties<br />
When a data controller needs to find information about the properties within a data model, it calls the<br />
data model’s %GetPropertyInfo method. This returns a multidimensional array containing details<br />
about the properties of the data model. The code that assembles this information is automatically<br />
generated based on the properties, property types, and property parameters of the data model class.<br />
A data model class can modify the property information returned by %GetPropertyInfo by overriding<br />
the %OnGetPropertyInfo callback method. %GetPropertyInfo invokes the %OnGetPropertyInfo<br />
immediately before it returns the property information. %OnGetPropertyInfo receives, by reference,<br />
the multidimensional array containing the property information. %OnGetPropertyInfo can modify<br />
the contents of this array as it sees fit. Properties can be added, removed, or have their attributes<br />
changed. Attributes that you add using this method are called virtual properties.<br />
Note:<br />
For examples, see the exercises in with an Adaptor Data Model, Step 4: Virtual<br />
Properties.<br />
The %OnGetPropertyInfo signature looks like this:<br />
ClassMethod %OnGetPropertyInfo(pIndex As %Integer,<br />
ByRef pInfo As %String,<br />
pExtended As %Boolean = 0,<br />
pModelId As %String = "",<br />
pContainer As %String = "") As %Status<br />
Where:<br />
• pIndex is the index number that should be used to add the next property to the list.<br />
• pInfo is a multidimensional array containing information about the properties of this data model.<br />
• If pExtended is true, then complete information about the properties should be returned; if false,<br />
then only property names need be returned (applications can simply ignore this).<br />
• pModelId is the id value of the current Data Model instance. This is provided for cases where the<br />
contents of a dynamic form may vary by instance of the Data Model object.<br />
• If this is an embedded property, pContainer is the name of the property that contains it.<br />
256 <strong>Using</strong> <strong>Zen</strong>
Within the %OnGetPropertyInfo method, the property information array pInfo is subscripted by<br />
property name. The top node for each property contains an integer index number used to determine<br />
the ordinal position of a property within a dynamically generated form:<br />
If you want %OnGetPropertyInfo to add a new property to a data model, simply add the appropriate<br />
nodes to the property information array. The new property will be treated as a “virtual” property. That<br />
is, you can set and get its value by name even though there is no property formally defined with this<br />
name. When adding a new property in %OnGetPropertyInfo, set the top level node to the current<br />
index number and then increment the index by 1:<br />
pInfo("Property") = pIndex<br />
Set pIndex = pIndex + 1<br />
The property information array has a number of subnodes that can be defined to provide values for<br />
other property attributes. Built-in attributes start with % and include:<br />
• pInfo("Property","%type") = "control"<br />
The %type subnode identifies the name of the <strong>Zen</strong> control that should be used for properties of<br />
this type when using a dynamic form. Note that this name is the class name of a component. If<br />
no package name is provided, it is assumed that this is a component in the %ZEN.Component<br />
package. Use a full class name if you wish to specify a component from a different package.<br />
• pInfo("Property","%group") = "groupId"<br />
The %group subnode indicates the id of a group component contained by a dynamic form. If<br />
%group is specified and there is a group with this id, then the control for this property will be<br />
created within this group. This provides a way to control the layout of controls within a dynamic<br />
form.<br />
Attributes that do not start with a % specify values that should be applied to a property of the control<br />
with the same name. For example, the following statement causes a dynamic form to set the label<br />
property of the control used for the MyProp property to "My Label".<br />
Set pInfo("MyProp","label") = "This is an extra field!"<br />
Data Model Classes<br />
Data models and data controllers each support the %OnGetPropertyInfo method. At runtime, the<br />
order in which <strong>Zen</strong> adds controls to the generated form is as follows:<br />
1. Creates an initial list of controls based on the data model properties and their parameters.<br />
2. Modifies this list of controls by calling the data model’s %OnGetPropertyInfo method, if present.<br />
3. Further modifies this list of controls by calling the data controller’s %OnGetPropertyInfo method,<br />
if present.<br />
<strong>Using</strong> <strong>Zen</strong> 257
Model View Controller<br />
13.7.6 Controller Actions<br />
The %OnInvokeAction callback lets you define “actions” that can be invoked on the data model via<br />
the data controller. The client can invoke an action by calling the dataController’s invokeAction<br />
method as follows:<br />
controller.invokeAction('MyAction',data);<br />
This, in turn, invokes the server-side %OnInvokeAction callback of the data model, passing the name<br />
of the action and the data value. The interpretation of the action name and data is up to the application<br />
developer.<br />
13.7.7 Data Model Series<br />
The basic data model object consists of a series of name-value pairs.<br />
Data Model with Name-Value Pairs<br />
The name-value pairs in the data model comprise all of the properties in the data model class, minus<br />
those properties marked ZENHIDDEN, plus any properties added by %OnGetPropertyInfo, minus<br />
any properties deleted by %OnGetPropertyInfo. By default, the number of series is 1, but it could<br />
be larger. If there are multiple series in the model, conceptually it becomes a matrix.<br />
258 <strong>Using</strong> <strong>Zen</strong>
Data Model Classes<br />
Data Model with Data Series<br />
You can add multiple series to the model if you write your own %OnLoadModel method, as in the<br />
SAMPLES class ZENMVC.ChartDataModel2, shown below. This example creates three series for the<br />
model and assigns values to data model properties in each of the series.<br />
Class ZENMVC.ChartDataModel2 Extends %ZEN.DataModel.ObjectDataModel<br />
{<br />
Property Cars As %Integer;<br />
Property Trucks As %Integer;<br />
Property Trains As %Integer;<br />
Property Airplanes As %Integer;<br />
Property Ships As %Integer;<br />
Method %OnLoadModel(pSource As %RegisteredObject) As %Status<br />
{<br />
Set scale = 100<br />
}<br />
#; This model has multiple data series. We set up the data series here.<br />
Set ..%seriesCount = 3<br />
Set ..%seriesNames(1) = "USA"<br />
Set ..%seriesNames(2) = "Europe"<br />
Set ..%seriesNames(3) = "Asia"<br />
#; Now we provide data for each property within each series.<br />
#; We use the %data array so that we can address multiple series.<br />
For n = 1:1:..%seriesCount {<br />
Set ..%data(n,"Cars") = $RANDOM(100) * scale<br />
Set ..%data(n,"Trucks") = $RANDOM(100) * scale<br />
Set ..%data(n,"Trains") = $RANDOM(100) * scale<br />
Set ..%data(n,"Airplanes") = $RANDOM(100) * scale<br />
Set ..%data(n,"Ships") = $RANDOM(100) * scale<br />
}<br />
Quit $$$OK<br />
}<br />
When your data model has multiple series, if you bind the data model to a chart, the chart automatically<br />
picks up the various series, although you need to be careful with a pie chart. Series work similarly for<br />
<strong>Using</strong> <strong>Zen</strong> 259
Model View Controller<br />
a grid. A form can only display one series at a time, so you need to rely on the data controller attribute<br />
defaultSeries to determine which series is currently in view.<br />
13.7.8 Custom Data Model Classes<br />
%ZEN.DataModel.ObjectDataModel or %ZEN.DataModel.Adaptor are sufficient for most needs. However,<br />
sometimes a developer might want to create a special category of data model, for example to represent<br />
a global. In that case the developer must subclass %ZEN.DataModel.DataModel and implement the<br />
details of this subclass.<br />
The following table lists methods that applications can call in order to work with a data model object.<br />
The behavior of these methods is up to the specific %ZEN.DataModel.DataModel subclass that implements<br />
them.<br />
Custom Data Model Class Methods<br />
Method<br />
%DeleteModel<br />
%OpenModel<br />
%SaveModel<br />
Description<br />
Delete an instance of a data model object given an identifier value.<br />
This takes the given identifier value and uses it to delete an instance<br />
of a source object (if applicable). (If the data model object serves as<br />
both interface and data source, then the data model object itself is<br />
deleted).<br />
Open an instance of a data model object given an identifier value.<br />
This takes the given identifier value and uses it to find an instance<br />
of a source object (if applicable) and then copies the appropriate<br />
values of the source object into the properties of the data model<br />
object. (If the data model object serves as both interface and data<br />
source, then this copying is not carried out).<br />
Save an instance of a data model object. This copies the properties<br />
of the data model object back to the appropriate source object (if<br />
applicable) and then asks the source object to save itself. (If the data<br />
model object serves as both interface and data source, then the data<br />
model itself is saved.).<br />
260 <strong>Using</strong> <strong>Zen</strong>
14<br />
Navigation Components<br />
The <strong>Zen</strong> Layout chapter, Groups topic introduced <strong>Zen</strong> group components as the key to laying out the<br />
<strong>Zen</strong> page. That chapter described the simple group components , , , ,<br />
and .<br />
This chapter describes a more complex set of group and menu components. A developer can use these<br />
components to support navigation through <strong>Zen</strong> applications:<br />
• Links — Link to other <strong>Zen</strong> pages, or other application content, via a URI.<br />
• Menus — Present and manage a structured set of choices, usually links.<br />
• Tabs — Define tabbed menus and tabbed forms.<br />
• — Display a group that expands or contracts when the user clicks on an icon.<br />
The following table organizes <strong>Zen</strong> navigation components into two categories: containers (at left) and<br />
contained (at right). This chapter describes each component in the order listed in the table.<br />
<strong>Using</strong> <strong>Zen</strong> 261
Navigation Components<br />
Container<br />
(Any)<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Purpose<br />
Provide a link to another page<br />
or to a popup message.<br />
Navigation bar for the top of<br />
the page.<br />
Menu container. The default<br />
layout is vertical but you can<br />
use the layout attribute to<br />
change to horizontal layout.<br />
Alternatively, you may use<br />
or .<br />
Horizontally oriented menu<br />
Vertically oriented menu<br />
Traditional set of tabs from<br />
which the user can choose<br />
one to be displayed on top of<br />
the set.<br />
A tabbed menu that displays<br />
a button for each tab. Clicking<br />
on a button makes the tab<br />
contents display beneath the<br />
button. Each tab consists of<br />
menu items.<br />
A tab is a group that may<br />
contain any combination of<br />
components.<br />
Expanding and contracting<br />
group which may contain any<br />
combination of components.<br />
Components It Typically Contains<br />
for each link.<br />
for each link in the<br />
navigation sequence.<br />
for each option.<br />
for the space<br />
between options.<br />
for each option.<br />
Inside a , each <br />
contains and<br />
components.<br />
For a simple navigation tree, you can<br />
provide components within<br />
.<br />
The following figure lists the components described in this chapter. All of the classes shown in the<br />
diagram are in the package %ZEN.Component, for example %ZEN.Component.tab. The diagram shows<br />
the inheritance relationships for these classes. It also highlights which of these components can contain<br />
other components, by showing which components inherit from %ZEN.Component.group.<br />
262 <strong>Using</strong> <strong>Zen</strong>
Links<br />
<strong>Zen</strong> Navigation Components<br />
14.1 Links<br />
The following <strong>Zen</strong> components provide links to content that is available via a URI:<br />
• <br />
• <br />
14.1.1 <br />
The component outputs a simple link (an HTML anchor element) to the <strong>Zen</strong> page. The default<br />
formatting for this type of link is to use color and underline it. has the following attributes.<br />
Attribute<br />
<strong>Zen</strong><br />
component<br />
attributes<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> component.<br />
The chapter <strong>Zen</strong> Style describes them.<br />
<strong>Using</strong> <strong>Zen</strong> 263
Navigation Components<br />
Attribute<br />
caption<br />
disabled<br />
href<br />
Description<br />
Text for this link in the <strong>Zen</strong> page display.<br />
The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />
expression. See <strong>Zen</strong> Runtime Expressions.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
If true, this link is disabled. The default is false. A newly disabled link is<br />
redisplayed, without an anchor tag, to ensure that it is truly disabled from<br />
the user’s point of view.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
URI of the content to display when the user clicks the caption text. If you<br />
want to invoke a client-side JavaScript method in the href, start the URI<br />
with javascript: as in:<br />
href="javascript:zenPage.myMethod();"<br />
The href value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
onclick<br />
(Optional) Client-side JavaScript expression that <strong>Zen</strong> invokes when the<br />
user clicks on the link. Generally this expression invokes a client-side<br />
JavaScript method.This method becomes the “onclick handler” for the link.<br />
If onclick is specified, href is ignored. If onclick is not specified, the link<br />
displays the content specified by href.<br />
When providing a value for an event handler attribute such as onclick, use<br />
double quotes to enclose the value and single quotes (if needed) within<br />
the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
style<br />
CSS style to apply to cells in this link, for example:<br />
color: red;<br />
264 <strong>Using</strong> <strong>Zen</strong>
Links<br />
Attribute<br />
title<br />
Description<br />
Help message to display when the user hovers the cursor over the link,<br />
without clicking.<br />
The title value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
One way to use is to place it within an component to present a tree-style menu of<br />
links.<br />
14.1.2 <br />
A looks like the following example, based on the class ZENTest.FormTest in the SAM-<br />
PLES namespace:<br />
The corresponding definition follows. As this example shows, entries<br />
within the display their caption values on the <strong>Zen</strong> page in sequential order, from left to<br />
right. The text for each caption is enclosed in square brackets. Captions are further separated by a right<br />
angle bracket to indicate the navigation sequence. The next topic provides additional details about<br />
attributes.<br />
<br />
<br />
<br />
<br />
<br />
has the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 265
Navigation Components<br />
Attribute<br />
<strong>Zen</strong> component<br />
attributes<br />
OnGetQuickLinks<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong><br />
component. The chapter <strong>Zen</strong> Style describes them.<br />
(Optional) Name of a server-side method that returns an array of<br />
“quick links.” If provided, these links are displayed in a dropdown<br />
list at the edge of the locator bar. The array is of the form:<br />
pLink("caption")=url<br />
The OnGetQuickLinks value must be the name of a server-only<br />
method in the page class that contains this form component.<br />
14.1.3 <br />
can appear only inside the container. Each defines one<br />
link within the navigation chain expressed in the . is the XML projection<br />
of the auxiliary class %ZEN.Auxiliary.locatorLink. has the following attributes.<br />
Attribute<br />
id<br />
name<br />
caption<br />
href<br />
Description<br />
This value can be used to select a CSS style definition for the .<br />
Component name. Typically, this is not used for .<br />
Text for this link in the .<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
URI of the content to display when the user clicks the caption text. If you<br />
want to invoke a client-side JavaScript method in the href, start the URI with<br />
javascript: as in:<br />
link="javascript:zenPage.myMethod();"<br />
title<br />
Help message to display when the user hovers the cursor over the link,<br />
without clicking.<br />
Although you enter ordinary text for this attribute, it has the underlying data<br />
type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />
languages. See <strong>Zen</strong> Localization.<br />
266 <strong>Using</strong> <strong>Zen</strong>
Menus<br />
14.2 Menus<br />
Menu components permit you to create classic navigation menus, with lists of choices from which the<br />
user can select an item by clicking on it. With each choice of a menu item, an event may occur<br />
depending on how the menu and menu item have been defined:<br />
• A submenu might display<br />
• A message might pop up<br />
• A different page might display<br />
• The contents of the current page might change<br />
• Something else might happen, depending on how you have programmed the menu to respond<br />
when the user selects each <br />
A vertical menu, expanded to three levels, looks like the following example, based on the class<br />
ZENTest.MenuTest in the SAMPLES namespace. Any options that produce submenus use the » right<br />
angle quote to indicate this, as shown for “Submenu” and “Sub Submenu”.<br />
The definition that produced this illustration is shown below:<br />
<strong>Using</strong> <strong>Zen</strong> 267
Navigation Components<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The next several topics explain details of the menu components in this example. For now, simply note:<br />
• In many cases, the example uses JavaScript alerts in place of URI links for demonstration purposes.<br />
link values can take this form, or they can redirect the browser to other pages in the <strong>Zen</strong> application,<br />
as the example shows:<br />
• A can contain a . If so, the contained becomes a submenu and its caption<br />
is listed in sequence along with any components at the same level. The above<br />
example provides three levels of .<br />
• The example provides a on the first- and third-level menus. Note how the<br />
component generates the divider bar between “Submenu” and “Test Suite” and<br />
between “Sub Submenu” and “Help Desk” in the output.<br />
14.2.1 <br />
Each item on a is defined using . has the following attributes. Since<br />
either of them may display their caption or image as a choice within a menu cell, and<br />
share all of these attributes in common. has additional attributes; the next topic<br />
describes them.<br />
Menu Cell Attributes<br />
Attribute<br />
<strong>Zen</strong><br />
component<br />
attributes<br />
Description<br />
and have the same general-purpose attributes<br />
as any <strong>Zen</strong> component. The chapter <strong>Zen</strong> Style describes them.<br />
268 <strong>Using</strong> <strong>Zen</strong>
Menus<br />
Attribute<br />
caption<br />
disabled<br />
help<br />
image<br />
Description<br />
Text for this menu item when it appears as a choice within its containing<br />
.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
If true, this menu item is disabled. The default is false.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
The help attribute supplies help text for this menu item.<br />
Generally what you want in place of help is the title attribute. title supplies<br />
tooltip text that displays whenever the user hovers the mouse over this<br />
item. All <strong>Zen</strong> components, including and , support<br />
the title attribute.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
Identifies the pathname and filename of an image to display for this<br />
menu item. If both image and caption are provided, they appear side<br />
by side, teh image at left and the text at right.<br />
The image path is relative to the Caché installation directory. Typically<br />
this path identifies the images subdirectory for your <strong>Zen</strong> application, for<br />
example:<br />
<br />
imageHeight<br />
imageWidth<br />
link<br />
If an image is provided, imageHeight is its height in pixels. The default<br />
is 16.<br />
If an image is provided, imageWidth is its width in pixels. The default is<br />
16.<br />
URI of the content to display when the user clicks the menu item. If you<br />
want to invoke a client-side JavaScript method in the link, start the URI<br />
with javascript: as in:<br />
link="javascript:zenPage.myMethod();"<br />
<strong>Using</strong> <strong>Zen</strong> 269
Navigation Components<br />
Attribute<br />
linkResource<br />
onclick<br />
Description<br />
Name of a Caché resource. The user must have privileges to access<br />
this resource or this menu item becomes disabled. If you are not familiar<br />
with Caché resources, see the Caché Security Administration Guide<br />
chapter Assets and Resources.<br />
(Optional) Client-side JavaScript expression that <strong>Zen</strong> invokes when the<br />
user clicks on the menu item. Generally this expression invokes a clientside<br />
JavaScript method. This method becomes the “onclick handler” for<br />
the menu item.<br />
If onclick is specified, link is ignored. If onclick is not specified, the menu<br />
item displays the content specified by link.<br />
When providing a value for an event handler attribute such as onclick,<br />
use double quotes to enclose the value and single quotes (if needed)<br />
within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
14.2.2 , , and <br />
All <strong>Zen</strong> groups that do not have a predefined layout setting have a vertical layout by default. This is<br />
true for the component. However, it can be useful to explicitly state the desired layout of the<br />
menu group. You can do this by:<br />
• Setting a value for the layout attribute (as in the example above)<br />
• Choosing one of the following in place of :<br />
- — a horizontally oriented list of choices<br />
- — a vertically oriented list of choices<br />
, , and have the following attributes.<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
Description<br />
A menu has the same style and layout attributes as any <strong>Zen</strong> group. The<br />
chapter <strong>Zen</strong> Layout describes them. The layout attribute does not apply<br />
to or because these components have layout set to<br />
"horizontal" and "vertical" respectively.<br />
270 <strong>Using</strong> <strong>Zen</strong>
Tabs<br />
Attribute<br />
<strong>Zen</strong> menu<br />
cell attributes<br />
onactivate<br />
Description<br />
A menu may display its caption or image as a choice within a menu cell.<br />
For this reason, , , and share a number of<br />
attributes in common with . See the previous topic.<br />
If this menu is a submenu, onactivate is the client-side JavaScript<br />
expression that <strong>Zen</strong> invokes just before the submenu is made visible.<br />
Generally this expression invokes a client-side JavaScript method. This<br />
method becomes the “onactivate handler” for the menu.<br />
When providing a value for an event handler attribute such as onactivate,<br />
use double quotes to enclose the value and single quotes (if needed)<br />
within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
onshowHelp<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user moves<br />
the mouse over this menu item. Generally this expression invokes a<br />
client-side JavaScript method.<br />
14.2.3 <br />
A bar helps to visually group the options on a . has the<br />
same general-purpose attributes as any <strong>Zen</strong> component. The chapter <strong>Zen</strong> Style describes them.<br />
has no additional attributes.<br />
14.3 Tabs<br />
The following <strong>Zen</strong> components support tabbed menus and forms for <strong>Zen</strong> applications:<br />
• <br />
• <br />
• <br />
<strong>Using</strong> <strong>Zen</strong> 271
Navigation Components<br />
14.3.1 <br />
A displays a set of components. It can only display one at a time. The user<br />
can choose one of these tabs to be displayed on top of the set. A looks like the following<br />
example, based on the class ZENTest.TabTest in the SAMPLES namespace.<br />
In the above example, the user has clicked the tab labelled “First Page.” In the following example, the<br />
user has clicked the tab labelled “Second Page” and has clicked the down-arrow to select a “Home<br />
City” option from the control.<br />
272 <strong>Using</strong> <strong>Zen</strong>
Tabs<br />
The definition that produces these illustrations is shown below:<br />
<strong>Using</strong> <strong>Zen</strong> 273
Navigation Components<br />
<br />
<br />
<br />
<br />
<br />
<br />
This is the first tab!<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
This is the second tab!<br />
<br />
<br />
<br />
<br />
This is the third tab!<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
has the following attributes. Since either or may display<br />
components, both and share these attributes in common. has additional attributes that distinguish it from ; the next topic describes them.<br />
274 <strong>Using</strong> <strong>Zen</strong>
Tabs<br />
Tab Group Attributes<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
currTab<br />
onhideTab<br />
Description<br />
and have the same style and layout<br />
attributes as any <strong>Zen</strong> group. The chapter <strong>Zen</strong> Layout describes them.<br />
1–based sequential number of the tab currently displayed. The default<br />
is 1.<br />
(Optional) Client-side JavaScript expression that <strong>Zen</strong> invokes when a<br />
previously displayed tab becomes hidden. Generally this expression<br />
invokes a client-side JavaScript method. This method becomes the<br />
“onhideTab handler” for the menu item.<br />
When providing a value for an event handler attribute such as onhideTab,<br />
use double quotes to enclose the value and single quotes (if needed)<br />
within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
onshowTab<br />
remember<br />
showTabBar<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when a previously<br />
hidden tab becomes the displayed tab. Generally this expression invokes<br />
a client-side JavaScript method.<br />
If true, remember the most recently displayed tab number in a session<br />
cookie and return to this tab when redisplayed. The default is false.<br />
remember has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
If true, display a set of tab buttons along the top of this group.The default<br />
is false.<br />
remember has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
14.3.2 <br />
A presents a stack of buttons, one for each tab. Clicking on a button shifts the other<br />
buttons down so that they display below the contents of the currently selected tab.<br />
<strong>Using</strong> <strong>Zen</strong> 275
Navigation Components<br />
The following example is based on the class ZENTest.LookoutMenuTest in the SAMPLES namespace.<br />
In the illustration, the user has clicked the “Animal” button to reveal the contents of that tab. This<br />
selection moved the remaining buttons to the bottom of the lookout menu. The cursor is now on the<br />
“Vegetables” menu item. If the user clicks this item, the contents of its link will be activated as defined<br />
in the corresponding .<br />
A contains a set of components, which in turn contain and<br />
components. These tabs are groups that can contain any component, but when they<br />
are present inside a they contain the components that would normally define a .<br />
The definition that produced the above illustration follows:<br />
276 <strong>Using</strong> <strong>Zen</strong>
Tabs<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
has the following attributes.<br />
Attribute<br />
<strong>Zen</strong> tab<br />
group<br />
attributes<br />
expandable<br />
Description<br />
shares a number of attributes in common with .<br />
See the previous topic. also has the attributes listed in this<br />
table.<br />
If true, this group is expandable. The default is false.<br />
When expandable is true, an expansion bar displays along the top of the<br />
as shown in the illustration above. The user clicks on this<br />
bar to toggle the expanded state of the . When the menu<br />
is contracted, only the expansion bar is visible. The user clicks the bar<br />
again to expand the .<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
<strong>Using</strong> <strong>Zen</strong> 277
Navigation Components<br />
Attribute<br />
expanded<br />
oncontract<br />
Description<br />
If true, this group is expanded (children visible). If false, it<br />
is contracted (children not visible). The default is true.<br />
expanded has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />
or false in client-side code. See Datatype Classes.<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes just before contracting<br />
(hiding) the children of this group. Generally this expression<br />
invokes a client-side JavaScript method. This method becomes the<br />
“oncontract handler” for the .<br />
When providing a value for an event handler attribute such as oncontract,<br />
use double quotes to enclose the value and single quotes (if needed) within<br />
the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
onexpand<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes just before expanding<br />
(displaying) the children of this group.<br />
14.3.3 <br />
A is a specialized group that defines a tab within a or . has<br />
the following attributes.<br />
278 <strong>Using</strong> <strong>Zen</strong>
Expanding Group<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
caption<br />
tabResource<br />
Description<br />
has the same style and layout attributes as any <strong>Zen</strong> group. The<br />
chapter <strong>Zen</strong> Layout describes them.<br />
Text for this tab when it appears as a choice within its containing or .<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
Name of a Caché resource.The user must have privileges to access this<br />
resource or this tab becomes disabled. If you are not familiar with Caché<br />
resources, see the Caché Security Administration Guide chapter Assets<br />
and Resources.<br />
14.4 Expanding Group<br />
The is a group with the ability to show or hide its children. A clickable graphic beside the<br />
label expands (displays) or contracts (hides) the contents of the group. A fully contracted<br />
group looks like the following example.<br />
The user expands the group by clicking on the plus sign beside its label. The contents of the<br />
then display below its label. As a <strong>Zen</strong> group, an may contain any type of <strong>Zen</strong><br />
component. In particular, each level of the may contain additional, nested <br />
groups that can be expanded or contracted independently of the containing group.<br />
In the following example, the user has just clicked on the plus sign to expand the group. The cursor is<br />
now poised to contract the by clicking the minus sign<br />
beside the label. This example<br />
<strong>Using</strong> <strong>Zen</strong> 279
Navigation Components<br />
contains three nested groups. The innermost uses a horizontal layout, and<br />
contains components instead of components as in the other levels.<br />
The definition that produced this example follows:<br />
280 <strong>Using</strong> <strong>Zen</strong>
Expanding Group<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
This definition references a number of methods defined in the page class. For example, the secondlevel<br />
references the server-side callback method DrawContent to produce additional formatted<br />
text, in this case a list of honors awarded to the author of the books listed. DrawContent looks<br />
like this:<br />
Method DrawContent(ByRef expando As %ZEN.Component.expando) As %Status<br />
{<br />
&html<br />
Quit $$$OK<br />
}<br />
The component has the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 281
Navigation Components<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
caption<br />
Description<br />
has the same style and layout attributes as any <strong>Zen</strong> group.<br />
The chapter <strong>Zen</strong> Layout describes them.The default layout<br />
is vertical.<br />
Text to display as the title of this group. This text displays<br />
even when the is contracted.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
childIndent<br />
expanded<br />
HTML length value giving the amount to indent the children in the<br />
expanded list of items. The above example uses 35px. The default is<br />
to use no indentation, aligning the children with the caption.<br />
If true, this group is expanded (children visible). If false, it<br />
is contracted (children not visible). The default is true.<br />
expanded has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
imageContracted<br />
(Optional) URI of the image to display when the group is<br />
contracted. The user clicks on this image to expand the group. The<br />
default for imageContracted is the plus sign<br />
whose URI is:<br />
/csp/broker/images/contracted.gif<br />
You may specify an alternate image. The path that you provide for<br />
imageContracted must be relative to the Caché installation directory.<br />
imageExpanded<br />
(Optional) URI of the image to display when the group is<br />
expanded. The user clicks on this image to contract the group. The<br />
default for imageExpanded is the minus sign<br />
whose URI is:<br />
/csp/broker/images/expanded.gif<br />
You may specify an alternate image. The path that you provide for<br />
imageExpanded must be relative to the Caché installation directory.<br />
282 <strong>Using</strong> <strong>Zen</strong>
Expanding Group<br />
Attribute<br />
oncontract<br />
Description<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes just before contracting<br />
(hiding) the children of this group. Generally this<br />
expression invokes a client-side JavaScript method. This method<br />
becomes the “oncontract handler” for the .<br />
When providing a value for an event handler attribute such as<br />
oncontract, use double quotes to enclose the value and single quotes<br />
(if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
OnDrawContent<br />
onexpand<br />
remember<br />
Optional. Name of a server-side callback method that provides<br />
additional HTML content for this component. If defined, this callback<br />
is invoked on the server when the component is drawn. It<br />
provides HTML content by using &html or the WRITE command.<br />
OnDrawContent must be the name of a server-only method in the page<br />
class that contains this view component; this method must return a<br />
%Status type.<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes just before<br />
expanding (displaying) the children of this group.<br />
If true, remember the most recent expanded state in a session cookie<br />
and return to this state when redisplayed. The default is false.<br />
remember has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
can be particularly useful in navigation when combined with .<br />
<strong>Using</strong> <strong>Zen</strong> 283
15<br />
Popup Windows and Dialogs<br />
This chapter describes <strong>Zen</strong> components that “pop up” to display their contents over the main application<br />
page. The tradeoff for the flexibility provided by these components is that you must provide more<br />
programming in the page class to make them effective. This chapter describes the following components:<br />
• Modal Groups — Make HTML content visible in response to a user event.<br />
• Popup Windows — Pop up a new window that displays a <strong>Zen</strong> page or any other content.<br />
• Dialogs — Pop up a dialog that prompts the user and accepts user input.<br />
15.1 Modal Groups<br />
A modal group is a specialized group component that normally does not display its contents. When<br />
the modal group is made visible, only its contents receive user events. Any event that occurs outside<br />
of the modal group (such as a mouse click) automatically hides the modal group. <strong>Zen</strong> uses this modal<br />
mechanism when it creates dropdown menus and dropdown combobox controls. You can also use this<br />
mechanism for popup items.<br />
You can define the contents of a modal group either by placing a component within<br />
the page class or by creating an instance of the %ZEN.Component.modalGroup class programmatically.<br />
There are three options:<br />
• Static — Place a component in the page class XData Contents block. Its contents<br />
remain hidden until a client-side method on the page calls the modalGroup show method.<br />
• Dynamic — Have the page call its createComponent method to create a modalGroup component<br />
dynamically. Add components to the group. Display it by calling the modalGroup show method.<br />
<strong>Using</strong> <strong>Zen</strong> 285
Popup Windows and Dialogs<br />
• Built-in — Have the page call the modalGroup show method to display one of the built-in modal<br />
groups: "msgBox" or "calendar"<br />
To close the current modal group, the page must invoke its endModal method. Generally endModal<br />
is triggered by an event handler for one of the buttons in the modal group (OK, Cancel, or similar). It<br />
is an error to call endModal if there is no modal group currently displayed.<br />
While a modal group has the editing focus, keyboard controls are disabled. For example, it is not<br />
possible to use Tab to move from field to field within the modal group. This prevents the user from<br />
(inadvertently) pressing Tab to navigate through all the fields and then back to the page, while the<br />
modal group has focus. The modal group keeps the focus until the user either clicks away from it or<br />
clicks the button that has been set up to close the modal group.<br />
Note:<br />
For Internet Explorer (IE) only: When displaying a modal group, <strong>Zen</strong> hides the contents of<br />
any elements (that is, SVG content). This is because IE ignores z-index setting for<br />
elements.<br />
15.1.1 Static Modal Groups<br />
In static mode, the modal group is defined within a page class XData Contents block using XML<br />
statements. The contents of the group are hidden until the modal group component’s show method is<br />
called; then they are displayed in a popup window.<br />
The following steps set this up in the page class:<br />
1. Supply a definition within the in XData Contents. For example:<br />
<br />
<br />
<br />
<br />
2. Provide a client-side method to display the modal group. For example:<br />
Method modalGroupStatic() [ Language = javascript ]<br />
{<br />
var group = this.getComponentById('mgStatic');<br />
}<br />
group.show();<br />
This method:<br />
• Finds the on the by calling getComponentById with the id value<br />
• Calls the client-side show method. No arguments are needed because the <br />
definition provides all the necessary information to show.<br />
286 <strong>Using</strong> <strong>Zen</strong>
3. Somewhere within the you must give the user a mechanism to invoke the<br />
modalGroupStatic method to display the modal group. The following example provides a button:<br />
<br />
4. For testing purposes, you may provide the with a field in which to echo the data from the<br />
popup:<br />
No data entered yet. <br />
The page XData Contents block now looks like this.<br />
<br />
No data entered yet. <br />
<br />
<br />
<br />
<br />
<br />
<br />
5. You must give the user a mechanism to close the popup. Additionally, if your popup invited the<br />
user to enter values, you will want to retrieve and use these values. The following client-side<br />
method in the page class does this:<br />
Method mgBtnClick() [ Language = javascript ]<br />
{<br />
// get value from text field<br />
var ctrl = zenPage.getComponentById('mgText');<br />
}<br />
// write user value into HTML component<br />
var html = zenPage.getComponentById('mgHtml');<br />
html.setProperty('content','User entered: ' + ctrl.getValue());<br />
// hide the modal group<br />
zenPage.endModal();<br />
This method:<br />
• Executes when the user clicks OK in the popup. This works because step 1 identified this<br />
method as the onclick event handler for the in the .<br />
• Finds the control from the by calling getComponentById with the<br />
id value<br />
• Gets the value entered into the control by calling getValue<br />
Modal Groups<br />
• Finds the component on the by calling getComponentById with the <br />
id value<br />
<strong>Using</strong> <strong>Zen</strong> 287
Popup Windows and Dialogs<br />
• Sets the content property of the component by calling setProperty. The new <br />
content concatenates a literal string with the newly-acquired value.<br />
• Calls the page’s endModal method to close the popup.<br />
The user may interact with this sample page as follows:<br />
1. The user initially sees:<br />
2. Clicking the button on this page invokes the modalGroupStatic method. This causes a window<br />
to pop up in front of the main page. The contents of the popup are the contents of the . The popup title is the groupTitle text.<br />
In the illustration below, the user has typed a value in the control within the popup:<br />
3. Clicking the OK button in this popup invokes the mgBtnClick method. This closes the popup<br />
and changes the contents of the component on the to echo the user input, as follows:<br />
The above example is similar to one available in the class ZENDemo.MethodTest in the SAMPLES<br />
namespace. You can try this sample from the <strong>Zen</strong> Demo main page by choosing Home, Overview,<br />
Methods, then Modal Group: Static.<br />
15.1.2 Dynamic Modal Groups<br />
In dynamic mode, the page creates a modal group component programmatically, by calling the clientside<br />
JavaScript methods createComponent, addChild, and setProperty. The sequence culminates<br />
in a call to the modalGroup show method with the appropriate arguments.<br />
The following steps set this up in the page class:<br />
1. Provide a client-side method to display the modal group. For example:<br />
288 <strong>Using</strong> <strong>Zen</strong>
Modal Groups<br />
Method modalGroupDynamic() [ Language = javascript ]<br />
{<br />
// create a modal group<br />
var group = this.createComponent('modalGroup');<br />
}<br />
// add components dynamically<br />
var col = this.createComponent('colorPicker');<br />
group.addChild(col);<br />
col.setProperty('id','myCol');<br />
var radio = this.createComponent('radioSet');<br />
group.addChild(radio);<br />
radio.setProperty('id','myRadio');<br />
radio.setProperty('valueList','elm,maple,oak');<br />
var btn = this.createComponent('button');<br />
group.addChild(btn);<br />
btn.setProperty('caption','Save');<br />
btn.setProperty('onclick','zenPage.btnClick();');<br />
// Show the group in "dynamic" mode.<br />
group.show('Dynamic Popup','dynamic',null,null,null,'236');<br />
This method:<br />
• Calls the page’s createComponent method to add a modalGroup component<br />
• Adds a colorPicker to the group<br />
- Calls the page’s createComponent method to create a colorPicker control<br />
- Calls the modal group’s addChild method to add the colorPicker to the group<br />
- Calls the color picker’s setProperty method to give the colorPicker an id value<br />
• Adds a radioSet to the group in the same way<br />
• Adds a button to the group in the same way<br />
• Calls the button’s setProperty method to set its onclick value to the name of a client-side<br />
method that will execute when the user clicks this button<br />
• Calls the modal group’s show method with these arguments:<br />
- A title for the popup window<br />
- The keyword 'dynamic'<br />
- The keyword null in argument positions three, four, and five<br />
- An optional width value of '236'<br />
For argument details see The show Method topic, below.<br />
2. Somewhere within the you must give the user a mechanism to invoke the<br />
modalGroupDynamic method to display the modal group. The following example provides a<br />
button:<br />
<strong>Using</strong> <strong>Zen</strong> 289
Popup Windows and Dialogs<br />
<br />
3. For testing purposes, you may provide the with a field in which to echo the data from the<br />
popup:<br />
No data entered yet. <br />
The page XData Contents block now looks like this.<br />
<br />
No data entered yet. <br />
<br />
<br />
4. You must give the user a mechanism to close the popup. Additionally, if your popup invited the<br />
user to enter values, you will want to retrieve and use these values. The following client-side<br />
method in the page class does this:<br />
Method btnClick() [ Language = javascript ]<br />
{<br />
// get values from controls<br />
var col = zenPage.getComponentById('myCol');<br />
var radio = zenPage.getComponentById('myRadio');<br />
}<br />
// write user values into HTML component<br />
var html = zenPage.getComponentById('mgHtml');<br />
html.setProperty('content','User entered: ' +<br />
col.getValue() + ' ' + radio.getValue());<br />
// hide the modal group<br />
zenPage.endModal();<br />
This method:<br />
• Executes when the user clicks Save in the popup. This works because step 1 identified this<br />
method as the onclick event handler for the Save button in the modal group.<br />
• Gets the color picker’s value as follows:<br />
- Finds the color picker control by calling getComponentById with the color picker id<br />
value<br />
- Gets the value entered into the color picker control by calling its getValue method<br />
• Gets the radio set’s value in the same way<br />
• Finds the component on the by calling getComponentById with the <br />
id value<br />
• Sets the content property of the component by calling setProperty. The new <br />
content concatenates a literal string with the newly-acquired color picker and radio set values.<br />
290 <strong>Using</strong> <strong>Zen</strong>
Modal Groups<br />
• Calls the page’s endModal method to close the popup.<br />
The user may interact with this sample page as follows:<br />
1. The user initially sees:<br />
2. Clicking the button on this page invokes the modalGroupDynamic method. This causes a window<br />
to pop up in front of the main page. The contents of the popup are the child components that<br />
modalGroupDynamic added. The popup title is the first argument that modalGroupDynamic<br />
passed to the show method.<br />
In the illustration below, the user has clicked on a color and a radio button:<br />
3. Clicking the Save button in this popup invokes the btnClick method. This closes the popup and<br />
changes the contents of the component on the as follows:<br />
15.1.3 Built-in Modal Groups<br />
In built-in mode, <strong>Zen</strong> dynamically creates and displays one of its built-in modal groups. This option<br />
is much simpler than the steps for a dynamic modal group. There are two options for built-in modal<br />
groups:<br />
• "calendar" — Display the built-in calendar box.<br />
• "msgBox" — Display the built-in message box.<br />
15.1.3.1 Calendar<br />
The following steps add a calendar popup to a <strong>Zen</strong> page class:<br />
1. Provide a client-side method to display the modal group.<br />
<strong>Using</strong> <strong>Zen</strong> 291
Popup Windows and Dialogs<br />
Method modalGroupCalendar() [ Language = javascript ]<br />
{<br />
var group = zenPage.createComponent('modalGroup');<br />
group.setProperty('onaction','zenPage.calendarAction(group);');<br />
group.show('Select a date:','calendar','2005-12-12');<br />
}<br />
This method:<br />
• Calls the page’s createComponent method to add a modalGroup component<br />
• Calls the modal group’s setProperty method to set its onaction value to the name of a clientside<br />
method that will execute when the user performs any action on this popup, such as<br />
selecting a date value from the calendar. This method accepts an argument, group, that represents<br />
the modalGroup instance.<br />
• Calls the modal group’s show method with three arguments:<br />
- A title for the popup window<br />
- The keyword 'calendar'<br />
- An optional pre-selected date for the calendar to display when it pops up<br />
2. Somewhere within the you must give the user a mechanism to invoke the method that<br />
displays the modal group. The following example provides a button:<br />
<br />
3. Finally, you must retrieve and use the date value acquired by the calendar control, and then close<br />
the popup. The following client-side method in the page class does this:<br />
Method calendarAction(group) [ Language = javascript ]<br />
{<br />
alert("You selected: " + group.getValue());<br />
}<br />
// write user value into HTML component<br />
var html = zenPage.getComponentById('mgHtml');<br />
html.setProperty('content','User entered: ' + group.getValue());<br />
This method:<br />
• Executes when the user clicks on a specific date value in the popup. This works because step<br />
1 identified this method as the onaction event handler for the modal group.<br />
• Calls the modal group’s getValue method to retrieve the date value entered into the calendar.<br />
• Issues a JavaScript alert message that confirms the value.<br />
• Finds the component on the by calling getComponentById with the <br />
id value<br />
292 <strong>Using</strong> <strong>Zen</strong>
Modal Groups<br />
• Sets the content property of the component by calling setProperty. The new <br />
content concatenates a literal string with the newly-acquired date value.<br />
• Does not call the page’s endModal method. The built-in calendar modal group closes automatically<br />
when the user chooses a date.<br />
The user may interact with this sample page as follows:<br />
1. The user initially sees:<br />
2. Clicking the button on this page invokes the modalGroupCalendar method. This causes a window<br />
to pop up in front of the main page. The popup title is the first argument that modalGroupCalendar<br />
passed to the show method. The currently selected date is the one specified by the third show<br />
argument.<br />
3. Selecting a different month, year, and date from the preselected value automatically invokes the<br />
calendarAction method. This closes the popup and displays a browser alert message that echoes<br />
the new date value:<br />
4. Dismissing the alert makes it easy to see that the contents of the component on the <br />
have now changed as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 293
Popup Windows and Dialogs<br />
The above example is similar to one available in the class ZENDemo.MethodTest in the SAMPLES<br />
namespace. You can try this sample from the <strong>Zen</strong> Demo main page by choosing Home, Overview,<br />
Methods, and Modal Group: Calendar.<br />
15.1.3.2 Message Box<br />
The following steps add a message box popup to a <strong>Zen</strong> page class:<br />
1. Provide a client-side method to display the modal group.<br />
Method modalGroupMsg() [ Language = javascript ]<br />
{<br />
var group = this.createComponent('modalGroup');<br />
group.show('My New Message','msgBox',<br />
'Thismessagecontains HTML!');<br />
}<br />
This method:<br />
• Calls the page’s createComponent method to add a modalGroup component<br />
• Calls the modal group’s show method with three arguments:<br />
- A title for the popup window<br />
- The keyword 'msgBox'<br />
- HTML-formatted message content for the popup message<br />
2. Somewhere within the you must give the user a mechanism to invoke the method that<br />
displays the modal group. The following example provide a button:<br />
<br />
3. When the user clicks this button, the popup displays:<br />
Clicking OK on the popup dismisses it.<br />
294 <strong>Using</strong> <strong>Zen</strong>
The above example is similar to one available in the class ZENDemo.MethodTest in the SAMPLES<br />
namespace. You can try this sample from the <strong>Zen</strong> Demo main page by choosing Home, Overview,<br />
Methods, and Modal Group: MsgBox.<br />
15.1.4 The show Method<br />
show is a client-side JavaScript method that displays a modal group. It has no return value, and up to<br />
eight optional arguments. Previous topics have discussed some of these arguments. A complete list<br />
follows:<br />
• title — Title for the popup window. For static modal groups, this overrides the groupTitle value<br />
in the definition.<br />
• type — One of the following keywords:<br />
- "calendar" — Display the built-in calendar box.<br />
- "dynamic" — Display a dynamically created modal group.<br />
- "msgBox" — Display the built-in message box.<br />
- "static" — Display a statically defined .<br />
If no type argument is supplied, the default is "static" if a definition exists<br />
within the . Otherwise the default is "dynamic".<br />
• value — Value to display when a built-in modal group is used. When the type is:<br />
- "calendar" — value is a date in YYYY-MM-DD format. When the window pops up, the<br />
calendar displays this month and year with value as a pre-selected date.<br />
- "msgBox" — value is the HTML-formatted message content for the popup message.<br />
• top — Vertical coordinate at which the top left corner of the window will pop up (0 is the top)<br />
• left — Horizontal coordinate at which the top left corner of the window will pop up (0 is far left)<br />
• wid — Width of the popup window<br />
• hgt — Height of the popup window<br />
Modal Groups<br />
• parms — Object containing a set of additional characteristics passed on to the modalGroup as a<br />
set of name-value pairs. Typically this offers a way to pass additional parameters to the popup<br />
calendar.<br />
<strong>Using</strong> <strong>Zen</strong> 295
Popup Windows and Dialogs<br />
15.1.5 Attributes<br />
The component is the XML projection of the %ZEN.Component.modalGroup class.<br />
The following table lists the attributes that are available when defining a <br />
within a page class XData Contents definition.<br />
296 <strong>Using</strong> <strong>Zen</strong>
Modal Groups<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
groupTitle<br />
okCaption<br />
onaction<br />
Description<br />
has the same style and layout attributes as any <strong>Zen</strong><br />
group. The chapter <strong>Zen</strong> Layout describes them.<br />
Title to display at the top of the modal group. For static modal groups,<br />
you can set the groupTitle value in the definition. Otherwise,<br />
this value is set dynamically by the first argument of the show<br />
method.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
Caption displayed in OK button for a message box. The default is "OK".<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
Client-side JavaScript expression that runs whenever the user takes<br />
action on a built-in modal group popup ("msgBox" or "calendar").<br />
Generally this expression invokes a client-side JavaScript method<br />
defined in the page class. This method becomes the “onaction event<br />
handler” for the .<br />
When providing a value for an event handler attribute such as onaction,<br />
use double quotes to enclose the value and single quotes (if needed)<br />
within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
onhideGroup<br />
onshowGroup<br />
seed<br />
Client-side JavaScript expression that runs when the modal group is<br />
hidden.<br />
Client-side JavaScript expression that runs when the modal group is<br />
made visible.<br />
Allows you to pass some arbitrary value to the onaction event handler.<br />
%ZEN.Component.modalGroup also has a value property is used to hold a value for the modal group.<br />
value is set by the show method; applications should not set this. However, it is sometimes useful to<br />
retrieve this value, for example when working with the built-in calendar modal group.<br />
<strong>Using</strong> <strong>Zen</strong> 297
Popup Windows and Dialogs<br />
15.2 Popup Windows<br />
A popup window is a new browser window that pops up over the currently active window in response<br />
to a user event. The popup window becomes the active window as soon as it is displayed, and remains<br />
dominant until the user closes it.<br />
To display a popup window from a <strong>Zen</strong> page, do the following:<br />
1. Open the <strong>Zen</strong> page class in Studio.<br />
2. Add a client-side method that calls the function zenLaunchPopupWindow, for example:<br />
Method showPopupWindow() [ Language = javascript ]<br />
{<br />
zenLaunchPopupWindow(<br />
zenLink('MyApp.MyDialog.cls'),<br />
'A True Dialogue',<br />
'status,scrollbars,resizable,width=400,height=300');<br />
}<br />
zenLaunchPopupWindow has the following arguments:<br />
• A string that identifies the content you wish to display, either:<br />
- The name of a <strong>Zen</strong> page class, including its package name and .cls extension<br />
- The URI of the desired content<br />
The zenLink function makes sure that any additional URI parameters, such as session tracking<br />
values, are included in the link. You may use zenLink with the class name or with any URI.<br />
In the following example, the client-side method uses JavaScript string concatenation to<br />
construct a URI from several disparate elements before making the call to<br />
zenLaunchPopupWindow. The example also uses the escape function to correctly format<br />
any variable values used in the string:<br />
Method editCSSValue(context) [ Language = javascript ]<br />
{<br />
var ctrl = this.getComponentById('value');<br />
var value = ctrl.getValue();<br />
var url = zenLink('%ZEN.Dialog.cssDeclarationEditor.clscontext='<br />
+ escape(context) + '&declaration=' + escape(value)<br />
);<br />
zenLaunchPopupWindow(url,<br />
'CSSDeclarationEditor',<br />
'resizable,width=500,height=700'<br />
);<br />
}<br />
• A string that identifies the popup window<br />
• A comma-separated list of window attributes expected by the JavaScript function<br />
window_open.<br />
298 <strong>Using</strong> <strong>Zen</strong>
Dialogs<br />
3. Provide a component on the page that invokes this method, for example:<br />
<br />
4. Override the onPopupAction method to retrieve and use the value returned by the popup. Use<br />
the exact method signature shown below. Within the method, you may use the value in any way<br />
you wish, for example:<br />
Method onPopupAction(popupName, action, value) [ Language = javascript ]<br />
{<br />
var html = zenPage.getComponentById('mgHtml');<br />
html.setProperty('content','User entered: ' + value);<br />
}<br />
5. Clicking the button on the page displays the popup window.<br />
zenLaunchPopupWindow supports a fourth parameter, an array of values intended to be used as URI<br />
parameters. You can use it to supply parameters for the URI so that you do not have to worry about<br />
correctly concatenating them to the string provided in the first parameter. The convention for this array<br />
is as follows:<br />
var parms = new Object();<br />
parms.Aaa = 10;<br />
parms.Bbb = 20;<br />
Now when you call zenLaunchPopupWindow with parms as its fourth parameter, the function uses<br />
Aaa and Bbb as parameters within the URI that you provided in the first parameter, and gives these<br />
parameters the values that you assigned to the corresponding members of the parms array.<br />
zenLaunchPopupWindow takes care of all the details of correctly escaping these parameters in the<br />
URI string.<br />
Important:<br />
When Internet Explorer is the browser, do not use a submit operation to save values<br />
from any popup window. Use a save operation instead.<br />
15.3 Dialogs<br />
<strong>Zen</strong> includes some built-in classes designed to work as popup dialog windows. A <strong>Zen</strong> dialog window<br />
can contain any of the usual <strong>Zen</strong> components. All dialog windows are subclasses of<br />
%ZEN.Dialog.standardDialog, which is a <strong>Zen</strong> page class. This base class provides classic dialog buttons<br />
such as OK, Apply, and Cancel, as well as conventions for retrieving the values entered into the dialog<br />
if the user clicks OK.<br />
This topic describes the conventions for working with <strong>Zen</strong> dialog windows:<br />
• Displaying the built-in file select window<br />
<strong>Using</strong> <strong>Zen</strong> 299
Popup Windows and Dialogs<br />
• Displaying the built-in color select window<br />
• Creating a new dialog window based on %ZEN.Dialog.standardDialog<br />
• Creating a new dialog window template, as an alternative to %ZEN.Dialog.standardDialog<br />
15.3.1 File Selection Dialog Window<br />
The %ZEN.Dialog.fileSelect window displays and lets the user choose from a list of directories and<br />
files on the server system. The resulting value is a full path and filename. To display the fileSelect<br />
dialog as a popup window, use the steps in the previous topic, but in step 2, provide a client-side<br />
method similar to the following:<br />
Method showPopupFile() [ Language = javascript ]<br />
{<br />
var pathname = '\Temp';<br />
var showdir = '0';<br />
zenLaunchPopupWindow(<br />
'%ZEN.Dialog.fileSelect.clsDir=' + escape(pathname) +<br />
'&showdirectoryonly=' + showdir,<br />
'FileSelectWindow',<br />
'status,scrollbars,resizable,width=660,height=700');<br />
}<br />
The method calls the client-side function zenLaunchPopupWindow with these arguments:<br />
• URI string beginning with the filename of the %ZEN.Dialog.fileSelect class. The filename is all<br />
that is needed, but in this case, the URI continues with various parameters, including:<br />
- Pathname for the file search window. This is either a full pathname or a path relative to the<br />
Caché system management directory (\mgr under the Caché installation directory). If omitted,<br />
the default is the Caché system management directory.<br />
- A showdirectoryonly value of 0 so that files will be visible in the display. You can omit<br />
this, as 0 is the default. Set showdirectoryonly to 1 if you want to show directories only.<br />
• Identifier for the popup window<br />
• Comma-separated list of popup window characteristics<br />
15.3.2 Color Selection Dialog Window<br />
The %ZEN.Dialog.colorSelect window lets the user choose from a set of colored cells. The resulting<br />
value is an HTML color value, such as #F3FDDA. To display the fileSelect dialog as a popup window,<br />
use the steps in the previous topic, but in step 2, provide a client-side method similar to the following:<br />
300 <strong>Using</strong> <strong>Zen</strong>
Dialogs<br />
Method showPopupColor() [ Language = javascript ]<br />
{<br />
zenLaunchPopupWindow(<br />
'%ZEN.Dialog.colorSelect.cls',<br />
'ColorPicker',<br />
'status,scrollbars,resizable,width=500,height=700');}<br />
This method calls the client-side function zenLaunchPopupWindow with arguments as follows:<br />
• Filename of the %ZEN.Dialog.colorSelect class<br />
• Identifier for the popup window<br />
• Comma-separated list of popup window characteristics<br />
15.3.3 Creating a Dialog Window<br />
To create a new type of <strong>Zen</strong> dialog window based on %ZEN.Dialog.standardDialog:<br />
1. Subclass %ZEN.Dialog.standardDialog.<br />
2. Add a new XData block with:<br />
• The name dialogBody<br />
• A as the container<br />
• An id value for the component that you identify as the source of user input<br />
For example:<br />
XData dialogBody<br />
{<br />
<br />
<br />
<br />
<br />
}<br />
3. Override the server-side callback method %OnGetTitle, for example:<br />
Method %OnGetTitle() As %String<br />
{<br />
Quit $$$TextHTML("This is My Dialog")<br />
}<br />
4. Override the server-side callback method %OnGetSubtitle, for example:<br />
Method %OnGetSubtitle() As %String<br />
{<br />
Quit $$$TextHTML("by John Smith")<br />
}<br />
5. Override the client-side JavaScript method getDialogValue so that it returns a value, for example:<br />
<strong>Using</strong> <strong>Zen</strong> 301
Popup Windows and Dialogs<br />
Method getDialogValue() [ Language = javascript ]<br />
{<br />
return this.getComponentById('yourReply').getValue()<br />
}<br />
6. To give the dialog an Apply button (in addition to the automatic OK and Cancel buttons) override<br />
the APPLYBUTTON parameter and set it to 1:<br />
Parameter APPLYBUTTON = 1;<br />
7. To enable the $$$Text localization macros, give the DOMAIN parameter a meaningful value:<br />
Parameter DOMAIN = "MyDomain";<br />
8. When displayed, this dialog appears as follows:<br />
15.3.4 Creating a Dialog Window Template<br />
Suppose you want to apply your own styling to the dialogs, rather than using the same layout and<br />
graphics as in the <strong>Zen</strong> standard dialog. The most straightforward way to accomplish this is to create<br />
a new dialog window template class and use it as an alternative to %ZEN.Dialog.standardDialog in the<br />
above instructions. The steps are:<br />
1. Subclass %ZEN.Dialog.standardDialog.<br />
2. In your subclass, apply the style differences you require.<br />
3. When creating new dialogs, extend the new subclass instead of extending<br />
%ZEN.Dialog.standardDialog<br />
4. When you need a file selector class:<br />
302 <strong>Using</strong> <strong>Zen</strong>
Dialogs<br />
• Copy the class %ZEN.Dialog.fileSelect<br />
• Edit the copy so that it extends your new dialog window template class instead of extending<br />
%ZEN.Dialog.standardDialog<br />
5. When you need a color selector class:<br />
• Copy the class %ZEN.Dialog.colorSelect<br />
• Edit the copy so that it extends your new dialog window template class instead of extending<br />
%ZEN.Dialog.standardDialog<br />
<strong>Using</strong> <strong>Zen</strong> 303
16<br />
Other <strong>Zen</strong> Components<br />
This chapter describes components that fit into none of the previously defined categories: layout, tables,<br />
meters, charts, forms, controls, menus, or popups. These are the “other” components, in approximate<br />
order of complexity:<br />
• — A snippet of arbitrary HTML content<br />
• — A static image or other content within a frame<br />
• — A non-visible component that fires an event after a time interval<br />
• — A group component that helps visually organize a form<br />
• — A large, detailed palette from which the user can select colors<br />
• — Repeat the same layout for each entry returned by a runtime query.<br />
• — Draw an expandable tree of links based on a global or callback method.<br />
• — Display a view box based on data provided by a callback method.<br />
If you have examined the full roster of components, including those listed above, and still do not see<br />
the functionality you need, consider adding a custom component to the <strong>Zen</strong> library. The Custom<br />
Components chapter provides full instructions.<br />
16.1 HTML Content<br />
The <strong>Zen</strong> component provides a way to place arbitrary HTML content within a <strong>Zen</strong> page. The<br />
HTML content is displayed within the <strong>Zen</strong> page exactly as specified. This content is drawn within an<br />
enclosing HTML in the same manner as any other <strong>Zen</strong> component.<br />
There are several ways to define the content displayed by the element:<br />
<strong>Using</strong> <strong>Zen</strong> 305
Other <strong>Zen</strong> Components<br />
• Literally specify the content within the component:<br />
<br />
This is some HTML.<br />
<br />
The content must be well-formed. That is, any HTML elements within the content must have<br />
matching closing elements, and any attribute values must be quoted correctly. The tag<br />
is not allowed.<br />
The content may not reference other <strong>Zen</strong> components. However, it may contain <strong>Zen</strong> #()# expressions.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
• Define a server-side OnDrawContent callback method that writes HTML content. If you define<br />
such a method, and reference it from the element, this method is called whenever the<br />
component is displayed.<br />
<br />
The method itself would look something like this:<br />
Method GetHTMLContent(pSeed As %String) As %Status<br />
{<br />
&html<br />
Quit $$$OK<br />
}<br />
• If you work with the component programmatically, you will see that it has a content<br />
property, a string of HTML statements. An initial value of the content can be set by placing the<br />
desired HTML tags in between the and elements in XData Contents, or by referencing<br />
an OnDrawContent callback.<br />
Client code can change the value of the content property by resetting it from JavaScript. For<br />
example:<br />
// get html content<br />
var html = zenPage.getComponentById('myContent');<br />
html.setProperty('content','some new content');<br />
The component has the attributes listed in the following table.<br />
306 <strong>Using</strong> <strong>Zen</strong>
Framed Content<br />
Attribute<br />
<strong>Zen</strong> component<br />
attributes<br />
OnDrawContent<br />
seed<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong><br />
component.<br />
Optional.The name of a server-side callback method that provides<br />
HTML content for this component, either by using &html or by<br />
using the WRITE command.<br />
The OnDrawContent value must be the name of a server-only<br />
method defined in the page class whose XData Contents references<br />
this component, and it must return the %Status data type.<br />
Optional. Allows you to pass some arbitrary value to the<br />
OnDrawContent callback.<br />
16.2 Framed Content<br />
The <strong>Zen</strong> component is a wrapper for the HTML element. It may display images<br />
or other content within a frame. <strong>Zen</strong> has the following attributes.<br />
Attribute<br />
<strong>Zen</strong><br />
component<br />
attributes<br />
longdesc<br />
frameAlign<br />
frameBorder<br />
scrolling<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> component.<br />
URI that provides the link to the long (text) description of the frame.<br />
The align value for the HTML : "left", "right", or "center".<br />
The frameborder value for the HTML . If true, the frame has a<br />
border; if false it does not have a border.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />
the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />
true or false in client-side code. See Datatype Classes.<br />
The scrolling value for the HTML : "auto", "yes", or "no".<br />
<strong>Using</strong> <strong>Zen</strong> 307
Other <strong>Zen</strong> Components<br />
Attribute<br />
src<br />
Description<br />
Identifies the pathname and filename of the frame content. The path is<br />
relative to the Caché installation directory, for example:<br />
<br />
If you wish to change the contents of the frame from the client, you can<br />
do so programmatically by resetting the value of the src property of the<br />
iframe object.<br />
If you wish to place an image on a button control, so that you can define an onclick event or other<br />
types of event for it, use the control component. See the <strong>Zen</strong> Controls chapter.<br />
16.3 Page Timer<br />
The component has no visual representation. It raises a client-side event after a specified time<br />
period. You may place a on the <strong>Zen</strong> page within XData Contents as follows:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
}<br />
has the following attributes.<br />
308 <strong>Using</strong> <strong>Zen</strong>
Field Sets<br />
Attribute<br />
ontimeout<br />
Description<br />
Client-side JavaScript expression that runs whenever the timer runs out.<br />
Generally the ontimeout expression invokes a client-side JavaScript<br />
method defined in the page class. This method becomes the “ontimeout<br />
event handler” for the timer. It must accept an argument, timer, that represents<br />
this timer object.The element can use the built-in variable<br />
zenThis to pass the timer object to the method.<br />
When providing a value for this attribute, use double quotes to enclose<br />
the value and single quotes (if needed) within the JavaScript expression.<br />
For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
timeout<br />
Number of milliseconds in the timer. <strong>Zen</strong> automatically starts the timer<br />
when the page is first loaded. When the timeout time has elapsed, <strong>Zen</strong><br />
fires the ontimeout expression.<br />
The example above sets a timeout value of 10,000 milliseconds. This<br />
provides an timeout value of 10 seconds.<br />
The client-side ontimeout method might look something like the following. A only fires its<br />
ontimeout event once, so your JavaScript method must restart the timer (by calling its startTimer<br />
method) before exiting. The following example does this:<br />
Method timeout(timer) [ Language = javascript ]<br />
{<br />
// ...do something<br />
}<br />
// restart the timer<br />
timer.startTimer();<br />
16.4 Field Sets<br />
A is a group component that draws an outer box around the children and displays a title<br />
within this box. This creates a visual panel that can help to organize a page. The following example<br />
from the SAMPLES namespace class ZENApp.HelpDesk defines a panel called “Details” that contains<br />
a form with several different controls.<br />
<strong>Using</strong> <strong>Zen</strong> 309
Other <strong>Zen</strong> Components<br />
The that produces the above example looks like this:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
A group may contain a , as above, or a may contain a . A<br />
provides a visual grouping only; it is not a <strong>Zen</strong> form, because it does not provide any form<br />
behavior such as validation or submit. has the following attributes:<br />
310 <strong>Using</strong> <strong>Zen</strong>
Color Selector<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
legend<br />
title<br />
Description<br />
A has the same style and layout attributes as any <strong>Zen</strong> group.<br />
The chapter <strong>Zen</strong> Layout describes them.<br />
Text specifying the caption to display for this . The legend<br />
can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong><br />
Runtime Expressions.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
Text specifying a popup message to display for this . The title<br />
can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong><br />
Runtime Expressions.<br />
Although you enter ordinary text for this attribute, it has the underlying<br />
data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />
into other languages. See <strong>Zen</strong> Localization.<br />
16.5 Color Selector<br />
The component lets the user view and select colors or enter RGB values in a large color<br />
palette. The palette is a grid that can be visualized as one possible slice from a three-dimensional cube<br />
of available colors. The captures a slice from the cube by accepting the user’s choice of<br />
one of three faces (red, green, or blue) and slicing through the cube, parallel to that face, at some saturation<br />
level (brighter or dimmer) to produce a grid of colors.<br />
From the user’s viewpoint, the has these features:<br />
• The user selects a color by clicking a square in the palette.<br />
• The user can cycle through different faces and slices of the color cube by clicking on the red,<br />
green, or blue color bars at left, bottom, and right. The segmented bar at left allows the user to<br />
select a slice that uses a brighter or dimmer range of color combinations.<br />
• The bar at top right displays the currently selected color and its corresponding HTML hexadecimal<br />
value. The user can copy (but not edit) the text value from this color bar.<br />
• At top left, the user can change the text entry fields R, G, and B to any number in the range 0–255,<br />
then click on the color bar at top right to apply these changes and see the result. The text fields R,<br />
G, and B also respond to user selections from the palette.<br />
<strong>Using</strong> <strong>Zen</strong> 311
Other <strong>Zen</strong> Components<br />
A with a color selected looks like this:<br />
has the following attributes. For a simpler color selection component, see .<br />
Attribute<br />
<strong>Zen</strong><br />
component<br />
attributes<br />
currCol<br />
currRow<br />
currSlice<br />
face<br />
Description<br />
has the same general-purpose attributes as any <strong>Zen</strong> component.<br />
The chapter <strong>Zen</strong> Style describes them.<br />
is not a full-blown control component, but it does allow the<br />
user to select a value, and it can be used within <strong>Zen</strong> forms. Any control<br />
attribute not listed in this table is not available for .<br />
0–based column number of the currently selected cell in the color palette.<br />
The default is 0. The range is from 0 to 15.<br />
0–based row number of the currently selected cell in the color palette. The<br />
default is 0. The range is from 0 to 15.<br />
0–based slice number of the currently selected slice of the 3–dimensional<br />
color cube. The default is 0. The range is from 0 to 15.<br />
Face number of the currently selected face of the 3–dimensional color cube:<br />
1, 2, or 3. The default is 1.<br />
312 <strong>Using</strong> <strong>Zen</strong>
Repeating Group<br />
Attribute<br />
onchange<br />
Description<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the value of the<br />
component changes. Generally this expression invokes a<br />
client-side JavaScript method. This becomes the “onchange handler” for<br />
the component.<br />
When providing a value for an event handler attribute such as onchange,<br />
use double quotes to enclose the value and single quotes (if needed) within<br />
the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />
Runtime Expressions.<br />
ondblclick<br />
value<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />
double-clicks on the component.<br />
String that identifies the most recently selected HTML hexadecimal value.<br />
The default is:<br />
#FFFFFF<br />
16.6 Repeating Group<br />
A is a specialized group component that defines the layout for a single group entry,<br />
then outputs multiple entries with this layout. The number of entries, and the data contained in each<br />
entry, is determined by a runtime query.<br />
has the following attributes.<br />
<strong>Using</strong> <strong>Zen</strong> 313
Other <strong>Zen</strong> Components<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
Data source<br />
attributes<br />
Description<br />
has the same style and layout attributes as any<br />
<strong>Zen</strong> group.The chapter <strong>Zen</strong> Layout describes them.The default layout<br />
for a is vertical.<br />
has the same attributes as for specifying<br />
a data source. For details and examples, see the <strong>Zen</strong> Tables<br />
chapter as follows:<br />
• How to use query attributes with :<br />
- Data Sources (maxRows)<br />
- Specifying an SQL Query (sql)<br />
- Referencing a Class Query (queryClass, queryName)<br />
• How to provide elements within :<br />
- Query Parameters<br />
The typical layout strategy for a repeating group is for the element to enclose a<br />
horizontal group that contains the individual entry. Since the default layout for a <br />
is vertical, the result of this arrangement is that each entry is laid out horizontally, while the set of<br />
entries is laid out from top to bottom.<br />
The following excerpt from an XData Contents block provides an example of this layout strategy for<br />
. This is similar to the XData Contents block in the class ZENTest.RepeatingGroupTest<br />
in the SAMPLES namespace. Note the that defines the individual entry. This <br />
contains a and an component.<br />
314 <strong>Using</strong> <strong>Zen</strong>
Repeating Group<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
#(%query.Title)#<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The following figure illustrates sample output from this excerpt. To produce this output, the user<br />
entered the key C, requested 10 rows, and then clicked Search. This caused <strong>Zen</strong> to display the repeating<br />
group using the first 10 entries that start with the letter C. The user then clicked an employee name in<br />
the group to display the alert window, which contains data retrieved from the server during the query.<br />
<strong>Using</strong> <strong>Zen</strong> 315
Other <strong>Zen</strong> Components<br />
16.7 Dynamic Tree<br />
The component displays a set of user-defined items as an expandable tree. In many ways<br />
is similar to . However, instead of specifying components, acquires<br />
its contents dynamically, using a global or callback.<br />
16.7.1 Defining a Tree <strong>Using</strong> a Global<br />
The simplest way to define a is to use a Caché global (multidimensional array). The following<br />
definition references the ^myTree global by providing the dataGlobal attribute:<br />
<br />
This definition causes the contents of the ^myTree global to be displayed on the page as nodes within<br />
an expandable tree.<br />
16.7.1.1 Node Labels<br />
Suppose you define ^myTree using the following statements at the Terminal command line:<br />
Set ^myTree("Root","Item 1") = "ZENMVC.MVCForm.cls"<br />
Set ^myTree("Root","Item 2") = "http://www.intersystems.com"<br />
Set ^myTree("Root","Item 2","SubItem") = "ZENDemo.Home.cls"<br />
Each global node now has one or more subscripts, such as "Root" or "Item 2". <strong>Zen</strong> uses these<br />
subscripts as labels for the nodes in the . Our ^myTree global can now generate a that looks like the following illustration. This is fully expanded, with the user<br />
holding the cursor over the node label "SubItem" at the lowest level.<br />
Important:<br />
When you use a global to define a , the resulting nodes always appear in<br />
alphabetical order (by label) because that is the way globals are organized in the<br />
database.<br />
16.7.1.2 Node Values<br />
When the user clicks on a node label such as:<br />
316 <strong>Using</strong> <strong>Zen</strong>
Dynamic Tree<br />
"SubItem"<br />
The corresponding node value is triggered. If the values are set as described in the previous topic, then<br />
this value is:<br />
"ZENDemo.Home.cls"<br />
Each node value is a string. Typically the node values are URI values. For example:<br />
• The name of a <strong>Zen</strong> page class:<br />
"ZENMVC.MVCForm.cls"<br />
• A Web site:<br />
"http://www.intersystems.com"<br />
• Or the URI of some other content.<br />
If you want a link to invoke JavaScript, you can start the URI with the string javascript: as in the<br />
following examples:<br />
• You can invoke a client-side JavaScript method in the page class:<br />
"javascript: zenPage.myMethod();"<br />
• Or simply execute a JavaScript expression:<br />
"javascript: alert('You clicked me!');"<br />
When providing a JavaScript expression, use double quotes to enclose the value and single quotes<br />
(if needed) inside the expression, as shown above.<br />
16.7.2 Defining a Tree <strong>Using</strong> a Callback<br />
can get its list of nodes by invoking a server-side callback method, defined in the page<br />
class. The method name is specified using the OnGetNodeInfo attribute. For example:<br />
<br />
<br />
<br />
<br />
This example defines a tree whose nodes are provided by the server-side callback method GetNodeInfo.<br />
When the user clicks on an item, the treeClick method is called. For a similar example, see the class<br />
ZENTest.DynaTreeTest in the SAMPLES namespace.<br />
<strong>Using</strong> <strong>Zen</strong> 317
Other <strong>Zen</strong> Components<br />
16.7.2.1 Callback Parameters<br />
A can contain zero or more elements. Each specifies an input<br />
parameter for the callback method that generates the . and both<br />
support this convention.<br />
Note:<br />
For examples, see ZENTest.DynaViewTest in the SAMPLES namespace.<br />
The element has the following attributes.<br />
Attribute<br />
paramName<br />
value<br />
Description<br />
The paramName must be unique within the . It becomes a<br />
subscript in the array of parameters passed to the callback method.<br />
The value supplied for a can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
16.7.2.2 Callback Method<br />
The OnGetNodeInfo attribute must identify a server-side callback method in the page class that contains<br />
the component. This callback is called repeatedly to get information about each node<br />
displayed within the tree. <strong>Zen</strong> handles this repetition as follows:<br />
• A tree contains a set of top-level nodes at level 1. A node may contain child nodes; each child is<br />
considered to have a level number one greater than its parent: 2, 3, 4, etc.<br />
• Starting with level 1, <strong>Zen</strong> calls the OnGetNodeInfo callback repeatedly until it returns false, indicating<br />
that there are no more nodes at the current level.<br />
• If a node reports that it has child nodes, <strong>Zen</strong> calls the OnGetNodeInfo callback repeatedly (with<br />
the appropriate value for pLevel) to get information on each child node until false is returned for<br />
that child level.<br />
The OnGetNodeInfo callback method must have a signature that looks like this:<br />
Method GetNodeInfo(Output tSC As %Status,<br />
ByRef pParams As %String,<br />
pLevel As %Integer,<br />
ByRef pHandle As %String,<br />
pNodeInfo As %ZEN.Auxiliary.NodeInfo) As %Boolean<br />
Where:<br />
• The method returns a %Boolean value indicating whether or not there is a node at the level indicated<br />
by pLevel.<br />
• tSC is a status code, returned by reference, that indicates success.<br />
318 <strong>Using</strong> <strong>Zen</strong>
• pParms represents any elements defined by the . pParms is an array.<br />
Each member of this array uses its paramName as a subscript and its value as a value.<br />
• pLevel is the current level of the tree.<br />
Dynamic Tree<br />
• pHandle is user-definable value that is passed, unchanged, to each call to the callback. The callback<br />
can use this store any state information it needs while providing the view information.<br />
• pNodeInfo is a pre-instantiated %ZEN.Auxiliary.NodeInfo object and is used to specify how the tree<br />
node should be displayed. A %ZEN.Auxiliary.NodeInfo object has the following properties.<br />
Property<br />
expanded<br />
hasChildren<br />
link<br />
Description<br />
If true, this node (if it has children) is initially displayed as expanded. If<br />
false, it is initially displayed as contracted. The default is true.<br />
expanded has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value 1 or 0 in server-side code, true or false in client-side code. See<br />
Datatype Classes.<br />
If true, this node has one or more child nodes. If this is the case, thenthe<br />
next call to the OnGetNodeInfo callback will be to fetch information about<br />
these child nodes. The default is true.<br />
hasChildren has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value 1 or 0 in server-side code, true or false in client-side code. See<br />
Datatype Classes.<br />
If non-empty, link defines a link that will be used if the user clicks on this<br />
node. This can be a URI such as the name of a page to display, or a<br />
JavaScript expression. If you want to invoke a client-side JavaScript<br />
method in the link, start the URI with javascript: as in:<br />
link="javascript:zenPage.myMethod();"<br />
When providing a JavaScript expression, use double quotes to enclose<br />
the value and single quotes (if needed) inside the expression.<br />
text<br />
value<br />
A string containing a value to display for this node within the tree.<br />
A string containing a logical value to associate with this node within the<br />
tree.<br />
<strong>Using</strong> <strong>Zen</strong> 319
Other <strong>Zen</strong> Components<br />
16.7.3 Attributes<br />
The component is the XML projection of the %ZEN.Component.dynaTree class. This<br />
topic has already described the dataGlobal and OnGetNodeInfo attributes in detail. The following<br />
table lists all the attributes.<br />
Attribute<br />
<strong>Zen</strong> group<br />
attributes<br />
childIndent<br />
dataGlobal<br />
Description<br />
has the same style and layout attributes as any <strong>Zen</strong><br />
group. The chapter <strong>Zen</strong> Layout describes them.<br />
HTML length value giving the amount by which each level within the<br />
dynaTree should be indented. The default is to use no indentation.<br />
Name of a Caché global (multidimensional array) that can provide<br />
the contents of the . This string must include the ^ prefix<br />
that is characteristic of Caché global names, for example:<br />
dataGlobal="^myTree"<br />
<strong>Using</strong> dataGlobal excludes OnGetNodeInfo. See Defining a Tree<br />
<strong>Using</strong> a Global.<br />
imageContracted<br />
(Optional) URI of the image to display when the is contracted.<br />
The user clicks on this image to expand the group. The<br />
default for imageContracted is the plus sign<br />
whose URI is:<br />
/csp/broker/images/contracted.gif<br />
You may specify an alternate image. The path that you provide for<br />
imageContracted must be relative to the Caché installation directory.<br />
imageExpanded<br />
(Optional) URI of the image to display when the is<br />
expanded. The user clicks on this image to contract the group. The<br />
default for imageExpanded is the minus sign<br />
whose URI is:<br />
/csp/broker/images/expanded.gif<br />
You may specify an alternate image. The path that you provide for<br />
imageExpanded must be relative to the Caché installation directory.<br />
320 <strong>Using</strong> <strong>Zen</strong>
Dynamic Tree<br />
Attribute<br />
onchange<br />
Description<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the current<br />
value of the changes. Generally this expression invokes<br />
a client-side JavaScript method.This method becomes the “onchange<br />
handler” for the .<br />
When providing a value for an event handler attribute such as<br />
onchange, use double quotes to enclose the value and single quotes<br />
(if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />
<strong>Zen</strong> Runtime Expressions.<br />
onclick<br />
ondblclick<br />
OnGetNodeInfo<br />
selectedIndex<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />
clicks on a node within the .<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />
double-clicks on a node within the .<br />
Name of a server-side callback method that reports information about<br />
each node within the tree. <strong>Using</strong> OnGetNodeInfo excludes<br />
dataGlobal. See Defining a Tree <strong>Using</strong> a Callback.<br />
0-based index of the currently selected node in the .The<br />
default selectedIndex is –1 (nothing is selected).<br />
When you work with %ZEN.Component.dynaTree programmatically, you must also know about the<br />
following properties of the dynaTree class:<br />
• Each element provided in the original definition in XData Contents<br />
becomes a member of the dynaTree parameters property, a list collection of<br />
%ZEN.Auxiliary.parameter object. Each acquires an ordinal position in the parameters<br />
collection: 1, 2, 3, etc.<br />
• The read-only text property holds the text (display) value of the currently selected node within<br />
the tree. This is the node label that displays in the .<br />
• The read-only value property holds the logical (actual) value of the currently selected node within<br />
the tree. This is the string that is activated when the user clicks the corresponding label in the<br />
.<br />
<strong>Using</strong> <strong>Zen</strong> 321
Other <strong>Zen</strong> Components<br />
16.8 Dynamic View<br />
The component displays a set of user-defined items within a view box, similar to the<br />
way a file dialog box might display a set of files or directories. items can displayed in<br />
one of two modes:<br />
• "list" — All items are displayed compactly in a grid. Only the first column of data is displayed.<br />
• "details" — Each item is displayed as one row within a table. Each row may present several<br />
columns of data.<br />
A in “details” mode looks like the following example, based on the class<br />
ZENTest.DynaViewTest in the SAMPLES namespace.<br />
16.8.1 Defining a View <strong>Using</strong> a Callback<br />
gets its list of items by invoking a server-side callback method, defined in the page class.<br />
The method name is specified using the OnGetViewContents attribute. For example:<br />
<br />
<br />
<br />
This example defines a view box whose items are provided by the server-side callback method<br />
GetViewContents. When the user clicks on an item, the viewChange method is called. For a similar<br />
example, see the class ZENTest.DynaViewTest in the SAMPLES namespace.<br />
16.8.1.1 Callback Parameters<br />
A can contain zero or more elements. Each specifies an input<br />
parameter for the callback method that generates the . and both<br />
support this convention.<br />
322 <strong>Using</strong> <strong>Zen</strong>
Dynamic View<br />
Note:<br />
For examples, see ZENTest.DynaViewTest in the SAMPLES namespace.<br />
The element has the following attributes.<br />
Attribute<br />
paramName<br />
value<br />
Description<br />
The paramName must be unique within the . It becomes a<br />
subscript in the array of parameters passed to the callback method.<br />
The value supplied for a can be a literal string, or it can<br />
contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />
16.8.1.2 Callback Method<br />
The OnGetViewContents attribute must identify a server-side callback method in the page class that<br />
contains the component. The callback method must have a signature that looks like this:<br />
Method GetViewContents(<br />
ByRef pParms As %String,<br />
Output pContents As %String,<br />
Output pHeaders As %String) As %Status<br />
Where:<br />
• The method returns a %Status value indicating success or failure.<br />
• pParms represents any elements defined by the . pParms is an array.<br />
Each member of this array uses its paramName as a subscript and its value as a value.<br />
• pContents is a multidimensional array that describes the set of items that will be displayed within<br />
the view box. The array is subscripted by item number (starting with 1). Each array element contains<br />
a $List structure containing the following information:<br />
Set pContents(n) =<br />
$ListBuild(textValue,logicalValue,icon,col2,col3,...))<br />
Where:<br />
- textValue is the value displayed for the item<br />
- logicalValue is a logical value associated with the item<br />
- icon is the URI of the image to be displayed with the item (if any)<br />
- Subsequent values define the values displayed in any additional columns when the dynaView<br />
is in “details” mode<br />
• pHeaders is a multidimensional array that provides a set of column headers, subscripted by column<br />
number. When the dynaView is in “details” mode, this is used to define how many columns of<br />
data to display and what the column headers are. For example:<br />
<strong>Using</strong> <strong>Zen</strong> 323
Other <strong>Zen</strong> Components<br />
// define 3 column headers<br />
Set pHeaders(1) = "Name"<br />
Set pHeaders(2) = "Size"<br />
Set pHeaders(3) = "Date"<br />
16.8.2 Attributes<br />
The component is the XML projection of the %ZEN.Component.dynaView class. This<br />
topic has already described the OnGetViewContents attribute in detail. The following table lists all the<br />
attributes.<br />
Property<br />
onchange<br />
Description<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the<br />
current value of the changes. Generally this<br />
expression invokes a client-side JavaScript method. This method<br />
becomes the “onchange handler” for the .<br />
When providing a value for an event handler attribute such as<br />
onchange, use double quotes to enclose the value and single<br />
quotes (if needed) within the JavaScript expression. For example:<br />
<br />
The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />
See <strong>Zen</strong> Runtime Expressions.<br />
onclick<br />
ondblclick<br />
OnGetViewContents<br />
rows<br />
selectedIndex<br />
viewType<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />
clicks on a node within the .<br />
Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />
double-clicks on a node within the .<br />
Name of a server-side callback method that provides the contents<br />
of the . See Defining a View <strong>Using</strong> a Callback.<br />
Number of rows to display when the is in list mode.<br />
0-based index of the currently selected node in the .<br />
The default selectedIndex is –1 (nothing is selected).<br />
Specifies how the contents of the should be displayed.<br />
Possible values are:<br />
• "list" — all items are displayed compactly in rows and columns<br />
• "details" — each item is displayed as one row within a table<br />
324 <strong>Using</strong> <strong>Zen</strong>
Dynamic View<br />
When you work with %ZEN.Component.dynaView programmatically, you must also know about the<br />
following properties of the dynaView class:<br />
• Each element provided in the original definition in XData Contents<br />
becomes a member of the dynaView parameters property, a list collection of<br />
%ZEN.Auxiliary.parameter object. Each acquires an ordinal position in the parameters<br />
collection: 1, 2, 3, etc.<br />
• The read-only text property holds the text (display) value of the currently selected node within<br />
the tree. This is the node label that displays in the .<br />
• The read-only value property holds the logical (actual) value of the currently selected node within<br />
the tree. This is the string that is activated when the user clicks the corresponding label in the<br />
.<br />
<strong>Using</strong> <strong>Zen</strong> 325
17<br />
Custom Components<br />
One of the most powerful features of the <strong>Zen</strong> framework is that it lets you easily develop new, reusable<br />
components that automatically work with other <strong>Zen</strong> components.<br />
The first chapter in this book, Introducing <strong>Zen</strong>, asserts that the <strong>Zen</strong> application development framework<br />
is extensible. The claim is certainly true. However, <strong>Zen</strong> anticipates many of the features that you might<br />
consider adding yourself. It is worthwhile to examine all of the available <strong>Zen</strong> components before<br />
beginning a custom development effort. Possibly, you will discover the features you want in a <strong>Zen</strong><br />
component that already exists.<br />
Following the introductory chapters <strong>Zen</strong> Component Concepts, <strong>Zen</strong> Layout, and <strong>Zen</strong> Style, this book<br />
presents the details of existing <strong>Zen</strong> components by category: tables, meters, charts, forms, controls,<br />
menus, popups, and other. After examining all of these chapters, you might find that you still wish to<br />
create custom components. If so, continue with this chapter to view the options and instructions for<br />
doing so.<br />
In general, the most common way to extend <strong>Zen</strong> is to create a custom component. Custom components<br />
fit into the existing <strong>Zen</strong> framework with minimal effort. They provide the style and behavior that you<br />
need while still obeying the <strong>Zen</strong> layout conventions and leveraging the <strong>Zen</strong> client/server framework.<br />
The following table describes options for creating custom components.<br />
<strong>Using</strong> <strong>Zen</strong> 327
Custom Components<br />
Options for Extending <strong>Zen</strong><br />
Task<br />
Build a composite<br />
component<br />
Modify component<br />
style<br />
Create a custom<br />
component<br />
Create a custom<br />
meter<br />
Description<br />
A composite arranges a group of existing, built-in <strong>Zen</strong><br />
components in a particular way.You can place this arrangement<br />
on the page as if it were a single component.<br />
You can make simple changes to the style of a built-in <strong>Zen</strong><br />
component by subclassing it and overriding its XData Style block.<br />
The chapter <strong>Zen</strong> Style, topic Overriding Built-in Styles explains<br />
how to do this.<br />
You can extend the roster of <strong>Zen</strong> components by writing a new<br />
component class. When you use <strong>Zen</strong> conventions to do this, the<br />
resulting class is automatically projected as XML for use in any<br />
<strong>Zen</strong> page XData Contents block.<br />
You can add a new type of meter to <strong>Zen</strong> by subclassing the base<br />
meter class and adding the method calls required to render the<br />
new meter’s SVG contents.<br />
17.1 Building Composite Components<br />
A composite component assembles a group of built-in <strong>Zen</strong> components and lets you refer to the group<br />
from XData Contents as if it were a single component. <strong>Zen</strong> places the children of the composite within<br />
the page’s object model as if XData Contents referenced them explicitly. This shorthand is convenient,<br />
and it also prevents errors when you want to repeat identical component arrangements on different<br />
pages.<br />
The following table is your checklist for building a composite component class. Not every item in the<br />
checklist is necessary for every composite. This checklist lists every possible item, and notes those<br />
that are optional. See the example of a composite component class that follows the table.<br />
Extending <strong>Zen</strong> with Composite Components<br />
Task<br />
Subclass<br />
Description<br />
Extend %ZEN.Component.composite to create a new class. The example<br />
creates a composite component class called myComposite in the MyApp<br />
package. Any class that extends %ZEN.Component.composite is a group,<br />
with all of the group layout and style attributes listed in the <strong>Zen</strong> Layout<br />
chapter.<br />
328 <strong>Using</strong> <strong>Zen</strong>
Building Composite Components<br />
Task<br />
Parameters<br />
Properties<br />
Methods<br />
XData<br />
Contents<br />
XML<br />
Element<br />
Description<br />
Provide class parameters and appropriate values. The NAMESPACE<br />
parameter is required to assign a namespace to the composite.You must<br />
reference this namespace when you place the composite component on<br />
a <strong>Zen</strong> page.<br />
(Optional) Provide properties, if needed. The example does not require<br />
any new properties for the subclass.<br />
(Optional) Provide supporting methods as needed for component behavior.<br />
The example provides an event handler method that is activated when<br />
the user clicks one of the buttons in the composite.<br />
Within the composite component class, define an XData Contents block<br />
that uses as its top-level element. The example provides<br />
two elements within .<br />
To add a composite element to a page, place its corresponding XML<br />
element in the page class XData Contents block.There is a specific syntax<br />
for this; see the example following this table.<br />
The following is a sample composite component class that provides two buttons:<br />
Class MyApp.myComposite Extends %ZEN.Component.composite<br />
{<br />
}<br />
/// Define xml namespace for this component<br />
Parameter NAMESPACE = "http://www.intersystems.com/myApp";<br />
/// Contents of this composite component:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
<br />
}<br />
Method okBtn() [Language = JavaScript]<br />
{<br />
alert('ok');<br />
}<br />
The correct way to reference this composite component from an XData Contents block is as follows:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
}<br />
<strong>Using</strong> <strong>Zen</strong> 329
Custom Components<br />
Where:<br />
• The element references the namespace defined for the composite component, and defines<br />
an alias for it, by providing the following attribute within the opening element:<br />
xmlns:myApp="http://www.intersystems.com/myApp"<br />
This statement defines an alias myApp for the namespace that was defined in the composite<br />
component class<br />
Parameter NAMESPACE = "http://www.intersystems.com/myApp";<br />
• The element references the myComposite component. This reference<br />
has the form:<br />
<br />
where alias is the namespace alias defined in the element (myApp in this case) and<br />
component is the name of the custom component class (myComposite in this case).<br />
17.1.1 The composite Property<br />
When you work with composite components programmatically, every component within a composite<br />
has a property called composite that points to the containing composite object. This makes it easy to<br />
define actions for a composite that refer to methods of the composite class. You can see this in the<br />
first element from the example above:<br />
<br />
The onclick attribute value for this definition uses zenThis.composite to represent the containing<br />
composite object. This convention allows the to call the okBtn method that is defined<br />
within the composite class.<br />
17.1.2 Composites and Panes<br />
To review panes and how their contents are defined, see the chapter <strong>Zen</strong> Layout.<br />
When a component is placed within a composite element, the contents of the pane can be<br />
defined within the composite class (or subclass of the composite). At runtime, the composite first looks<br />
for a pane with a given name within the current page; if it does not find it there, it looks within the<br />
composite class.<br />
330 <strong>Using</strong> <strong>Zen</strong>
17.2 Overriding Component Style<br />
Overriding Component Style<br />
If you have subclassed a built-in <strong>Zen</strong> component to modify styles already in use by a parent component,<br />
then the instructions in the chapter <strong>Zen</strong> Style, topic Overriding Built-in Styles, are sufficient. These<br />
are:<br />
1. Determine the relevant CSS style name<br />
2. Subclass the built-in <strong>Zen</strong> component<br />
3. Use the <strong>Zen</strong> Style Wizard to edit XData Style.<br />
If you want to define an entirely new CSS style (with a new name) and apply that style to a component,<br />
then there are additional steps to perform. You must not only define the CSS style, but also reference<br />
it from the class code that renders the custom component as HTML. At this point, you are truly creating<br />
a custom component. The next topic covers the necessary steps in detail.<br />
17.3 Creating Custom Components<br />
Each <strong>Zen</strong> component is implemented as a class and is completely self-contained. The component class<br />
specifies its own behavior (server and client methods) and appearance (SVG or HTML, DHTML, and<br />
stylesheets) in one logic unit: the class. Each component class has an XML projection. This projection<br />
consists of:<br />
• An XML element with the same name as the class (, , , etc.)<br />
• XML attributes, which are properties of that class (width, height, etc.)<br />
To build a <strong>Zen</strong> page you place a selection of the available XML elements and attributes in a wellformed<br />
XML document in the <strong>Zen</strong> page class. The container for this document is called XData Contents.<br />
At compile time, <strong>Zen</strong> generates the code required to display the page in the browser with the layout,<br />
style, and behavior that you have chosen for its components. At runtime, <strong>Zen</strong> handles all of the display<br />
details and correctly executes any snippets of JavaScript, HTML, or CSS that are embedded or referenced<br />
in the component or page classes.<br />
<strong>Zen</strong> components provide all of these features automatically because they inherit them from their base<br />
classes. This is something you can do yourself. To create a custom component, simply choose the<br />
appropriate base class and extend it. Your new class automatically gets the following features:<br />
• An XML projection to use in the page class XData Contents<br />
• Any properties, methods, parameters, or other characteristics of its parent(s)<br />
<strong>Using</strong> <strong>Zen</strong> 331
Custom Components<br />
• Appropriate handling of any client-side material in the class:<br />
- JavaScript<br />
- CSS style definitions<br />
- HTML<br />
- SVG<br />
• Properties can be exposed as settings, to be observed and modified using the client-side getProperty<br />
and setProperty methods.<br />
The following table is your checklist for creating a custom component class. The following topics<br />
describe each item in detail.<br />
Extending <strong>Zen</strong> with Custom Components<br />
Task<br />
Package<br />
XML Namespace<br />
Subclass<br />
Parameters<br />
XData Style<br />
Properties<br />
Methods<br />
%DrawHTML<br />
XML Element<br />
Description<br />
Use one class package for all your custom components.<br />
Use one XML namespace for all your custom components.<br />
Choose a base class from a short list of candidates.<br />
Provide class parameters, such as NAMESPACE.<br />
(Optional) Within the component class, provide an XData Style block<br />
that defines CSS styles.<br />
(Optional) Provide properties, if needed. The various properties of<br />
a component can be exposed as settings, and can be observed and<br />
modified using the client-side getProperty and setProperty<br />
methods.<br />
(Optional) Provide supporting methods as needed for component<br />
behavior.<br />
Within the component class, ensure that the %DrawHTML method<br />
references any new CSS styles. Visual components must draw the<br />
HTML (or SVG) needed to create their client-side visual<br />
representation.<br />
To add a custom component to a page, place its corresponding XML<br />
element in the page class XData Contents block. There is a specific<br />
syntax for this; see the Examples topic below.<br />
332 <strong>Using</strong> <strong>Zen</strong>
Creating Custom Components<br />
17.3.1 Package and Namespace<br />
The best practice is to use a common XML namespace for all your custom components (and only for<br />
custom components). Also, place all your component classes in their own package. There are two main<br />
reasons for these conventions:<br />
• Custom components need their own XML namespace to avoid conflict with other components.<br />
• The <strong>Zen</strong> framework automatically generates JavaScript and CSS stylesheet include files for your<br />
custom components. These files are generated on a per-class-package basis, so it is much easier<br />
to organize this if your custom components are contained within their own package.<br />
Whatever namespace you choose, it must specified by the NAMESPACE parameter within each custom<br />
component class that you create. For example:<br />
Parameter NAMESPACE = "http://www.mycompany.com/mycomponents";<br />
17.3.2 Base Class<br />
Choose a base class for the new component. There are five significant options to choose from. The<br />
following table and figure summarize the choices.<br />
Custom Component Base Classes<br />
Base Class<br />
%ZEN.Component.component<br />
%ZEN.Component.control<br />
%ZEN.SVGComponent.svgComponent<br />
%ZEN.SVGComponent.meter<br />
Purpose<br />
Visual, HTML based<br />
component.<br />
HTML based component<br />
can be placed within a<br />
form for the user to enter<br />
a value.<br />
Visual, SVG based<br />
component.<br />
Dynamically updated SVG<br />
graphic that displays a<br />
value.<br />
Inherited Attributes<br />
<strong>Zen</strong> components<br />
<strong>Zen</strong> components,<br />
<strong>Zen</strong> controls<br />
SVG components<br />
SVG components,<br />
meter components<br />
%ZEN.Component.object<br />
Non-visual component. Typically this is a helper<br />
object that is used by visual components and<br />
requires a client-side object representation.<br />
<strong>Using</strong> <strong>Zen</strong> 333
Custom Components<br />
Base Classes for Custom Components<br />
17.3.3 <strong>Zen</strong> Component Wizard<br />
Use the Caché Studio New <strong>Zen</strong> Component Wizard to create a new <strong>Zen</strong> component class. You can<br />
start the wizard using the Studio File New command, selecting the Custom tab, and clicking the New<br />
<strong>Zen</strong> Component icon.<br />
17.4 Custom Style<br />
To define a new CSS style for a custom component, you can place an XData Style block in the subclass.<br />
Within this block place a tag and a closing tag. Within<br />
the element, place whatever CSS style definitions you like.<br />
The built-in class %ZEN.Component.group includes the following XData Style block:<br />
334 <strong>Using</strong> <strong>Zen</strong>
Custom Style<br />
XData Style<br />
{<br />
<br />
/* @doc="Table used by groups." */<br />
table.group {<br />
padding: 0px;<br />
}<br />
/* @doc="Cell within table used by groups." */<br />
table.group td {<br />
padding: 0px;<br />
}<br />
/* @doc="Header within table used by groups." */<br />
table.group th {<br />
padding: 0px;<br />
}<br />
<br />
}<br />
Note the /* @doc="text" */ syntax in the above example. When you provide a comment for an<br />
XData Style entry using this syntax, the <strong>Zen</strong> Style Wizard automatically includes a description of your<br />
style in its list of available styles. To display this list while editing a <strong>Zen</strong> class in Studio, press CTRL-<br />
T to display the list of <strong>Zen</strong> templates. Select the <strong>Zen</strong> Style Wizard; a list of all defined styles appears.<br />
This list is organized alphabetically by component name.<br />
While viewing the list of styles in the <strong>Zen</strong> Style Wizard, you can select the radio button next to the<br />
name of the styles you want to edit and click OK. Templates for these styles appear in your XData<br />
Style block.<br />
Important:<br />
If you are overriding existing styles in a subclass of one of the built-in <strong>Zen</strong> components,<br />
the <strong>Zen</strong> Style Wizard offers the most convenient way to select the styles you want to<br />
override.<br />
The XData Style example above is a definition of styles for a built-in <strong>Zen</strong> component,<br />
%ZEN.Component.group. Suppose you wish to create a custom component with entirely new styles.<br />
In that case you will want to create styles named appropriately for your component. A component<br />
called MyComponent might include an XData Style block like the one shown below. <strong>Zen</strong> automatically<br />
includes this style definition in any page that uses in its XData Contents block:<br />
XData Style<br />
{<br />
<br />
/* @doc="Main style definition for MyComponent." */<br />
.MyComponent {<br />
color: blue;<br />
background: yellow;<br />
white-space: nowrap;<br />
}<br />
<br />
}<br />
Simply defining a XData Style block is not sufficient: the component class must actually use the newly<br />
defined CSS styles within the HTML that it generates. To accomplish this, you must provide a reference<br />
to the style in the %DrawHTML method that renders HTML for the custom component class. The<br />
<strong>Using</strong> <strong>Zen</strong> 335
Custom Components<br />
following sample %DrawHTML method references the MyComponent style defined in the XData<br />
Style example above:<br />
Method %DrawHTML()<br />
{<br />
&html<br />
}<br />
This sample %DrawHTML method uses a syntax that you see commonly throughout this book: &html<br />
followed by HTML statements enclosed in angle brackets . This is the ObjectScript syntax for<br />
embedded HTML statements. See the definition of the & symbol in the Caché ObjectScript Reference.<br />
By convention, any CSS style names you provide in an XData Style block should use a name that is<br />
related to the name of the component, as in the example above. This helps to avoid conflicts (which<br />
cannot be detected in advance due to the nature of CSS) and makes it easier for users to determine<br />
how to override styles. A component should never redefine a style defined by another component, or<br />
define an element-wide style selector (such as “input” or “table”), as this will cause interference with<br />
other components.<br />
Important:<br />
The chapter <strong>Zen</strong> Style, topic Cascade of Styles describes order of precedence rules<br />
for CSS styles defined in component, page, and application classes. Custom components<br />
are subject to these rules.<br />
17.4.1 XData SVGStyle<br />
XData Style does not apply to <strong>Zen</strong> SVG components. <strong>Zen</strong> SVG components use XData SVGStyle.<br />
To define styles for a custom <strong>Zen</strong> SVG component class, you can provide an XData SVGStyle block<br />
and add CSS statements between the tag and the closing <br />
tag. For example:<br />
XData SVGStyle<br />
{<br />
<br />
.customSVGComponent {<br />
fill: url(#myGrad);<br />
stroke: black;<br />
stroke-width: 2px;<br />
}<br />
<br />
}<br />
17.4.2 XData SVGDef<br />
The XData SVGStyle example above is from the class ZENTest.customSVGComponent in the SAMPLES<br />
namespace. It refers to a color myGrad as the fill color for the customSVGComponent shape.<br />
myGrad is defined in the same class, but in a separate block called XData SVGDef. This block defines<br />
myGrad as a shaded gradient from blue to red:<br />
336 <strong>Using</strong> <strong>Zen</strong>
Custom Properties<br />
XData SVGDef<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
17.4.3 <strong>Zen</strong> Color Definitions<br />
The built-in class %ZEN.SVGComponent.svgPage provides an XData SVGDef block with several<br />
useful color definitions:<br />
• The glow-silver color produces a metallic look for instrumentation items such as the<br />
meter.<br />
• Meters such as the traffic light use glow-red, glow-yellow, and glow-green for indicator lamps.<br />
• Lamp colors glow-blue, glow-purple, glow-orange, and glow-teal are also available.<br />
always references this class, or some subclass of it, through its svgPage attribute, so these<br />
colors are always available to any SVG component.<br />
17.5 Custom Properties<br />
Since a component is a class, it may define properties in addition to those it inherits. The definition of<br />
these properties influence how they work on the server, how they can be used within the component’s<br />
corresponding JavaScript class definition, and how they can be specified within an XML representation<br />
of the page.<br />
17.5.1 Naming Conventions<br />
The chapter <strong>Zen</strong> Tutorial, topic <strong>Zen</strong> Naming Conventions, describes the case-sensitive naming conventions<br />
for properties in <strong>Zen</strong> classes. Briefly:<br />
• Client-only properties: myProperty<br />
• Server-only properties (the % is essential): %MyProperty<br />
• Properties that invoke an event handler via Javascript: onmousedown<br />
• Properties that identify a server-side callback method: OnCreateDataSet<br />
• Other properties: myProperty<br />
<strong>Using</strong> <strong>Zen</strong> 337
Custom Components<br />
17.5.2 XML Projection<br />
All <strong>Zen</strong> components are derived from the %XML.Adaptor class and use its mechanisms for defining<br />
their XML behavior. If you would like more detail about this, see the book <strong>Using</strong> XML with Caché,<br />
chapter Controlling the Caché Object-XML Projection.<br />
All simple properties of <strong>Zen</strong> components should have an XMLPROJECTION value of "attribute". If<br />
you do not want to make a property visible via XML, set its XMLPROJECTION parameter to "none"<br />
as in the following example:<br />
Property beeswax As %ZEN.Datatype.string(XMLPROJECTION="none");<br />
Datatypes from the %ZEN.Datatype package use a default XMLPROJECTION value of "attribute" so<br />
that they will be projected as XML attributes. <strong>Zen</strong> datatypes offer many conveniences when you are<br />
defining properties in a custom component class. See the topic Datatype Classes below.<br />
17.5.3 setProperty Method<br />
If you add a property to a custom component class, you must override the setProperty method in the<br />
subclass to implement cases for each property that you have added to the class. You can default to the<br />
superclass method for properties of the superclass. There are several examples of this practice in the<br />
topics below.<br />
Near the end of each example of a custom component class is a setProperty method that implements<br />
cases for properties defined in that class. See the Odometer Meter Example and the Clock Meter<br />
Example.<br />
17.5.4 Datatype Parameters<br />
All <strong>Zen</strong> classes inherit (from %ZEN.componentParameters) the following set of property parameters,<br />
which you can apply to any property you add to a <strong>Zen</strong> class. The property does not need to have a <strong>Zen</strong><br />
datatype to use these parameters:<br />
• ZENENCRYPT<br />
• ZENEXPRESSION<br />
• ZENLOCALIZE<br />
• ZENSETTING<br />
17.5.4.1 ZENENCRYPT<br />
Set ZENENCRYPT to 1 (true) to specify that a property’s value will be encrypted (using the current<br />
session key) when it is sent to the client. If this value is returned to the server, it will be automatically<br />
338 <strong>Using</strong> <strong>Zen</strong>
decrypted. This makes it possible to place sensitive data on the client for future processing on the<br />
server without letting a user view this data.<br />
The ZENENCRYPT parameter applies only to code that <strong>Zen</strong> generates from the XML description<br />
within XData Contents in the page class. If you bypass XData Contents and work with <strong>Zen</strong> pages<br />
programmatically, then you are responsible for handling the equivalent encryption tasks.<br />
17.5.4.2 ZENEXPRESSION<br />
Set ZENEXPRESSION to 1 (true) to indicate that the property can interpret a <strong>Zen</strong> #()# expression to<br />
get its value at runtime. For details, see <strong>Zen</strong> Runtime Expressions.<br />
17.5.4.3 ZENLOCALIZE<br />
Any <strong>Zen</strong> property that has its ZENLOCALIZE parameter set to 1 (true) automatically generates a<br />
Message Dictionary entry that can be used to translate the value of the property into another language.<br />
This is described in detail in the chapter <strong>Zen</strong> Localization.<br />
It is a good practice to localize any string-valued properties that contain messages that you want to<br />
display to communicate with the <strong>Zen</strong> application user. It is convenient to give a property the <strong>Zen</strong><br />
datatype %ZEN.Datatype.caption, which always has ZENLOCALIZE set to 1 (true) but you can set<br />
ZENLOCALIZE directly if you want to.<br />
The ZENLOCALIZE parameter:<br />
Custom Properties<br />
• Applies only if the class that uses it also defines a localization domain by providing a value for<br />
the DOMAIN class parameter.<br />
• Applies only to code that <strong>Zen</strong> generates from the XML description within XData Contents in the<br />
page class. If you bypass XData Contents and work with <strong>Zen</strong> pages programmatically, then you<br />
are responsible for handling the equivalent localization tasks (including calls to $$$Text). See<br />
<strong>Zen</strong> Localization.<br />
17.5.4.4 ZENSETTING<br />
Set ZENSETTING to 1 (true) to specify that the property should be considered as a “setting” within<br />
the client class definition. This means that:<br />
• The property becomes visible to <strong>Zen</strong> utilities such as the Control Test page<br />
• You can observe and modify its value using the client-side getProperty and setProperty methods<br />
Every datatype class in the %ZEN.Datatype package already sets ZENSETTING to 1. When you use<br />
the %ZEN.Datatype classes, you must set ZENSETTING to 0 for any properties that you do not want<br />
to be treated as settings.<br />
<strong>Using</strong> <strong>Zen</strong> 339
Custom Components<br />
17.5.5 Datatype Classes<br />
For convenience, <strong>Zen</strong> provides a set of datatype classes that you can use when defining properties in<br />
<strong>Zen</strong> classes. The datatype classes are in the %ZEN.Datatype package. The following table lists them.<br />
When you define new <strong>Zen</strong> classes, you are free to use any datatype classes you wish. <strong>Using</strong> the<br />
%ZEN.Datatype classes makes it easier to understand the purpose of a property in the context of a Web<br />
application. Also, in many cases datatype classes automatically enable features that you would otherwise<br />
have to encode yourself, including easy localization, event handler conventions, and language-independence<br />
for Boolean values and list arrays.<br />
Fundamentally, all <strong>Zen</strong> datatypes classes are strings. All of the datatypes listed in the following table<br />
share the same base class, %ZEN.Datatype.datatype, whose value is defined as type %Library.String.<br />
As you can see from the entries in the table, each of these strings is interpreted by its subclass in a<br />
uniquely useful way.<br />
Datatype Classes<br />
Class<br />
align<br />
boolean<br />
caption<br />
classMember<br />
className<br />
color<br />
cssClass<br />
Description<br />
HTML horizontal alignment value. Possible values for this are “left”, “right”,<br />
and “center”. For vertical alignment values, see valign.<br />
Boolean value: It can have the text value "true" or "false" in XData<br />
Contents. When accessed programmatically from ObjectScript or Basic<br />
code running on the server, it can have the value 1 or 0. When accessed<br />
programmatically from JavaScript code running on the client, it can have<br />
the value true or false.<br />
String that is automatically added to the set of localized text resources<br />
when this property is initialized by an XData Contents block provided that<br />
the page has defined a localization DOMAIN and its ZENLOCALIZE<br />
parameter is set to 1. See <strong>Zen</strong> Localization.<br />
Name of a server-side class member (such as a property name or method<br />
name). This class defines a datatype parameter, MEMBERNAME, that<br />
indicates the type of class member. When using this datatype to define<br />
a property, you must also provide a value for its MEMBERNAME<br />
parameter. Possible values for MEMBERNAME are “PROPERTY”,<br />
“METHOD”, “QUERY”, “INDEX”, or “XDATA”.<br />
Name of a server-side class.<br />
CSS color value.<br />
Name of a CSS style class.<br />
340 <strong>Using</strong> <strong>Zen</strong>
Custom Properties<br />
Class<br />
csv<br />
delegator<br />
eventHandler<br />
Description<br />
Comma-separated list of values such as “John,Paul,George,Ringo”<br />
Name of a server-side method within the current page class that is used<br />
as a callback method. For example, the <strong>Zen</strong> component has an<br />
OnDrawContent attribute that specifies the name of a server-side callback<br />
method that provides HTML content by using &html or by using the WRITE<br />
command. If defined, this callback is invoked on the server whenever this<br />
component is drawn. In the underlying class %ZEN.Component.html,<br />
OnDrawContent is defined to be of type delegator.<br />
JavaScript expression to be executed on the client in response to a clientside<br />
event. As an event handler, this JavaScript expression is expected<br />
to invoke a client-side method that is the “handler” for this event.<br />
For example, the <strong>Zen</strong> component has an onclick attribute that<br />
specifies what should happen when a user clicks on the control. In the<br />
underlying class %ZEN.Component.button, onclick is defined to be of type<br />
eventHandler.<br />
You must use the eventHandler type if you wish to use the %GetEventHandlers<br />
helper method to access the event handler from %DrawHTML.<br />
The next topic explains the details.<br />
expression<br />
float<br />
glvn<br />
html<br />
id<br />
integer<br />
length<br />
list<br />
name<br />
Server-side ObjectScript expression.<br />
Floating point numeric value.<br />
Name of a Caché global (multidimensional array) such as “^myGlobal”.<br />
String of text that is marked up using HTML.<br />
The id value for a component. It must not be used for any other purpose.<br />
Integer value.<br />
HTML length value. For example: “5” or “5%”.<br />
On the server a list represents a set of items as a piece-delimited string.<br />
On the client the list is converted to a JavaScript array. This datatype has<br />
a DELIMITER parameter, the value of which is used to delimit the server<br />
representation of the list. The default DELIMITER value is $C(5).<br />
The name value for a component. It must not be used for any other<br />
purpose.<br />
<strong>Using</strong> <strong>Zen</strong> 341
Custom Components<br />
Class<br />
resource<br />
script<br />
sql<br />
string<br />
style<br />
svgStyle<br />
uri<br />
valign<br />
value<br />
Description<br />
Name of a Caché resource. If you are not familiar with Caché resources,<br />
see the Caché Security Administration Guide chapter Assets and<br />
Resources.<br />
Client-side JavaScript expression.<br />
SQL statement. By default, properties of this type are encrypted when<br />
sent to the client (the ZENENCRYPT parameter is set to 1).<br />
String with a default MAXLEN of 250. You can reset the MAXLEN value.<br />
CSS style statement. For example: "color:red; background:<br />
yellow;"<br />
SVG CSS style definition. Styles within SVG are CSS compliant, but there<br />
is a different set of styles available, so this datatype designates them.<br />
URI value. For example: “http://www.intersystems.com/zen”<br />
HTML vertical alignment value. Possible values are “top”, “bottom”, and<br />
“middle”. For horizontal alignment values, see align.<br />
A value to be used as the value of an HTML control.<br />
17.6 Custom Methods<br />
Since a component is a class, it may define methods in addition to those it inherits. The definitions of<br />
these methods influence where and how they can be used. These rules are exactly the same for methods<br />
in <strong>Zen</strong> component classes as they are for methods within a <strong>Zen</strong> page.<br />
The chapter <strong>Zen</strong> Application Programming, topic <strong>Zen</strong> Page Methods, describes these rules. The following<br />
table summarizes them.<br />
342 <strong>Using</strong> <strong>Zen</strong>
Custom Methods<br />
Component Class Method Conventions<br />
Callable<br />
From<br />
Runs On<br />
Code<br />
Language<br />
Keyword<br />
Naming<br />
Convention<br />
Client<br />
Client<br />
JavaScript<br />
Language =<br />
JavaScript<br />
myMethod<br />
Client<br />
Server (but can<br />
send back code<br />
that runs on the<br />
client)<br />
ObjectScript or<br />
Basic<br />
<strong>Zen</strong>Method<br />
MyMethod<br />
Server<br />
Server<br />
ObjectScript or<br />
Basic<br />
—<br />
%MyMethod<br />
The most important method in your custom component class is the required server-side method<br />
%DrawHTML. The following topics describe how to work with this method.<br />
17.6.1 %DrawHTML<br />
The %DrawHTML method is responsible for providing the HTML used to draw a <strong>Zen</strong> component.<br />
This method is called when the page containing the component is first served. It may subsequently be<br />
called if the page needs to dynamically refresh the contents of the component, such as when the query<br />
for a is re-executed.<br />
The basic operation of the %DrawHTML method is very simple: Any output that this method produces<br />
is served up as HTML within the browser. You can output from %DrawHTML using the WRITE<br />
command, as follows:<br />
Method %DrawHTML()<br />
{<br />
Write "This is some HTML!",!<br />
}<br />
As an alternative to WRITE, you can use the ObjectScript syntax for embedded HTML statements.<br />
This syntax uses &html followed by HTML statements enclosed in angle brackets as in the following<br />
example:<br />
Method %DrawHTML()<br />
{<br />
&html<br />
}<br />
Any output from %DrawHTML is enveloped by the component’s enclosing element, as supplied<br />
by the <strong>Zen</strong> framework.<br />
What makes this convention powerful is that %DrawHTML is an instance method of the component<br />
class: it can execute logic and has access to the component’s properties and methods, as well as the<br />
<strong>Using</strong> <strong>Zen</strong> 343
Custom Components<br />
underlying Caché database. It supports Caché ObjectScript expression, CSP #()# syntax, and <strong>Zen</strong> #()#<br />
expression syntax. The following simple example uses a number of these features:<br />
Method %DrawHTML()<br />
{<br />
#; draw items as specified by myCount<br />
For i=1:1:..myCount {<br />
&html<br />
}<br />
}<br />
17.6.2 Helper Methods for %DrawHTML<br />
The <strong>Zen</strong> framework defines three server-side helper methods for use in the %DrawHTML method<br />
for custom components: %MakeId, %Attr, and %GetEventHandlers. The class code for <br />
shows one way to use these methods effectively in %DrawHTML:<br />
344 <strong>Using</strong> <strong>Zen</strong>
Custom Methods<br />
Class %ZEN.Component.button Extends control<br />
{<br />
Parameter DEFAULTCONTROLCLASS = "button";<br />
/// Caption displayed for this button.<br />
/// This is a localized value.<br />
Property caption As %ZEN.Datatype.caption;<br />
/// defines style sheet used by this component<br />
XData Style<br />
{<br />
<br />
/* @doc="Style for button (input)." */<br />
.button {<br />
}<br />
<br />
}<br />
Method %DrawHTML()<br />
{<br />
Set disabled = $S(..disabled:"disabled",1:"")<br />
Set tIgnore("onchange") = ""<br />
&html<<br />
<br />
><br />
}<br />
/// This method fills in reasonable default values for<br />
/// this control. Used by tools (such as Control Tester) to<br />
/// dynamically create controls.<br />
Method %SetDefaultValues()<br />
{<br />
Set ..caption = "Button"<br />
}<br />
/// Set the value of a named property.<br />
Method setProperty(property, value, value2) [ Language = javascript ]<br />
{<br />
switch(property) {<br />
}<br />
}<br />
case 'caption':<br />
this.caption = value;<br />
var el = this.findElement('control');<br />
if (el) {<br />
el.value = this.caption;<br />
}<br />
break;<br />
case 'value':<br />
// do not set control value; just internal value<br />
this.value = value;<br />
break;<br />
default:<br />
// dispatch<br />
return this.invokeSuper('setProperty',arguments);<br />
}<br />
return true;<br />
Important:<br />
This example is close, but not identical, to the built-in class %ZEN.Component.button.<br />
The following topics discuss how each of the %DrawHTML helper methods is used:<br />
<strong>Using</strong> <strong>Zen</strong> 345
Custom Components<br />
• %MakeId — Generate the id value for the HTML element that displays the component on the<br />
page. Use a consistent naming scheme so that the client-side method findElement can find the<br />
HTML element on the page.<br />
• %Attr — Assign a value to an attribute of the HTML element that displays the component on the<br />
page. This method may be called repeatedly to assign values to all the HTML attributes required<br />
to render the component.<br />
• %GetEventHandlers — Retrieve all of the event handling information from the component definition,<br />
so that the HTML representation of the component can correctly match each user event<br />
with the code that should execute.<br />
17.6.3 Identifying HTML Elements<br />
The %MakeId server-side method ensures uniqueness for the id of every HTML element on the output<br />
page. The example in the previous topic calls %MakeId from embedded HTML to set the id for the<br />
HTML element as follows:<br />
id="#(..%MakeId("control"))#"<br />
%MakeId concatenates the string provided by the caller with the underscore character “_” followed<br />
by the unique sequential number that <strong>Zen</strong> assigns to every component it places on the page. It then<br />
gives this identifier to <strong>Zen</strong> to use as the value for the id attribute in the enclosing for the element.<br />
Additionally, if the component is part of a repeating group, <strong>Zen</strong> adds a further underscore character<br />
“_” followed by the tuple number.<br />
Thus, if you view the source of any generated <strong>Zen</strong> page you will see enclosing elements with<br />
generated id values like spacer_23 in the following example:<br />
<br />
The following more complex excerpt shows how <strong>Zen</strong> provides unique HTML id values for each element<br />
in a repeating group of radio buttons. This excerpt is part of the page that results when <strong>Zen</strong> renders<br />
the class ZENDemo.FormDemo from the SAMPLES namespace:<br />
346 <strong>Using</strong> <strong>Zen</strong>
<br />
Marital Status:<br />
<br />
<br />
<br />
<br />
Single <br />
<br />
<br />
Married <br />
<br />
<br />
Divorced <br />
<br />
<br />
Widowed <br />
<br />
<br />
Other <br />
<br />
<br />
<br />
The client-side equivalent for %MakeId is a JavaScript method called makeId. The custom meter<br />
component examples use makeId. See the Odometer Meter Example and the Clock Meter Example.<br />
17.6.4 Finding HTML Elements<br />
Custom Methods<br />
When you are writing client-side code and need to access a specific HTML element on the page, you<br />
can use the findElement method. Its argument is the value that you assigned to the id attribute when<br />
placing the component on the page. findElement combines this string with the sequential identifier<br />
for the element on the output page to generate the appropriate HTML id for the element on the output<br />
page. It uses this information to obtain a pointer to the component object within the page object model<br />
for the rendered page, then returns that pointer so that you can use properties and methods of the<br />
component object.<br />
Ordinary <strong>Zen</strong> components inherit findElement from %ZEN.Component.object. For SVG components<br />
you must use findSVGElement from %ZEN.SVGComponent.svgComponent. The custom meter<br />
component examples use findSVGElement.<br />
findElement and findSVGElement work correctly only if you have assigned HTML id values using<br />
%MakeId (on the server) or makeId (on the client).<br />
<strong>Using</strong> <strong>Zen</strong> 347
Custom Components<br />
17.6.5 Setting HTML Attribute Values<br />
The %Attr server-side method assigns a value to an attribute of the HTML element that displays the<br />
component on the page. This method may be called repeatedly to assign values to all the HTML<br />
attributes required to render the component. The following sample %DrawHTML method uses %Attr<br />
in rendering the component:<br />
Method %DrawHTML()<br />
{<br />
Set disabled = $S(..disabled:"disabled",1:"")<br />
Set tIgnore("onchange") = ""<br />
&html<br />
}<br />
Suppose the value of the controlStyle attribute is currently myActionStyle. As the<br />
%DrawHTML method outputs HTML, an expression in this format:<br />
#(..%Attr("style",..controlStyle))#<br />
Generates the following output:<br />
style="myActionStyle"<br />
17.6.6 Attaching Event Handlers to HTML Elements<br />
The %GetEventHandlers server-side method gets all the event handler attributes for a given component<br />
and uses them to write out any event handler attributes for the HTML that displays that component in<br />
the output page.<br />
Important:<br />
%GetEventHandlers can only find event handler attributes whose underlying property<br />
has been defined using the datatype class %ZEN.Datatype.eventHandler.<br />
The chapter <strong>Zen</strong> Controls, topic Control Attributes lists the event handler attributes that you can<br />
specify for a control component on a <strong>Zen</strong> form. The types of events covered by this list include mouse<br />
movements, mouse clicks, or key clicks. Other types of <strong>Zen</strong> component have event handlers, but controls<br />
offer the single largest pool for comparison.<br />
Preceding chapters have explained that to set up an event handler for a built-in <strong>Zen</strong> component you<br />
must specify a JavaScript expression as the value of the corresponding event handler attribute. Generally<br />
this JavaScript expression invokes a client-side method that serves as the “handler” for this event. Of<br />
course, if you set up the component this way you must also write the client-side method that is being<br />
invoked.<br />
348 <strong>Using</strong> <strong>Zen</strong>
For custom components, you must take additional steps to connect each user event with its appropriate<br />
handler. This connection takes place in the %DrawHTML method for the custom component. Consider<br />
the %DrawHTML method for the component:<br />
Method %DrawHTML()<br />
{<br />
#; handle onclick directly<br />
Set tIgnore("onclick")=""<br />
Set tIgnore("onchange")=""<br />
#; select image to display<br />
Set tSrc = ..src<br />
If (..streamId '= "") {<br />
Set tSrc = ##class(%CSP.Page).Link(<br />
"%25CSP.StreamServer.clsSTREAMOID="_$ZCVT(..streamId,"O","URL"))<br />
}<br />
Custom Methods<br />
#; disabled logic<br />
Set tSrc = $Case(..disabled,0:tSrc,:$S(..srcDisabled="":tSrc,1:..srcDisabled))<br />
}<br />
&html<br />
In the above example, some interesting things take place with regard to event handlers. The following<br />
line tells %GetEventHandlers to ignore any value provided for the onchange event handler, even if<br />
it discovers that there is such a value:<br />
Set tIgnore("onchange") = ""<br />
You must provide one such line for each event handler that you want to handle directly in<br />
%DrawHTML, as shown for onclick and onchange in the example above. Then, at the end of<br />
%DrawHTML, pass the variable tIgnore to %GetEventHandlers by reference, as shown in the<br />
example:<br />
#(..%GetEventHandlers(.tIgnore))#<br />
The %DrawHTML example above asks %GetEventHandlers to ignore onclick and onchange, but<br />
for different reasons in each case: ignores onchange because it does not accept user input.<br />
ignores onclick because it is designed to handle all onclick events in the same way, without<br />
permitting the <strong>Zen</strong> programmer to specify a different behavior in the page class. Therefore, it provides<br />
code in %DrawHTML to handle this event directly. Any event handlers that are not expressly ignored<br />
by %DrawHTML in this way are written out to the page exactly as defined by the <strong>Zen</strong> programmer.<br />
Now consider this expression from the example above:<br />
#($S(..onclick="":"",1:"class=""imageLink"""))#<br />
This expression uses the ObjectScript $SELECT function to return the first true expression it<br />
encounters in a list of expressions. Looking at the expressions provided: If the component’s<br />
<strong>Using</strong> <strong>Zen</strong> 349
Custom Components<br />
onclick attribute value is an empty string, this statement writes an empty string. Otherwise, this statement<br />
formats the HTML element on the output page by writing out the following string:<br />
class="imageLink"<br />
The following expression directs the client-side HTML page to invoke the component’s imageClick<br />
method in response to any user mouse clicks on the corresponding HTML element.<br />
onclick="zenPage.getComponent(#(..index)#).imageClick();"<br />
The imageClick method is a client-side JavaScript method in the component class. It uses<br />
the JavaScript helper method zenInvokeCallbackMethod to invoke onclick callback method for this<br />
component. The imageClick method looks like this:<br />
Method imageClick() [ Language = javascript ]<br />
{<br />
if (!this.disabled) {<br />
// invoke callback, if present<br />
zenInvokeCallbackMethod(this.onclick,this,'onclick');<br />
}<br />
}<br />
Where the zenInvokeCallbackMethod arguments are as follows:<br />
• this.onclick — The component’s onclick attribute value (a JavaScript expression that invokes<br />
a client-side JavaScript method)<br />
• this — A pointer to the component object<br />
• 'onclick' — The HTML name for the event (must be quoted)<br />
This completes the connection between the HTML element, the event, and its handler. You must provide<br />
similar conventions for any event that you intend your custom component to support.<br />
17.6.7 HTML for Dynamic Components<br />
%DrawHTML works differently for components that change in response to runtime information or<br />
that are generated using SVG.<br />
The is an example of a component that writes no static HTML at all. Its %DrawHTML<br />
method simply sets the values of properties such as the currently selected month and date, in preparation<br />
for the more complex JavaScript method renderContents that is invoked whenever the page needs<br />
to redraw the calendar. renderContents and its helper methods generate an array of dynamic HTML<br />
statements based on the user’s current selections of calendar month and date. For details, examine the<br />
class code for %ZEN.Component.calendar.<br />
350 <strong>Using</strong> <strong>Zen</strong>
Examples of Custom Components<br />
17.7 Examples of Custom Components<br />
The following is an example of a custom component that defines a title bar. This example is from the<br />
ZENDemo package in the SAMPLES namespace:<br />
Class ZENDemo.Component.demoTitle Extends %ZEN.Component.component<br />
{<br />
/// XML namespace for this component.<br />
Parameter NAMESPACE = "http://www.intersystems.com/zendemo";<br />
/// Domain used for localization.<br />
Parameter DOMAIN = "ZENDemo";<br />
/// Title displayed within this pane.<br />
Property title As %ZEN.Datatype.caption;<br />
/// Category displayed within this pane (above the title).<br />
Property category As %ZEN.Datatype.caption<br />
[ InitialExpression = {$$$Text("ZEN Demonstration")} ];<br />
/// defines style sheet used by this component<br />
XData Style<br />
{<br />
<br />
.demoTitle {<br />
color: black;<br />
background: #c5d6d6;<br />
width: 100%;<br />
padding: 0px;<br />
border-bottom: 1px solid darkblue;<br />
font-size: 1.4em;<br />
font-family: verdana;<br />
text-align: center;<br />
}<br />
<br />
}<br />
/// Draw the HTML contents of this component.<br />
Method %DrawHTML()<br />
{<br />
Set tCategory = ..category<br />
}<br />
}<br />
&html<br />
The purpose of defining a custom component for a title bar is to provide a consistent look for every<br />
page in a Web application. Page classes in the ZENDemo package provide countless examples of the<br />
<strong>Using</strong> <strong>Zen</strong> 351
Custom Components<br />
correct way to reference a custom component. An XData Contents block that provides a correct reference<br />
looks like this:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
<br />
}<br />
Where:<br />
• The element references the namespace defined for the custom component, and defines an<br />
alias for it, by providing the following attribute within the opening element:<br />
xmlns:demo="http://www.intersystems.com/zendemo"<br />
This statement defines an alias demo for the full namespace name.<br />
• The element references the demoTitle custom component. This reference has<br />
the form:<br />
<br />
where alias is the namespace alias defined in the element (demo in this case) and component<br />
is the name of the custom component class (demoTitle in this case).<br />
There are further examples of custom components, and references to these components, in the SAMPLES<br />
namespace. You can examine these classes in Studio. The examples of custom component classes<br />
include:<br />
• ZENDemo.Component.demoMenu, a subclass of %ZEN.Component.composite<br />
• ZENDemo.Component.sidebar, a subclass of %ZEN.Component.component<br />
• ZENDemo.Component.bullet, a subclass of %ZEN.Component.object<br />
• ZENTest.customComponent, a subclass of %ZEN.Component.control<br />
• ZENTest.customSVGComponent, a subclass of %ZEN.SVGComponent.svgComponent<br />
352 <strong>Using</strong> <strong>Zen</strong>
Creating Custom Meters<br />
17.8 Creating Custom Meters<br />
The following table is your checklist for building a custom meter component. Also see the odometer<br />
and clock examples that follow the table.<br />
Extending <strong>Zen</strong> with Custom Meters<br />
Task<br />
Subclass<br />
renderMeter<br />
Parameters<br />
Properties<br />
XData SVGStyle<br />
XData SVGDef<br />
setProperty<br />
Methods<br />
renderLabel<br />
XML Element<br />
Description<br />
Extend %ZEN.SVGComponent.meter to create a new class.<br />
Any subclass of %ZEN.SVGComponent.meter must override this<br />
method to render the SVG contents of the meter. The odometer<br />
and clock examples show how to make SVG calls from the meter<br />
class.<br />
(Optional) Provide class parameters and appropriate values. The<br />
odometer example overrides the DEFAULTHEIGHT and<br />
DEFAULTVIEWBOXHEIGHT parameters from the base meter<br />
class.<br />
(Optional) Provide properties, if needed. The odometer sets a<br />
maximum number of digits for its display. The clock overrides the<br />
value property from the base meter class with an ObjectScript<br />
expression that is evaluated each time the meter is displayed. For<br />
the clock, this expression calculates the current time.<br />
(Optional) Provide any CSS style definitions for the meter.<br />
(Optional) Provide any SVG definitions for the meter.<br />
(Optional) You may override this method to provide unique ways<br />
to set certain properties of the meter. The clock example does this<br />
for the value property, then defers to the superclass for setting all<br />
other properties.<br />
(Optional) Provide supporting methods as needed for component<br />
behavior.<br />
(Optional) Any subclass of %ZEN.SVGComponent.meter may override<br />
this method to set the x and y positions of the meter label.<br />
To add the component to a page, place it within that page’s XData<br />
Contents block as an XML element. Examples of this convention<br />
follow this table.<br />
<strong>Using</strong> <strong>Zen</strong> 353
Custom Components<br />
17.8.1 Custom Meters in XData Contents<br />
The following sample XData Contents block refers to two custom meter elements, a clock called<br />
and an odometer called :<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
17.8.2 Odometer Meter Example<br />
The class code to display the meter would look like the following example:<br />
354 <strong>Using</strong> <strong>Zen</strong>
Creating Custom Meters<br />
Class MyTest.svgOdoDisplay Extends %ZEN.SVGComponent.meter<br />
{<br />
/// Default height of this component.<br />
Parameter DEFAULTHEIGHT As INTEGER = 40;<br />
/// Default viewBoxHeight of this component.<br />
/// This is set to 25 to provide a fixed coordinate system for meters.<br />
Parameter DEFAULTVIEWBOXHEIGHT As INTEGER = 40;<br />
/// maximum digits to display<br />
Property maxDigits As %ZEN.Datatype.length [ InitialExpression = 5 ];<br />
/// Render the inner SVG contents of this component.<br />
/// This is implemented by subclasses.<br />
Method renderMeter() [ Language = javascript ]<br />
{<br />
var digits=this.maxDigits<br />
var width=digits*5+8<br />
// body<br />
var body=this.document.createElementNS(SVGNS,'rect');<br />
body.setAttribute('class','speedometer-body');<br />
body.setAttribute('fill','url(#speedometer-bodyGrad)');<br />
body.setAttribute('x',5);<br />
body.setAttribute('y',3);<br />
body.setAttribute('width',90);<br />
body.setAttribute('height',14);<br />
body.setAttribute('rx',2);<br />
body.setAttribute('filter','url(#dropShadow)');<br />
}<br />
this.svgGroup.appendChild(body);<br />
var box=this.document.createElementNS(SVGNS,'rect');<br />
box.setAttribute('class','speedometer-levelTextBox');<br />
box.setAttribute('fill','url(#speedometer-bodyGrad2)');<br />
box.setAttribute('x',48-(width/2));<br />
box.setAttribute('y',5);<br />
box.setAttribute('width',width+3);<br />
box.setAttribute('height',10);<br />
box.setAttribute('rx',1);<br />
this.svgGroup.appendChild(box);<br />
var off=51+(width/2)<br />
var lvlText = this.document.createElementNS(SVGNS,'text');<br />
lvlText.setAttribute('id',this.makeId('levelText'));<br />
lvlText.setAttribute('class','speedometer-levelText');<br />
lvlText.setAttribute('x',off);<br />
lvlText.setAttribute('y',13);<br />
lvlText.setAttribute('text-anchor','end');<br />
var textNode = this.document.createTextNode(this.value);<br />
lvlText.appendChild(textNode);<br />
this.svgGroup.appendChild(lvlText);<br />
// label<br />
this.renderLabel('50%',32);<br />
Method setProperty(property, value) [ Language = javascript ]<br />
{<br />
switch(property) {<br />
case 'value':<br />
var text = this.findSVGElement('levelText');<br />
var lvl = value<br />
this.odometerValue = value;<br />
if (!(isNaN(value))) {<br />
lvl = value * this.scaleFactor;<br />
<strong>Using</strong> <strong>Zen</strong> 355
Custom Components<br />
}<br />
}<br />
// update odometer text<br />
text.setAttribute("class",<br />
(lvl>=0) "speedometer-levelText" : "speedometer-levelTextNeg");<br />
}<br />
this.setTextNode("levelText",lvl);<br />
break;<br />
default:<br />
return this.invokeSuper('setProperty',arguments);<br />
}<br />
return true;<br />
17.8.3 Clock Meter Example<br />
The class code to display the meter would look like the following example:<br />
356 <strong>Using</strong> <strong>Zen</strong>
Creating Custom Meters<br />
Class MyTest.svgWatch Extends %ZEN.SVGComponent.meter<br />
{<br />
/// Speed adjustment default = 1<br />
Property speed As %ZEN.Datatype.integer [ InitialExpression = 1 ];<br />
/// Steps the second hand runs default=1 :== 1/10 sec<br />
Property steps As %ZEN.Datatype.integer [ InitialExpression = 1 ];<br />
/// Text for logo displayed in center<br />
Property logo As %ZEN.Datatype.caption [ InitialExpression = "<strong>Zen</strong>" ];<br />
/// Current value of the meter.<br />
/// Start time in seconds since midnight [0...84000]<br />
Property value As %ZEN.Datatype.string [ InitialExpression = {$p($h,",",2)} ];<br />
/// fixed offset to local time in seconds e.g. -3600 => 1 hour less<br />
Property timeshift As %ZEN.Datatype.integer [ InitialExpression = 0 ];<br />
Method renderMeter() [ Language = javascript ]<br />
{<br />
var now = new Date();<br />
this._starttime=now.getTime();<br />
this._startvalue=this.value;<br />
var value=this.value*1+this.timeshift*1;<br />
var h=value/3600*30+90;<br />
var m=(value%3600)/60*6+90 ;<br />
var s=(value%60)*6+90 ;<br />
//<br />
var body=this.document.createElementNS(SVGNS,'g');<br />
body.setAttribute('class','Watch-shadow');<br />
body.setAttribute('fill','none');<br />
body.setAttribute('stroke','none');<br />
body.setAttribute('stroke-width','2px');<br />
body.setAttribute('filter','url(#dropShadow)');<br />
this.svgGroup.appendChild(body);<br />
//<br />
var path1d='M 20,45 a30,30 0 1,1 0,0.001'<br />
//<br />
var q1=this.document.createElementNS(SVGNS,'g');<br />
q1.setAttribute('id',this.makeId('quarter'));<br />
q1.setAttribute('fill','yellow');<br />
q1.setAttribute('stroke','yellow');<br />
body.setAttribute('stroke-width',2);<br />
body.appendChild(q1);<br />
for (a=0;a
Custom Components<br />
hr.setAttribute('fill','lightgrey');<br />
hr.setAttribute('stroke','grey');<br />
hr.setAttribute('stroke-width',1);<br />
hr.setAttribute('transform','rotate('+h+',50,45)');<br />
body.appendChild(hr);<br />
//<br />
var c=this.document.createElementNS(SVGNS,'path');<br />
c.setAttribute('d','M 25,45 l 27,-3 5,3 -5,3 z');<br />
hr.appendChild(c);<br />
// <br />
hr=this.document.createElementNS(SVGNS,'g');<br />
hr.setAttribute('id',this.makeId('min'));<br />
hr.setAttribute('fill','lightgrey');<br />
hr.setAttribute('stroke','grey');<br />
hr.setAttribute('stroke-width',2);<br />
hr.setAttribute('transform','rotate('+m+',50,45)');<br />
body.appendChild(hr);<br />
//<br />
c=this.document.createElementNS(SVGNS,'path');<br />
c.setAttribute('d','M 22,45 l 40,0');<br />
hr.appendChild(c);<br />
//<br />
c=this.document.createElementNS(SVGNS,'path');<br />
c.setAttribute('d','M 20,45 l 7,-1.5 0,3 z');<br />
c.setAttribute('stroke-width',1);<br />
hr.appendChild(c);<br />
// <br />
var c=this.document.createElementNS(SVGNS,'circle');<br />
c.setAttribute('cx',50);<br />
c.setAttribute('cy',45);<br />
c.setAttribute('r',3);<br />
c.setAttribute('fill','red');<br />
c.setAttribute('stroke-width',1);<br />
c.setAttribute('stroke','grey');<br />
body.appendChild(c);<br />
//<br />
hr=this.document.createElementNS(SVGNS,'g');<br />
hr.setAttribute('id',this.makeId('sec'));<br />
hr.setAttribute('fill','lightgrey');<br />
hr.setAttribute('stroke','red');<br />
hr.setAttribute('stroke-width',1);<br />
hr.setAttribute('transform','rotate('+s+',50,45)');<br />
body.appendChild(hr);<br />
//<br />
c=this.document.createElementNS(SVGNS,'path');<br />
//c.setAttribute('d','M 0,-12.5 l 0,50');<br />
c.setAttribute('d','M 50,45 l 7.5,0 -50,0');<br />
hr.appendChild(c);<br />
// <br />
var c=this.document.createElementNS(SVGNS,'circle');<br />
c.setAttribute('cx',50);<br />
c.setAttribute('cy',45);<br />
c.setAttribute('r',1);<br />
c.setAttribute('fill','black');<br />
c.setAttribute('stroke-width',1);<br />
c.setAttribute('stroke','black');<br />
body.appendChild(c);<br />
// logo<br />
var logo = this.document.createElementNS(SVGNS,'text');<br />
logo.setAttribute('id',this.makeId('logo'));<br />
logo.setAttribute('class','speedometer-logoText');<br />
logo.setAttribute('x',50);<br />
logo.setAttribute('y',35);<br />
logo.setAttribute('text-anchor','middle');<br />
358 <strong>Using</strong> <strong>Zen</strong>
Creating Custom Meters<br />
var textNode = this.document.createTextNode(this.logo);<br />
logo.appendChild(textNode);<br />
this.svgGroup.appendChild(logo);<br />
// label<br />
this.renderLabel('50%','97.5%');<br />
this.updateHandles();<br />
}<br />
/// Internal method: update position of needle<br />
Method updateHandles() [ Language = javascript ]<br />
{<br />
if (this.animate)<br />
}<br />
{<br />
}<br />
delete this._timerId;<br />
var now = new Date();<br />
var time=now.getTime();<br />
var delta=(time-this._starttime)/1000; //only seconds<br />
//if (delta >= (1/60)) // 0.1° change<br />
//{<br />
var value=this._startvalue*1+delta;<br />
this.setProperty('value',value);<br />
//}<br />
this._timerId = window.setTimeout('zenPage.getComponent(' + this.index<br />
+ ').updateHandles()',this.steps*100);<br />
Method setProperty(property, value) [ Language = javascript ]<br />
{<br />
switch(property) {<br />
case 'value':<br />
this.value=value;<br />
value+=this.timeshift*1;<br />
// calculate actual rotation<br />
var h = (value/120)+90;<br />
var m = (value%3600)/10+90;<br />
var s = (value%60)*6+90;<br />
this.findSVGElement('hour').setAttribute('transform','rotate('+h+',50,45)');<br />
this.findSVGElement('min').setAttribute('transform','rotate('+m+',50,45)');<br />
this.findSVGElement('sec').setAttribute('transform','rotate('+s+',50,45)');<br />
;break<br />
}<br />
}<br />
case 'logo':<br />
this.logo = value;<br />
this.setTextNode('logo',this.logo);<br />
break;<br />
default:<br />
return this.invokeSuper('setProperty',arguments);<br />
}<br />
return true;<br />
<strong>Using</strong> <strong>Zen</strong> 359
18<br />
<strong>Zen</strong> Application Programming<br />
A <strong>Zen</strong> application specifies the full set of activities that can result when a <strong>Zen</strong> client and server interact.<br />
These activities may consist of displaying Web pages, issuing queries to a database, writing data to<br />
disk, and more. When you create a <strong>Zen</strong> application, you create a suite of <strong>Zen</strong> classes that specify these<br />
activities. The language you use for these classes is Caché ObjectScript — with embedded snippets<br />
of XML, HTML, SVG, and JavaScript as needed.<br />
For an introduction to <strong>Zen</strong> application programming, see these chapters:<br />
• Introducing <strong>Zen</strong><br />
• <strong>Zen</strong> Tutorial<br />
• <strong>Zen</strong> Client and Server<br />
• <strong>Zen</strong> Application Concepts<br />
This chapter provides reference details that build upon the foundation provided by these chapters.<br />
18.1 <strong>Zen</strong> Classes as CSP Classes<br />
The base application class %ZEN.application and the base page class %ZEN.Component.page each<br />
inherit from %CSP.page. This means that every <strong>Zen</strong> application class and every <strong>Zen</strong> page class is also<br />
an instantiable Caché Server Page. All the CSP page class properties, methods, parameters, and variables<br />
(such as %session) are available to <strong>Zen</strong> application and page classes.<br />
The introductory chapter <strong>Zen</strong> Client and Server explains the relationship between <strong>Zen</strong> and CSP. This<br />
chapter provides reference details for the <strong>Zen</strong> side of this relationship. The book <strong>Using</strong> Caché Server<br />
Pages (CSP) provides details for CSP.<br />
<strong>Using</strong> <strong>Zen</strong> 361
<strong>Zen</strong> Application Programming<br />
18.2 <strong>Zen</strong> Application Classes<br />
Every <strong>Zen</strong> application has an application class. This is a class derived from %ZEN.application that<br />
provides high-level housekeeping and acts as the single root for all of the pages in the application. The<br />
application does not keep an inventory of its pages. The association between the application and its<br />
pages occurs because every <strong>Zen</strong> page class identifies the application that it belongs to.<br />
The following table lists the elements of a <strong>Zen</strong> application class.<br />
Application Class Elements<br />
Element<br />
APPLICATIONNAME<br />
CSSINCLUDES<br />
HOMEPAGE<br />
JSINCLUDES<br />
USERPACKAGES<br />
USERSVGPACKAGES<br />
Role<br />
Class<br />
parameter<br />
Class<br />
parameter<br />
Class<br />
parameter<br />
Class<br />
parameter<br />
Class<br />
parameter<br />
Class<br />
parameter<br />
Purpose<br />
Defines a text string that you can use in titles or<br />
labels.<br />
Comma-separated list of cascading style sheet<br />
(CSS) files to include for every page in the<br />
application. See <strong>Zen</strong> Style.<br />
URI of a default Home Page for the application.<br />
This makes it possible for the application class to<br />
be specified as a starting point for the application,<br />
even though it does not itself display a page.<br />
When the application class receives an HTTP<br />
request, it redirects the request to the URI specified<br />
by the HOMEPAGE class parameter.<br />
Comma-separated list of JavaScript include files<br />
to include for every page in the application.<br />
Comma-separated list of user-defined class<br />
packages whose HTML class and style definitions<br />
are in pre-generated include files. These include<br />
files will be available to every page within the<br />
application.<br />
Comma-separated list of user-defined class<br />
packages whose SVG class and style definitions<br />
are in pre-generated include files. These include<br />
files will be available to every page within the<br />
application.<br />
362 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Classes<br />
Element<br />
XData Style<br />
Role<br />
Embedded<br />
XML<br />
document<br />
Purpose<br />
Any CSS style definitions that appear within this<br />
XData block are placed on every page within the<br />
application. See <strong>Zen</strong> Style.<br />
When programming, be aware that the application class can contain server-side methods written in<br />
Caché Basic or ObjectScript only. It cannot contain any client-side methods marked with the JavaScript<br />
keyword, or client/server methods marked with the <strong>Zen</strong>Method keywords. The application class can<br />
execute methods on the server only.<br />
18.3 <strong>Zen</strong> Page Classes<br />
Pages within a <strong>Zen</strong> application are derived from the class %ZEN.Component.page. A page class defines<br />
and serves the contents of a <strong>Zen</strong> page in a browser. For an introduction to <strong>Zen</strong> pages, see these chapters:<br />
• <strong>Zen</strong> Tutorial<br />
• <strong>Zen</strong> Client and Server<br />
• <strong>Zen</strong> Application Concepts<br />
For details about placing components on a <strong>Zen</strong> page, see:<br />
• <strong>Zen</strong> Component Concepts<br />
• <strong>Zen</strong> Layout<br />
• <strong>Zen</strong> Style<br />
This topic provides reference details to support these chapters.<br />
18.3.1 <strong>Zen</strong> Page Parameters<br />
There are a number of class parameters that a page class can use to control the behavior of the page.<br />
The following table lists the most useful of them. Others are described in the online class documentation.<br />
<strong>Using</strong> <strong>Zen</strong> 363
<strong>Zen</strong> Application Programming<br />
Page Class Parameters<br />
Parameter<br />
APPLICATION<br />
AUTOLOGOUT<br />
CSSINCLUDES<br />
DOMAIN<br />
JSINCLUDES<br />
PAGENAME<br />
PAGETITLE<br />
RESOURCE<br />
USERPACKAGES<br />
USERSVGPACKAGES<br />
Description<br />
Package and class name of the associated application.<br />
If 1 (true) attempt to refresh this page when its session has<br />
expired. If 0 (false) do not. The default is 1.<br />
Comma-separated list of cascading style sheet (CSS) include<br />
files. See <strong>Zen</strong> Style.<br />
Used for <strong>Zen</strong> Localization. The default is "" (an empty string<br />
indicating no domain).<br />
Comma-separated list of JavaScript include files for the page.<br />
Defines a text string that you can use in titles or labels. If not<br />
specified, the <strong>Zen</strong> page class name is used.<br />
Default value for the component’s title attribute.<br />
Name of a system Resource for which the current user must<br />
hold USE privileges in order to view this page or to invoke any<br />
of its server-side methods from the client.<br />
See the Caché Security Administration Guide, chapter Assets<br />
and Resources, topic Application Resources and Their Privileges.<br />
Comma-separated list of user-defined class packages whose<br />
HTML class and style definitions are in pre-generated include<br />
files.<br />
Comma-separated list of user-defined class packages whose<br />
SVG class and style definitions are in pre-generated include<br />
files.<br />
18.3.2 <strong>Zen</strong> Special Variables<br />
<strong>Zen</strong> offers several special variables to represent instantiated objects of various types within the <strong>Zen</strong><br />
application. These variables offer a convenient way to reference the methods and properties of these<br />
objects from within <strong>Zen</strong> page or <strong>Zen</strong> component class code.<br />
364 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Classes<br />
Special Variables on the Server Side<br />
Server Side<br />
Variable<br />
Refers To<br />
Use in<br />
These<br />
Classes<br />
Use in <strong>Zen</strong><br />
Runtime<br />
Expressions<br />
%application<br />
Application object<br />
Page<br />
No<br />
%composite<br />
Current composite object (if any)<br />
Page,<br />
Component<br />
Yes<br />
%page<br />
Current page object<br />
Page,<br />
Component<br />
Yes<br />
%query<br />
Current ResultSet object (if any)<br />
Page,<br />
Component<br />
Yes<br />
%session<br />
Current CSP session object<br />
Page,<br />
Component<br />
Yes<br />
%this<br />
Current object (page or component)<br />
Page,<br />
Component<br />
Yes<br />
%url<br />
An object whose properties are URI<br />
parameters of the current page<br />
Page,<br />
Component<br />
Yes<br />
%zenContext<br />
String that indicates what the server<br />
code is currently doing<br />
Page<br />
No<br />
Note that the %url special variable will only contain values when a page is first served; If you refer<br />
to %url in subsequent methods calls or component refreshes, its properties will have no value. If you<br />
need to refer to a value passed in via a URI parameter, define a property of your page class, link it to<br />
a URI parameter using the ZENURL parameter, and then refer to this value via the %page object. See<br />
<strong>Zen</strong> Page URI Parameters, later in this chapter.<br />
18.3.2.1 %application<br />
The server-side %application variable is available in every <strong>Zen</strong> page class. It is intended for use<br />
in methods that run while the page object is being created. It refers to the instance, on the server, of<br />
the application class that is associated with this page. This allows the page to invoke server-side<br />
methods defined in the application class.<br />
For example, the following method is defined in the application class ZENDemo.Application in the<br />
SAMPLES namespace:<br />
<strong>Using</strong> <strong>Zen</strong> 365
<strong>Zen</strong> Application Programming<br />
ClassMethod GetQuickLinks(Output pLinks) As %Status<br />
{<br />
Set pLinks("Home") = "ZENDemo.Home.cls"<br />
Set pLinks("Expense Calculator") = "ZENDemo.ExpenseCalculator.cls"<br />
Set pLinks("MVC Master Detail") = "ZENMVC.MVCMasterDetail.cls"<br />
Set pLinks("MVC Chart") = "ZENMVC.MVCChart.cls"<br />
Set pLinks("MVC Meters") = "ZENMVC.MVCMeters.cls"<br />
Set pLinks("MVC Form") = "ZENMVC.MVCForm.cls"<br />
Set pLinks("Test Suite") = "ZENTest.HomePage.cls"<br />
Set pLinks("Controls") = "ZENDemo.ControlTest.cls"<br />
Set pLinks("Methods") = "ZENDemo.MethodTest.cls"<br />
Quit $$$OK<br />
}<br />
Page classes that are associated with this application can then invoke this method as follows:<br />
Class ZENDemo.ExpenseCalculator Extends %ZEN.Component.page<br />
{<br />
/// Application this page belongs to.<br />
Parameter APPLICATION = "ZENDemo.Application";<br />
}<br />
// ...Intervening lines removed...<br />
/// Return an array of quick links to be displayed by the locator bar.<br />
ClassMethod GetQuickLinks(Output pLinks) As %Status<br />
{<br />
// dispatch to our application class<br />
Quit %application.GetQuickLinks(.pLinks)<br />
}<br />
There is no client-side equivalent for %application.<br />
18.3.2.2 %page and zenPage<br />
<strong>Zen</strong> offers special variables to represent the <strong>Zen</strong> page object on the client and server sides:<br />
• In ObjectScript or Basic code that runs on the server side, the page object is %page:<br />
Set btn = %page.%GetComponentById("NewBtn1")<br />
• In <strong>Zen</strong> runtime expressions, the page object is %page:<br />
text id="rows" label="Rows:" value="#(%page.Rows)#" size="5"/><br />
• In JavaScript methods that run on the client side, the page object is zenPage:<br />
var chart = zenPage.getComponentById('chart');<br />
• In JavaScript expressions that are values of XML attributes, the page object is zenPage:<br />
<br />
18.3.2.3 %this, this, and zenThis<br />
<strong>Zen</strong> offers special variables to represent a <strong>Zen</strong> object (component or page) on the client and server<br />
sides:<br />
366 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Classes<br />
• In ObjectScript or Basic code that runs on the server side, the object itself is %this:<br />
Set %this.Name = pSource.Name<br />
• In <strong>Zen</strong> runtime expressions, the object itself is %this:<br />
Item #(%this.tuple)#: #(%query.Title)#<br />
• In JavaScript methods that run on the client side, the object itself is this:<br />
var out = this.getComponentById('events');<br />
• In JavaScript expressions that are values of XML attributes, the object itself is zenThis:<br />
onchange="zenPage.changeLayout('svgFrame',zenThis.getValue());"<br />
18.3.2.4 zenEvent<br />
Suppose you have a JavaScript expression as the value of an XML event handler attribute, such as<br />
onchange in the following example:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
The zenEvent special variable refers to the current JavaScript Event object that describes the event.<br />
zenEvent provides a browser-neutral way to get access to the current event (such as a mouse click).<br />
In the example above, onchange references the notifyOnChange method. The client-side method<br />
notifyOnChange can reference the zenEvent special variable inside its JavaScript code.<br />
zenEvent only works inside client-side JavaScript methods that are referenced from XML event<br />
handler attributes, as is the case for , onchange, and notifyOnChange above.<br />
18.3.2.5 %zenContext<br />
When any activity on the server is being initiated by <strong>Zen</strong>, the server-side special variable %zenContext<br />
tells you which type of activity it is. %zenContext is a string. If %zenContext has the value:<br />
• page, <strong>Zen</strong> is serving the page in response to an HTTP request<br />
• submit, <strong>Zen</strong> is processing a submit request<br />
• method, <strong>Zen</strong> is processing a hyperevent<br />
Sometimes it is possible to have trouble with code being executed at compile time. To detect this,<br />
check for:<br />
<strong>Using</strong> <strong>Zen</strong> 367
<strong>Zen</strong> Application Programming<br />
$G(%zenContent)==""<br />
There is no client-side equivalent for %zenContext.<br />
18.3.3 <strong>Zen</strong> Runtime Expressions<br />
Rather than always providing static information in a <strong>Zen</strong> page description, sometimes it is useful for<br />
the page running on the client to be able to invoke runtime expressions that execute on the server. For<br />
example, perhaps the caption text for a button needs to be different depending on the identity of the<br />
currently logged-in user, which can only be determined from the server at runtime. Various runtime<br />
values can play a part in these decisions. For this reason, <strong>Zen</strong> provides a way for client-side application<br />
code to contain expressions that are resolved only on the server, and only at runtime.<br />
Important:<br />
The syntax rules for <strong>Zen</strong> runtime expressions are extremely specific.<br />
A runtime expression is enclosed within #()# and looks something like this:<br />
<br />
Where myProperty has a specific value on the server at runtime.<br />
<strong>Zen</strong> runtime expression syntax can be used, with restrictions, in the following contexts only:<br />
• XML that is embedded within an XData block (certain XML elements and attributes only)<br />
• A server-side Caché ObjectScript method or <strong>Zen</strong>Method (but not a JavaScript method)<br />
• JavaScript that is embedded within a &js block in a <strong>Zen</strong>Method<br />
• A JavaScript expression provided as the value of an XML attribute such as onclick<br />
• HTML that is embedded within an &html block in a server-side method<br />
The following items cannot appear within the #()# delimiters of a <strong>Zen</strong> runtime expression:<br />
• Calls to macros, such as $$$Text<br />
• JavaScript expressions<br />
• ObjectScript expressions, unless the runtime expression appears inside a server-side ObjectScript<br />
method or <strong>Zen</strong>Method, as shown later in this topic<br />
18.3.3.1 Runtime Expressions in XML<br />
<strong>Zen</strong> runtime expressions can be used within a <strong>Zen</strong> class XData block, but only the values of specific<br />
XML elements and attributes can contain <strong>Zen</strong> runtime expressions. One such example is the <br />
caption attribute:<br />
<br />
368 <strong>Using</strong> <strong>Zen</strong>
Of all the possible attributes, only caption, value, and hidden support <strong>Zen</strong> runtime expressions.<br />
The value of onclick in the above example does contain a <strong>Zen</strong> runtime expression, but this is acceptable<br />
because the value of onclick is a JavaScript expression, which may contain #()# syntax. Refer to the<br />
restrictions listed in the topic above.<br />
XML elements and attributes that support <strong>Zen</strong> runtime expressions are clearly identified throughout<br />
this book; you may find them by searching for the #()# string in the book text.<br />
Another way to tell that an XML attribute supports runtime expressions is to consult the Caché class<br />
documentation to see if the corresponding property has the datatype parameter ZENEXPRESSION<br />
set to 1 (true).<br />
You cannot simply set a property to have ZENEXPRESSION=1 to cause the property to support runtime<br />
expressions. Built-in <strong>Zen</strong> component classes provide ZENEXPRESSION=1 to indicate that the property<br />
supports runtime expressions, not to enable it to do so.<br />
On the other hand, when you create your own component subclasses as instructed in the Custom<br />
Components chapter, Datatype Parameters topic, you can set ZENEXPRESSION=1 for properties in<br />
those subclasses. It must be a property of a custom component class and not a property of one of the<br />
built-in <strong>Zen</strong> component classes.<br />
A significant number of XML attributes support <strong>Zen</strong> runtime expressions, but only one XML element<br />
supports them. This is the component, which may contain literal text and #()# runtime<br />
expressions. For example:<br />
Item #(%this.tuple)#: #(%query.Title)#<br />
18.3.3.2 Runtime Expressions and Special Variables<br />
A runtime expression may use the server-side special variables listed in the topic <strong>Zen</strong> Special Variables,<br />
above. <strong>Zen</strong> runtime expressions support the following server-side special variables only:<br />
• %composite<br />
• %page<br />
• %query<br />
• %session<br />
• %this<br />
• %url<br />
<strong>Zen</strong> Page Classes<br />
By limiting expressions to a pre-defined set of object property values, the page developer maintains<br />
control over which server-side values the client can see. Otherwise it would be possible for a page to<br />
execute code that the page developer did not intend, and thus present a security risk.<br />
<strong>Using</strong> <strong>Zen</strong> 369
<strong>Zen</strong> Application Programming<br />
18.3.3.3 Runtime Expressions in Server-Side Methods<br />
The following is an example of a server-side method with an &html block, in which a runtime<br />
expression invokes the ObjectScript function $ZCONVERT ($ZCVT) to help it to write out the elements<br />
of a bulleted list:<br />
Method %DrawHTML()<br />
{<br />
&html<br />
Write $ZCVT(..text,"O","HTML")<br />
}<br />
#; bullets<br />
Set tCount = ..bullets.Count()<br />
If (tCount > 0) {<br />
&html<br />
For n = 1:1:tCount {<br />
Set tBullet = ..bullets.GetAt(n)<br />
&html<br />
}<br />
&html<br />
}<br />
}<br />
&html<br />
The following is an example of a <strong>Zen</strong>Method with a &js block, in which a runtime expression<br />
passes the server-side identifier pIndex to JavaScript code that needs to execute on the client. In a later<br />
&js block, runtime expressions invoke the ObjectScript function $RANDOM ($R) to produce<br />
drawing coordinates, and provide CSS style statements to configure a graphical object:<br />
ClassMethod GetSVGContents(pIndex As %Integer) [ <strong>Zen</strong>Method ]<br />
{<br />
#; get the svg component<br />
&js<br />
}<br />
#; lines<br />
For i=1:1:30 {<br />
&js<<br />
var line = svg.document.createElementNS(SVGNS,'circle');<br />
//line.setAttribute('x1',200);<br />
//line.setAttribute('y1',100);<br />
line.setAttribute('r',5);<br />
line.setAttribute('cx',#(10+$Random(380))#);<br />
line.setAttribute('cy',#(10+$Random(180))#);<br />
line.setAttribute('style',<br />
'#("fill: yellow; stroke: black; stroke-width: 2;")#');<br />
svg.svgGroup.appendChild(line);<br />
><br />
}<br />
Quit<br />
The following is an example of a <strong>Zen</strong>Method that uses a &js block, in which runtime expressions<br />
call server-side methods of the server-side %page object to compose a JavaScript alert message:<br />
370 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Classes<br />
Method serverInstanceMethod() [ <strong>Zen</strong>Method ]<br />
{<br />
#; The server returns the following JavaScript statements to<br />
#; client for execution.<br />
&js<<br />
alert('Server instance method');<br />
alert('page: #(%page)#');<br />
alert('child 1: #(%page.children.GetAt(1))#');<br />
alert('title by id: #(%page.%GetComponentById("title"))#');<br />
alert('menu by id: #(%page.%GetComponentById("menu"))#');<br />
><br />
}<br />
Note:<br />
The samples in this topic demonstrate how runtime expressions can be used in a server-side<br />
method. In a client-side JavaScript method, you can achieve similar results without using<br />
runtime expressions.<br />
18.3.4 <strong>Zen</strong> Page Properties<br />
Any property defined within a page class whose name does not start with % becomes a property of the<br />
client-side page object. These client-side properties are initialized to the values they held on the server<br />
side, immediately before the page’s %DrawHTML method was invoked.<br />
You cannot set the value of any properties that you add to your page class by using the element<br />
within the XData Contents block. Only properties defined by the parent class %ZEN.Component.page<br />
are available in XData Contents.<br />
You can provide initial values for page class properties in one of the following ways:<br />
• Define an InitialExpression for the property, as in:<br />
Property dayList As %ZEN.Datatype.caption<br />
[ InitialExpression = "Sun,Mon,Tue,Wed,Thu,Fri,Sat" ];<br />
• Set the property in the %OnCreatePage or %OnAfterCreatePage callback methods.<br />
You can also set a page property’s value at runtime within any other method; these are just ways to<br />
initialize them.<br />
18.3.5 <strong>Zen</strong> Utility Methods<br />
The %ZEN.Utils class includes a number of utility methods for performing various common functions.<br />
Most of these classes are for internal use by the <strong>Zen</strong> library.<br />
ZENTest.LogPage in the SAMPLES namespace is an example of a page class that uses some of these<br />
utility methods to respond to the user’s selection of whether or not to enable logging for the application.<br />
The page class provides:<br />
• A definition for the event log display, plus the following :<br />
<strong>Using</strong> <strong>Zen</strong> 371
<strong>Zen</strong> Application Programming<br />
<br />
• This client-side method:<br />
Method enabledChange(cb) [ Language = javascript ]<br />
{<br />
this.EnableLog(cb.getValue()==1 true : false);<br />
}<br />
this.refreshLog();<br />
• And this <strong>Zen</strong> method:<br />
ClassMethod EnableLog(flag As %Boolean = "") As %Boolean [ <strong>Zen</strong>Method ]<br />
{<br />
If (flag = "") {<br />
Set flag = ##class(%ZEN.Utils).%LoggingEnabled()<br />
}<br />
If (flag) {<br />
Do ##class(%ZEN.Utils).%StartLog()<br />
}<br />
Else {<br />
Do ##class(%ZEN.Utils).%StopLog()<br />
}<br />
Quit 1<br />
}<br />
The result is as follows:<br />
Sample Log of <strong>Zen</strong> Events<br />
To read more about %ZEN.Utils, start the Caché online documentation system and choose Class Reference<br />
<strong>Documentation</strong> for the %SYS namespace.<br />
18.3.6 Client-Side Functions and Variables<br />
All page classes have the following JavaScript utility functions and variables available to them:<br />
372 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Classes<br />
Client-Side Functions and Variables<br />
Function or Variable<br />
zenLaunchPopupWindow<br />
zenLink<br />
zenSynchronousMode<br />
Description<br />
A function that launches the referenced HTML content as<br />
a popup window. See the chapter Popup Windows and<br />
Dialogs, topic Popup Windows.<br />
A function that escapes any special characters found in a<br />
string intended to be used as a URI. See the chapter Popup<br />
Windows and Dialogs, topic Popup Windows.<br />
A flag with the value true (all methods will be executed<br />
synchronously regardless of whether or not they have return<br />
values) or false (methods will be synchronous if they have<br />
a return value, asynchronous otherwise). See Synchronous<br />
and Asynchronous Methods, later in this chapter.<br />
18.3.7 <strong>Zen</strong> Page URI Parameters<br />
Sometimes it is useful to pass values to a page via URI parameters.<br />
There is a datatype parameter, ZENURL, that can be applied to properties of page classes. The presence<br />
of this parameter causes the page to generate code that will initialize the value of the datatype to the<br />
value of a URI parameter.<br />
For example, in a page class you can define a property:<br />
Property employeeID As %ZEN.Datatype.string(ZENURL="ID");<br />
When this page is requested, the value of the URI parameter, ID, will be assigned to the employeeID<br />
property. For example, this URI:<br />
MyApp.MyPage.clsID=48<br />
Will cause the following code to run:<br />
Set %page.employeeID = $GET(%request.Data("ID",1))<br />
If the URI parameter assigned to a property does not pass the property’s validation test for any reason,<br />
such as a value greater than the property’s MAXVAL, the page is not displayed and an error message<br />
is displayed instead.<br />
<strong>Using</strong> <strong>Zen</strong> 373
<strong>Zen</strong> Application Programming<br />
18.3.8 <strong>Zen</strong> Page Event Handling<br />
Many components define event handlers such as onclick, onchange, etc. See the description of any<br />
<strong>Zen</strong> control component, such as , , or . Also see the description of zenEvent<br />
in the topic <strong>Zen</strong> Special Variables, above.<br />
While a page is being displayed, <strong>Zen</strong> traps all events until the page finished building. This is to prevent<br />
the user from clicking on an element before the browser has finished building the zenPage object on<br />
the client side.<br />
18.4 <strong>Zen</strong> Properties on Client and Server<br />
On the server side, you can get and set values of class properties directly, using normal dot syntax.<br />
For example:<br />
Method serverInstanceMethodCreate() [ <strong>Zen</strong>Method ]<br />
{<br />
#; create<br />
Set group = %page.%GetComponentById("group")<br />
If '$IsObject(group) {<br />
&js<br />
Quit<br />
}<br />
Set count = group.children.Count()<br />
}<br />
Set cal = ##class(%ZEN.Component.calendar).%New()<br />
Set cal.id = "NewCal"_count<br />
Do group.%AddChild(cal)<br />
Set btn = ##class(%ZEN.Component.button).%New()<br />
Set btn.id = "NewBtn"_count<br />
Set btn.caption = "New Button"<br />
Do group.%AddChild(btn)<br />
Set btn = ##class(%ZEN.Component.text).%New()<br />
Set btn.label = "Hey"<br />
Do group.%AddChild(btn)<br />
On the client side, you cannot access any property values directly. You must use the get and set<br />
methods provided in the component classes. For single-valued properties, use the getProperty and<br />
setProperty methods. For example:<br />
var index = table.getProperty('selectedIndex');<br />
Or:<br />
var svg = zenPage.getComponentById('svgFrame');<br />
svg.setProperty('layout','');<br />
svg.setProperty('editMode','drag');<br />
374 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Methods<br />
Important:<br />
Do not confuse getProperty and setProperty with the getValue and setValue<br />
methods, which get and set the value of a control component, and do not apply to any<br />
other component property.<br />
18.5 <strong>Zen</strong> Methods<br />
The following table outlines the possibilities for different types of method in a <strong>Zen</strong> page class.<br />
Page Class Method Conventions<br />
Callable<br />
From<br />
Runs On<br />
Class<br />
Scope<br />
Timing<br />
Code<br />
Language<br />
Keyword<br />
Naming<br />
Convention<br />
Client<br />
Client<br />
Instance<br />
—<br />
JavaScript<br />
Language<br />
=<br />
JavaScript<br />
myMethod<br />
Client<br />
Server<br />
(Can send<br />
back code<br />
that runs on<br />
the client)<br />
Instance<br />
Class<br />
Async<br />
Sync<br />
Async<br />
Sync<br />
ObjectScript<br />
or Basic<br />
<strong>Zen</strong>Method<br />
MyMethod<br />
Server<br />
Server<br />
Instance<br />
Class<br />
—<br />
ObjectScript<br />
or Basic<br />
—<br />
%MyMethod<br />
Any method defined within a page class whose name does not start with % becomes a method of the<br />
client-side page object. Any method whose name starts with % is server-only.<br />
Any instance method defined as having [Language = javascript] automatically becomes a<br />
client-side instance method of the client page object. When called, it executes within the browser.<br />
Any method defined with its [<strong>Zen</strong>Method] keyword set automatically becomes a client-side instance<br />
method of the client page object. When the client-side method is called, the server-side version of the<br />
method is executed. Any context needed to run the server method is automatically provided. An instance<br />
method runs as an instance method on the server; the serialized state of its client object is shipped to<br />
the server and instantiated. A class method runs as a class method on the server (but is called as an<br />
instance method on the client).<br />
<strong>Using</strong> <strong>Zen</strong> 375
<strong>Zen</strong> Application Programming<br />
18.5.1 Synchronous and Asynchronous Methods<br />
Server-side methods can be called synchronously or asynchronously. This happens very smoothly and<br />
automatically as follows: If a server-side method has a return type, it is called synchronously, and its<br />
return value is returned to the client. If the method has no return type, it is called asynchronously; the<br />
client does not wait for the return value.<br />
The CSP hyper-event logic handles all the details of this, so (unlike AJAX) you do not need to provide<br />
any additional application logic to enable asynchronous calls. In this way, <strong>Zen</strong> takes the next step past<br />
most AJAX frameworks.<br />
The main advantages of asynchronous methods are:<br />
• The browser can keep working while the server request is processed<br />
• You can call a server method, modify the client (say by displaying a message), and the server<br />
logic can update this message when it completes<br />
Some of the <strong>Zen</strong> components take advantage of asynchronous methods. For example, the <br />
control uses an asynchronous method to execute a server-side query. This allows the <br />
to display a loading... message while the query is running. This message is replaced when the<br />
response from the server arrives, so the user does not see the message if the query is quick.<br />
<strong>Zen</strong> offers a client-side flag zenSynchronousMode that you can set to true to force all methods to<br />
be executed synchronously, regardless of their return values. When false, methods are synchronous<br />
if they have a return value, asynchronous otherwise. When you want to set this flag:<br />
1. First, get and store the current value of zenSynchronousMode.<br />
2. Then, set the flag as you wish.<br />
3. When your processing is done, restore the previous value of zenSynchronousMode.<br />
In addition to this convention, the client-side refreshContents method (available for every component)<br />
offers a single optional argument whose value can be true or false. This flag specifies whether the<br />
client should refresh the component synchronously (true) or asynchronously (false). If this argument<br />
is omitted, the default is false.<br />
18.5.2 Server-Side Callback Methods<br />
Callback methods are user-written methods within a Caché class that are triggered, not by a method<br />
call, but by specific system events. To distinguish callback methods, Caché developers give them<br />
names of the following form:<br />
%OnEvent<br />
376 <strong>Using</strong> <strong>Zen</strong>
where the keyword Event identifies the Caché system event that triggers the callback. If an event<br />
supports a callback method, the method controlling the event automatically executes the callback<br />
method, if it exists within the class.<br />
You must never execute callback methods by calling them explicitly. Instead, provide an implementation<br />
of the method within your class so that Caché can invoke the method automatically when the time is<br />
right. If you want your class to do nothing in response to an event, omit any implementation of the<br />
corresponding callback method.<br />
When an HTML page derived from %ZEN.Component.page is drawn, it invokes a number of callback<br />
methods that are executed on the server before the page content is sent to the browser. The following<br />
table lists these methods. A page class can override these methods to control the behavior of the page.<br />
Page Class Server-side Callback Methods<br />
<strong>Zen</strong> Methods<br />
Callback Method<br />
%OnBeforeCreatePage<br />
%OnCreatePage<br />
%OnAfterCreatePage<br />
%OnDrawHTMLHead<br />
%OnDrawHTMLBody<br />
Description<br />
This class method is called just before the server-side page<br />
object is created.<br />
This instance method is called just after the server-side page<br />
object is created but before any of its child components are<br />
created.<br />
This instance method is called after the server-side page object<br />
and all of its pre-defined child components are created. A<br />
subclass can override this method to add, remove, or modify<br />
items within the page object model, or to provide values for<br />
controls.<br />
This instance method is called when the HTML for the page is<br />
being rendered just before the end of the HTML HEAD section<br />
of the page. This provides a way to inject addition content into<br />
the HEAD section of a page should this ever be necessary.<br />
This instance method is called when the HTML for the page is<br />
being rendered close to the start of the HTML BODY section<br />
of the page (before any child components are rendered). This<br />
provides a way to inject additional content into the BODY<br />
section of a page should this ever be necessary.<br />
For details about each method see the class documentation for %ZEN.Component.abstractPage. That<br />
is, start the Caché online documentation system, choose Class Reference <strong>Documentation</strong> for the %SYS<br />
namespace, and navigate to %ZEN.Component.abstractPage.<br />
<strong>Using</strong> <strong>Zen</strong> 377
<strong>Zen</strong> Application Programming<br />
18.5.3 Server-Only Methods<br />
The %ZEN.Component.page class contains a number of server-side methods that can be useful when<br />
working with the page object tree on the server or for processing form submits. The following table<br />
lists these methods.<br />
Page Class Server Methods<br />
Method<br />
%GetComponent<br />
%GetComponentById<br />
%GetComponentByName<br />
%GetValueById<br />
%GetValueByName<br />
%SetErrorById<br />
%SetErrorByName<br />
%SetValueById<br />
%SetValueByName<br />
%SetValuesByName<br />
Description<br />
Find a component object given its system-assigned index<br />
number.<br />
Find a component object given its user-assigned id value.<br />
Find a control object given its user-assigned control name.<br />
Get the value of a control object given its user-assigned<br />
control id value.<br />
Get the value of a control object given its user-assigned<br />
control name.<br />
Set the value of a component error message given its<br />
user-assigned id value.<br />
Set the value of a component error message given its<br />
user-assigned control name.<br />
Set the value of a control object given its user-assigned<br />
control id value.<br />
Set the value of a control object given its user-assigned<br />
control name.<br />
Set the values of a set of control objects given an array of<br />
values subscripted by user-assigned control name.<br />
For details about each method see the class documentation for %ZEN.Component.abstractPage.<br />
18.5.4 Type Conversion for Server-Side Methods<br />
The mechanism for handling type conversions when invoking a server-side method works as follows:<br />
• When calling a server-side method, any %ZEN.Datatype.boolean arguments are converted from<br />
client-side true/false to server-side 1/0.<br />
• If a server method has a %ZEN.Datatype.boolean return type, its return value are converted to a<br />
client-side true/false value.<br />
378 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Methods<br />
• If a server method has a numeric return type, its return value are converted to a client-side numeric<br />
value (unless it the method returns "").<br />
• Methods that take object-valued arguments behave well if the argument is missing or null.<br />
18.5.5 Background Tasks on the Server<br />
There is a mechanism for starting a background job from a <strong>Zen</strong> page and tracking its progress within<br />
the page. This can be useful for cases where a page needs to initiate a long-running task and wants to<br />
provide some degree of feedback to the client while waiting for that task to complete.<br />
A <strong>Zen</strong> page class has a backgroundTimerInterval property. This is the interval, in milliseconds, at which<br />
timer events are fired to check on the status of background tasks started by this page. The default is<br />
1000.<br />
Two methods support background tasks; both are available in any class that inherits from<br />
%ZEN.Component.page:<br />
• %RunBackgroundMethod starts a background job to run a class method of this <strong>Zen</strong> page.<br />
%RunBackgroundMethod returns a %Status value and may have one or more arguments:<br />
- The first argument, a %String, is the name of the class method to run.<br />
- Depending on the method signature, a variable number of arguments may follow; these are<br />
the arguments of the method named in the first argument.<br />
<strong>Zen</strong> monitors only one background task at a time. If %RunBackgroundMethod is called while<br />
a previous background task is running, the new method becomes the current monitored task. The<br />
previous task runs to completion, but the client is not notified about it.<br />
• %SetBackgroundMethodStatus can be called from within a method that is running in the<br />
background, to update its own status information. %SetBackgroundMethodStatus has no return<br />
value and takes two arguments:<br />
- A %String specifies the status message that will be seen by the client page. The string may<br />
be empty.<br />
- An optional %Float value indicates how much of the background task is complete (as a percentage<br />
between 0 and 100). A client page can use this information to display progress to the<br />
user.<br />
18.5.6 Client-Side Page Callback Methods<br />
The client-side page object zenPage inherits a number of callback methods. These are JavaScript<br />
methods which, if defined, are called in response to specific events. The following table lists these<br />
methods.<br />
<strong>Using</strong> <strong>Zen</strong> 379
<strong>Zen</strong> Application Programming<br />
Page Class Client-side Callback Methods<br />
Callback Method<br />
onloadHandler<br />
onpopupAction<br />
onresizeHandler<br />
onunloadHandler<br />
Description<br />
This client-side page method, if defined, is called when the client<br />
page is finished loading (i.e. it is called by the page’s HTML onload<br />
event).<br />
This client-side page method, if defined, is called when a popup<br />
window, launched by this page, is completed.<br />
This client-side page method, if defined, is called when the client<br />
page is resized (it is called by the page’s HTML onresize event).<br />
This client-side page method, if defined, is called when the client<br />
page is about to unload (it is called by the page’s HTML onunload<br />
event).<br />
18.5.7 Client-Side Page Methods<br />
The client-side page object zenPage inherits a number of JavaScript methods that can be useful in<br />
client-side programming. The following table lists these methods.<br />
Page Class Client-side Methods<br />
Method<br />
cancelPopup<br />
createComponent<br />
createComponentNS<br />
endModal<br />
getComponent<br />
getComponentById<br />
startModal<br />
Description<br />
(Popup windows only). Close the current popup window with no<br />
further action.<br />
Create a new component on the page (by component name).<br />
Create a new component on the page (by component name and<br />
namespace).<br />
Hide the current modalGroup, if there is one.<br />
Find a component on the page given its system-assigned index<br />
number.<br />
Find a component on the page given its user-assigned id value.<br />
Make a modalGroup visible. Alternately, use the show method<br />
of the modalGroup.<br />
380 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Contents<br />
18.5.8 Client-Side Component Methods<br />
Every component on the page (including the page itself) inherits a number of useful JavaScript methods.<br />
The following table lists these methods. Specific components also have specialized methods not listed<br />
in the table.<br />
Page Class Client-side Component Methods<br />
Method<br />
findElement<br />
getEnclosingDiv<br />
getHidden<br />
getProperty<br />
getSettings<br />
getValue<br />
invokeSuper<br />
isOfType<br />
refreshContents<br />
setHidden<br />
setProperty<br />
setValue<br />
Description<br />
Find a named HTML element associated with a specific component.<br />
Get the HTML div element used to enclose a specific component.<br />
Return whether a component is hidden (or displayed).<br />
Return a named property of a component.<br />
Get the set of named properties that can be observed and modified<br />
using getProperty and setProperty.<br />
(Subclasses of control only). Get the value of a control. This is<br />
equivalent to calling getProperty('value').<br />
Invoke the super class implementation of the current component<br />
method.<br />
Tests if a component is a subclass of (is a type of) another component.<br />
Make a request to the server to regenerate the HTML that defines a<br />
component. For tablePane components, use executeQuery instead.<br />
Sets whether a component is hidden (or displayed).<br />
Sets the value of a named property for a component.<br />
(Subclasses of control only). Set the value of a control.<br />
18.6 <strong>Zen</strong> Page Contents<br />
This topic explains how to specify the component object model for a <strong>Zen</strong> page using XML, programmatically,<br />
or with a combination of both.<br />
The visible contents of the page are defined by a set of <strong>Zen</strong> components that belong to the page. This<br />
set of components is typically defined within an XML block named XData Contents. It is also possible<br />
to define or modify this set of components by overriding the %OnAfterCreatePage callback method.<br />
<strong>Using</strong> <strong>Zen</strong> 381
<strong>Zen</strong> Application Programming<br />
18.6.1 Defining Page Contents <strong>Using</strong> XML<br />
A <strong>Zen</strong> page class can provide an XData Contents block (an XML document embedded within the<br />
class definition) that defines the set of components that will be used for the page. It is possible to define<br />
the contents of a page programmatically, but in most cases an XML block is more convenient.<br />
The following XData Contents block defines a simple page object containing a single button<br />
component:<br />
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />
{<br />
<br />
<br />
<br />
}<br />
The XData Contents block is not processed at runtime. Instead, at compile time the class compiler<br />
uses the XData Contents information to generate a method called %CreatePage. You can view<br />
(but not modify) this method if you like by compiling a page class and then using the View Other<br />
command in Studio to see the code generated for the page class. The %CreatePage method is called<br />
at runtime to create the contents of the page component model.<br />
<strong>Zen</strong> Layout and the chapters that follow it describe XData Contents in detail.<br />
18.6.2 XML Namespaces<br />
<strong>InterSystems</strong> recommends that you include an XML namespace declaration within an XData Contents<br />
definition. You do this by providing the xmlns attribute with the element. For example:<br />
<br />
As you add custom components, chances increase that there will be conflicts between components in<br />
different namespaces. This is also true for other <strong>Zen</strong> elements such as and . Adding<br />
the xmlns attribute to the prevents this.<br />
18.6.3 Defining Page Contents Programmatically<br />
If you need to programmatically modify the contents of a page before displaying it, add code to the<br />
%OnAfterCreatePage callback method to do so. You can find a component on the page using the<br />
%GetComponentById method, then set component properties directly. Then you must add the new<br />
component to a group or page using %AddChild. For example:<br />
382 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Page Contents<br />
Method %OnAfterCreatePage() As %Status<br />
{<br />
Set tGroup = ##class(%ZEN.Component.group).%New()<br />
Do %page.%AddChild(tGroup)<br />
Set tBtn = ##class(%ZEN.Component.button).%New()<br />
Set tBtn.caption = "Button 1"<br />
Do tGroup.%AddChild(tBtn)<br />
Set tBtn = ##class(%ZEN.Component.button).%New()<br />
Set tBtn.caption = "Button 2"<br />
Do tGroup.%AddChild(tBtn)<br />
}<br />
Quit $$$OK<br />
Any text you add for captions or other labels is not magically localized as it is when you add a caption<br />
attribute using XML. If you want localized captions, your %OnAfterCreatePage methods must call<br />
the $$$Text localization macros. This is not shown in the example above.<br />
If the component is not visible (such as ) you may add it to a page using %AddComponent<br />
instead of %AddChild. For components that are visible, the methods %AddChildBefore and<br />
%AddChildAfter are also available. These methods have a second parameter that identifies the<br />
existing, sibling component.<br />
If you need to add components to a page programmatically, based on user interactions, you can do this<br />
as well. The SAMPLES namespace class ZENTest.DynamicComponentsTest provides useful examples<br />
of doing this from the client or server sides in response to user input. Remember that you need to both<br />
create the component and add it as a child of the page before the user can see it. A separate set of<br />
methods exists for doing this on the server and on the client (see the lists in previous topics). As another<br />
example of dynamically adding components to a page, see the Sample Development Project, below.<br />
One of the best ways to get a sense of how pages are put together programmatically is to look at the<br />
generated code for the %CreatePage method in any <strong>Zen</strong> page class that uses XData Contents to define<br />
page contents. To do this:<br />
1. Open the page class in Studio.<br />
2.<br />
Choose View > View Other or Ctrl-Shift-V or the<br />
icon.<br />
3. Select the file marked “1” and click Open.<br />
4. Search for this string: %CreatePage<br />
5. Scroll through the method to see how components are added to the page.<br />
18.6.4 <strong>Zen</strong> Layout Handler<br />
The actual work of laying out a group component’s children is handled by the %ZEN.LayoutManager<br />
class. It is possible to implement layout strategies in addition to those normally provided. If you wish<br />
to serve the page using your own, custom layout handler code, you can.<br />
<strong>Using</strong> <strong>Zen</strong> 383
<strong>Zen</strong> Application Programming<br />
<strong>Zen</strong> provides a simple, built-in layout strategy with the intention of making rapid application development<br />
easier. Components start at top left of the page and work their way to the right and bottom. You<br />
can achieve a lot, very quickly, by manipulating nests of vertical and horizontal groups.<br />
There may be cases when your layout needs finer control. If so, ultimately it might suit your project<br />
best to develop your own layout handler for use with <strong>Zen</strong>. For these cases, <strong>Zen</strong> provides an<br />
onlayoutHandler callback method. This client-side method, if defined, is called when a page is first<br />
displayed and whenever the size of the page is changed thereafter. This provides a way to define code<br />
that will adjust the size and position of components whenever the size of the containing page is changed.<br />
For example:<br />
Method onlayoutHandler(load) [ Language = javascript ]<br />
{<br />
// adjust size of lookout menu<br />
var menu = zenPage.getComponentById('lookout');<br />
zenASSERT(menu,'Unable to find menu',arguments);<br />
}<br />
// find div for titleBox & mainMenu<br />
var title = zenPage.getComponentById('titleBox');<br />
var divTitle = title.getEnclosingDiv();<br />
// find height of window<br />
var winHeight = zenGetWindowHeight();<br />
// adjust size of menu<br />
var sz =<br />
winHeight - (parseInt(divTitle.offsetHeight)) - 20;<br />
menu.setSize(null,sz);<br />
18.7 Sample Development Project<br />
The chapter <strong>Zen</strong> Layout explains how to use template pages and panes to organize layout and style<br />
for a <strong>Zen</strong> application. This topic traces an example that uses composites and dynamic page generation<br />
to organize behavior for a <strong>Zen</strong> application. This example uses <strong>Zen</strong> to add new order entry module<br />
pages to an existing Weblink application. Constraints are as follows:<br />
• You need to be able to call the new pages from within your existing application.<br />
• You do not have the luxury of rewriting the whole application, so you want to evolve into <strong>Zen</strong><br />
one module at a time.<br />
• Your order entry page needs to have flexible content. That is, you need to be able to easily update<br />
portions of the page depending on the context.<br />
• Your order entry page is so big and complex, you want to only build what you need when the<br />
page is first loaded and then fill in some empty segments on the fly.<br />
• Ideally, you want to break up the page into segments that can be written simultaneously by different<br />
developers.<br />
384 <strong>Using</strong> <strong>Zen</strong>
Sample Development Project<br />
The following example addresses these constraints. It purposely does not address layout or style but<br />
focuses on behavior.<br />
• The following class provides the main page. It defines a set of named groups. Each group is populated<br />
with components from the server in response to user events. The main page also defines<br />
an API (set of methods) that the various components can call to work with the page. For example,<br />
there is a method that loads a new component into one of the groups on the page. Note the<br />
parameter USERPACKAGES, the groups g1 and g2, and the method loadForm, which adds a<br />
specific type of form to the page based on the parameters provided to it.<br />
• The contents of each group is defined using a composite component. A composite is a custom<br />
component that you build by grouping one or more built-in <strong>Zen</strong> components in a specific way.<br />
For full details, see the chapter Custom Components, topic Building Composite Components.<br />
Composites can be developed individually by different developers; this satisfies the project constraints.<br />
In the sample code, there are four such composites: searchForm is the starting form that<br />
drives the loading of other forms. formOne, formTwo, and formThree are sample forms.<br />
<strong>Using</strong> <strong>Zen</strong> 385
<strong>Zen</strong> Application Programming<br />
Class TestMe.MainPage Extends %ZEN.Component.page<br />
{<br />
/// Comma-separated list of User class packages whose HTML class<br />
/// and style definitions are in pre-generated include files.<br />
Parameter USERPACKAGES = "TestMe.Components";<br />
/// Class name of application this page belongs to.<br />
Parameter APPLICATION;<br />
/// Displayed name of this page.<br />
Parameter PAGENAME;<br />
/// Domain used for localization.<br />
Parameter DOMAIN;<br />
/// This Style block contains page-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
/* style for title bar */<br />
#title {<br />
background: #C5D6D6;<br />
color: black;<br />
font-family: Verdana;<br />
font-size: 1.5em;<br />
font-weight: bold;<br />
padding: 5px;<br />
border-bottom: 1px solid black;<br />
text-align: center;<br />
}<br />
}<br />
/* container style for group g1 */<br />
#g1 {<br />
border: 1px solid black;<br />
background: #DDEEFF;<br />
}<br />
/* container style for group g2 */<br />
#g2 {<br />
border: 1px solid black;<br />
background: #FFEEDD;<br />
}<br />
<br />
/// This XML block defines the contents of this page.<br />
XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />
{<br />
<br />
TestMe Test Page<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
/// Create a form (via a composite element) and place it into the group with<br />
/// the id groupId. formClass is the name of the composite element<br />
386 <strong>Using</strong> <strong>Zen</strong>
Sample Development Project<br />
/// containing the form. formId is the id applied to the form.<br />
Method loadForm(formClass, formId, groupId) [ Language = javascript ]<br />
{<br />
try {<br />
// if there is already a form, get rid of it<br />
var comp = zenPage.getComponentById(formId);<br />
if (comp) {<br />
zenPage.deleteComponent(comp);<br />
}<br />
}<br />
}<br />
var group = zenPage.getComponentById(groupId);<br />
var form = zenPage.createComponentNS('TestMe',formClass);<br />
form.setProperty('id',formId);<br />
group.addChild(form);<br />
group.refreshContents(true);<br />
}<br />
catch(ex) {<br />
zenExceptionHandler(ex,arguments);<br />
}<br />
Some important things to notice about the TestMe.MainPage class:<br />
• The parameter USERPACKAGES is set as follows:<br />
Parameter USERPACKAGES = "TestMe.Components";<br />
This tells the page to use the generated include files for the components in this package. This is<br />
important as we are creating things on-the-fly and we want to ensure that the relevant JS object<br />
are available.<br />
• The XData Contents block for the page provides a reference to the XML namespace for the new<br />
composite components:<br />
xmlns:testme="TestMe"<br />
• XData Contents places the searchForm component on the page as follows:<br />
<br />
When the user presses one of the buttons on the searchForm, it invokes the loadForm method on<br />
the Main page. This deletes the current form (by id) and loads a new form (it does not actually<br />
have to be a form, that is just what we have used as an example).<br />
Now take a look at the components for the example. As suggested in Building Composite Components,<br />
all of these composite component classes are placed together in their own package, TestMe.Components.<br />
The reason for this is that <strong>Zen</strong> will automatically generate JS and CSS header files for components in<br />
a given package. By placing these components in a package you can exploit this feature by setting the<br />
parameter USERPACKAGES to the package name, on the main page, as shown above:<br />
Parameter USERPACKAGES = "TestMe.Components";<br />
The composites also use their own XML namespace to avoid conflict with other components.<br />
The composite component classes are as follows:<br />
<strong>Using</strong> <strong>Zen</strong> 387
<strong>Zen</strong> Application Programming<br />
• searchForm — the starting form that drives the loading of other forms:<br />
Class TestMe.Components.searchForm Extends %ZEN.Component.composite<br />
{<br />
/// This is the XML namespace for this component.<br />
Parameter NAMESPACE = "TestMe";<br />
/// This Style block contains component-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
}<br />
<br />
}<br />
/// Contents of this composite component.<br />
XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
/// User click on form 1 button.<br />
Method btnForm1() [ Language = javascript ]<br />
{<br />
// Notify the page that the search button was pressed<br />
// and that a new form should be loaded.<br />
zenPage.loadForm('formOne','form1','g1');<br />
}<br />
/// User click on form 2 button.<br />
Method btnForm2() [ Language = javascript ]<br />
{<br />
// replace contents of 'g1' with formTwo<br />
zenPage.loadForm('formTwo','form1','g1');<br />
}<br />
/// User click on form 3 button.<br />
Method btnForm3() [ Language = javascript ]<br />
{<br />
// replace contents of 'g2' with formTwo<br />
zenPage.loadForm('formTwo','form2','g2');<br />
}<br />
/// User click on form 4 button.<br />
Method btnForm4() [ Language = javascript ]<br />
{<br />
// replace contents of 'g2' with formThree<br />
zenPage.loadForm('formThree','form2','g2');<br />
}<br />
Every component that is part of a composite can refer to its containing composite group via its<br />
composite property. You can see this in the syntax used to invoke client-side methods defined in<br />
the composite class, when the user clicks a button on this form:<br />
onclick="zenPage.getComponent(#(..index)#).btnForm1();"<br />
• formOne — a sample form:<br />
388 <strong>Using</strong> <strong>Zen</strong>
Class TestMe.Components.formOne Extends %ZEN.Component.composite<br />
{<br />
/// This is the XML namespace for this component.<br />
Parameter NAMESPACE = "TestMe";<br />
Sample Development Project<br />
/// This Style block contains component-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
}<br />
<br />
/// Contents of this composite component.<br />
XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />
{<br />
<br />
}<br />
}<br />
<br />
<br />
<br />
• formTwo — another sample form:<br />
Class TestMe.Components.formTwo Extends %ZEN.Component.composite<br />
{<br />
/// This is the XML namespace for this component.<br />
Parameter NAMESPACE = "TestMe";<br />
/// This Style block contains component-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
}<br />
<br />
/// Contents of this composite component.<br />
XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />
{<br />
<br />
}<br />
}<br />
<br />
<br />
<br />
<br />
<br />
<br />
• formThree — yet another sample form:<br />
<strong>Using</strong> <strong>Zen</strong> 389
<strong>Zen</strong> Application Programming<br />
Class TestMe.Components.formThree Extends %ZEN.Component.composite<br />
{<br />
/// This is the XML namespace for this component.<br />
Parameter NAMESPACE = "TestMe";<br />
/// This Style block contains component-specific CSS style definitions.<br />
XData Style<br />
{<br />
<br />
}<br />
<br />
/// Contents of this composite component.<br />
XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />
{<br />
<br />
<br />
<br />
<br />
}<br />
/// colorChange<br />
Method colorChange(color) [ Language = javascript ]<br />
{<br />
alert('You have selected: ' + color);<br />
}<br />
}<br />
390 <strong>Using</strong> <strong>Zen</strong>
19<br />
<strong>Zen</strong> Security<br />
You can provide application-level security for <strong>Zen</strong> using CSP application settings. See the Caché<br />
Security Administration Guide, chapter Assets and Resources, topic Application Resources and Their<br />
Privileges.<br />
There are additional techniques for controlling access to pages and components within a <strong>Zen</strong> application.<br />
19.1 Controlling Access to Applications<br />
By default, when a user starts your <strong>Zen</strong> application it prompts the user to log in by displaying the<br />
standard Caché username and password dialog box. If you wish your application to present a custom<br />
login form, you must create and configure this form as follows:<br />
1. Create a new <strong>Zen</strong> page class.<br />
2. Within XData Contents, provide a whose nextPage value is the first <strong>Zen</strong> page that you<br />
want the user to see, upon successfully logging in:<br />
<br />
<br />
<br />
<br />
3. Make sure that, at minimum, this contains the following controls:<br />
• for the username<br />
• for the password<br />
Ensure that you provide a name attribute for each of these controls and that the corresponding<br />
name values are exactly as shown above: "CacheUserName" and "CachePassword". You<br />
<strong>Using</strong> <strong>Zen</strong> 391
<strong>Zen</strong> Security<br />
may provide other attributes for the controls as desired; a label is useful for each control so that<br />
the user knows what to enter.<br />
4. Provide a button. Your minimal user login form now looks like this:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
5. Define other characteristics of the form as desired.<br />
6. Start the Caché System Management Portal.<br />
7. Navigate to the [Home] > [Security Management] > [CSP Applications] page.<br />
8. Find your <strong>Zen</strong> application in the list and click its Edit button. The [Home] > [Security Management]<br />
> [CSP Applications] > [Edit CSP Application] page displays.<br />
9. In the Login Page field, enter the pathname of your new <strong>Zen</strong> page class. This pathname is relative<br />
to the Caché installation directory, for example:<br />
/csp/myApp/myLoginPage.cls<br />
10. Click Save.<br />
19.2 Controlling Access to Pages<br />
Each <strong>Zen</strong> page has a class parameter called RESOURCE that, if defined, provides the name of a system<br />
Resource for which the current user must hold USE privileges in order to view this page or to invoke<br />
any of its server-side methods from the client.<br />
19.3 Controlling Access to Components<br />
Each <strong>Zen</strong> component (subclass of %ZEN.Component.component) has a server-only property called<br />
%resource that determines whether or not this component should be added to the set of page components.<br />
The component projects this property to XML as an attribute called resource. You can use this resource<br />
when adding a component to XData Contents. For example:<br />
<br />
392 <strong>Using</strong> <strong>Zen</strong>
Controlling Access to Components<br />
If a resource value is specified, the current user must hold USE privileges on this resource or the<br />
component will not be added to the set of page components when the user attempts to display the page.<br />
This property is not available from the client.<br />
<strong>Using</strong> <strong>Zen</strong> 393
20<br />
<strong>Zen</strong> Localization<br />
When you localize the text for an application, you create an inventory of text strings in one language,<br />
then establish a convention for substituting translated versions of these messages when the application<br />
locale is different. Most of the information you need to localize <strong>Zen</strong> pages can be found in the book<br />
<strong>Using</strong> Caché Server Pages, chapter Localizing Text in a CSP Application. Everything described in<br />
that chapter for development of CSP pages also applies to <strong>Zen</strong> pages.<br />
There are a few additional details that apply only to <strong>Zen</strong>. This chapter:<br />
• Summarizes the CSP information<br />
• Describes <strong>Zen</strong> extensions to CSP techniques<br />
20.1 CSP Localization<br />
Important:<br />
This topic briefly outlines material from the Localizing Text in a CSP Application<br />
chapter in <strong>Using</strong> Caché Server Pages (CSP). If you are new to CSP, please read the<br />
other chapter before continuing in this book.<br />
For a simple demonstration of a localized CSP application, enter the following URI while Caché is<br />
running. Substitute your Caché Web server port number for 57772:<br />
http://localhost:57772/csp/samples/language.csp<br />
20.1.1 Localization Practices<br />
Caché supports the following process for localizing CSP application text:<br />
1. Developers determine where text strings are displayed in the application user interface.<br />
<strong>Using</strong> <strong>Zen</strong> 395
<strong>Zen</strong> Localization<br />
2. Developers create an XML message file that contains text strings in the original language.<br />
3. Developers import the XML into a Caché namespace.<br />
This adds new entries to the Message Dictionary in that namespace.<br />
4. Developers give the XML to a team of translators.<br />
5. Translators produce a new XML message file by substituting translated text for the original.<br />
6. Developers import the new XML into a Caché namespace.<br />
Translated and original texts coexist in the Message Dictionary.<br />
7. At runtime, the application chooses which text to display based on the browser default language.<br />
20.1.2 Message Dictionary<br />
A Message Dictionary is a simple database of text strings organized by domain name, language name,<br />
and message ID:<br />
• The text of each message is a string of up to 32K characters. A message may consist solely of<br />
text, or it may also contain one or more parameters specified by %1, %2, etc.<br />
• A domain name is any arbitrary string. It identifies a group of related text items, such as all<br />
messages for a specific application or page.<br />
• A language name is an all-lowercase language tag that conforms to RFC1766. It consists of one<br />
or more parts: a primary language tag (such as en or ja) optionally followed by a hyphen (-) and<br />
a secondary language tag (en-gb or ja-jp).<br />
• A message ID is any arbitrary string; it uniquely identifies a message. The message ID only needs<br />
to be unique within a domain. You may assign a message ID or allow Caché to assign one,<br />
depending on the conventions you use to create the message.<br />
Each user-defined namespace in Caché stores its Message Dictionary in a subscripted global called<br />
^CacheMsg. The order of subscripts in ^CacheMsg is domain, language, and message ID.<br />
20.1.3 $$$Text Macros<br />
The easiest way to create a Message Dictionary is to automatically generate Message Dictionary entries<br />
at compile time, by seeding the CSP class code with $$$Text macro calls. $$$Text automatically creates<br />
the message at compile time and generates the code that retrieves the message at runtime, as this topic<br />
explains.<br />
When it comes time to translate the application messages into another language, you can export the<br />
full list of messages for the original language out of the Message Dictionary by running an Export<br />
396 <strong>Using</strong> <strong>Zen</strong>
command. This generates a complete XML message file in the original language. See Managing a<br />
Message Dictionary in <strong>Using</strong> Caché Server Pages (CSP).<br />
The return value of a $$$Text macro is a %String. The correct $$$Text macro to use depends on the<br />
format you need for this output string:<br />
• $$$Text<br />
• $$$TextJS (applies JavaScript escaping to the $$$Text result)<br />
• $$$TextHTML (applies HTML escaping to the $$$Text result)<br />
The %String returned by $$$Text may be assigned to a variable, which you can use to represent the<br />
message in subsequent calls. For example:<br />
Set tmsg = $$$TextJS("Error saving production")<br />
&js<br />
Or, you can simply insert a $$$Text macro anywhere you need a string:<br />
&js<br />
20.1.3.1 $$$Text Arguments<br />
CSP Localization<br />
$$$Text has the arguments text, domain, and language as described in the following table. Only the<br />
first argument, text, is required.<br />
<strong>Using</strong> <strong>Zen</strong> 397
<strong>Zen</strong> Localization<br />
Argument<br />
text<br />
Description<br />
Non-empty string. text must be a literal string. It cannot use any type of<br />
expression syntax. The format used for text may be:<br />
"actualText"<br />
Or:<br />
"@textId@actualText"<br />
Where textId is a message ID and actualText is the text of the message.<br />
The string actualText may consist of any of the following items, separately<br />
or in combination:<br />
• Simple text, as permitted by the file format<br />
• Substitution arguments %1, %2, %3, or %4<br />
• HTML formatting<br />
• A string expression in Caché ObjectScript format<br />
If provided, the textId is used as the message ID. If @textId@ is not specified,<br />
Caché generates a new textId by calculating the 32–bit CRC (Cyclic<br />
Redundancy Check) of this text. If the textId is specified and a message<br />
already exists with this ID, the existing message is checked to see if it has<br />
the same text as actualText. If not, an error is reported.<br />
domain<br />
(Optional) A string specifying the domain for the new message. If not<br />
specified, domain defaults to the value of the DOMAIN class parameter at<br />
compile time and %response.Domain at runtime.<br />
398 <strong>Using</strong> <strong>Zen</strong>
CSP Localization<br />
Argument<br />
language<br />
Description<br />
(Optional) An RFC1766 code specifying the language. Caché converts<br />
this string to all-lowercase. If not specified, language defaults as follows:<br />
• At compile time: $$$DefaultLanguage.<br />
• At runtime: %response.Language, or if no value is defined for<br />
%response.Language then $$$DefaultLanguage.<br />
Tag-based CSP pages automatically acquire a value for<br />
%response.Language from browser settings, so it is available as a<br />
default language. This is not true for class-based CSP pages, which<br />
must explicitly set a value for %response.Language to use it as a<br />
default.<br />
You can assign a value to %response.Language by giving it the return<br />
value of the %Library.MessageDictionary class method MatchLanguage.<br />
Given a list of languages and a domain name, this method uses HTTP<br />
1.1 matching rules (RFC2616) to find the best-match language within<br />
the domain.<br />
20.1.3.2 $$$Text at Compile Time<br />
When you compile a class that contains calls to $$$Text, $$$TextJS, or $$$TextHTML macros, each<br />
call generates a message in the Message Dictionary, with text, message ID, domain, and language as<br />
provided by the macro arguments.<br />
20.1.3.3 $$$Text at Runtime<br />
If the message text contains arguments (%1, %2, %3, %4) you must specify the corresponding substitution<br />
text before displaying the text. Since $$$Text returns a string, you can use any string operation native<br />
to your coding language. For example, in JavaScript:<br />
var prompt = '#($$$TextHTML("Remove user %1 from this Role"))#';<br />
prompt = prompt.replace(/%1/g,member.userName);<br />
You can also input the $$$Text string into the first argument of the %response.FormatText method<br />
or a $$$FormatText macro. For details see Localization from Class Code in <strong>Using</strong> Caché Server Pages<br />
(CSP).<br />
<strong>Using</strong> <strong>Zen</strong> 399
<strong>Zen</strong> Localization<br />
20.2 <strong>Zen</strong> Localization<br />
<strong>Zen</strong> pages are CSP pages. All CSP localization practices also apply to <strong>Zen</strong> pages. However, <strong>Zen</strong> adds<br />
the following conventions to make localization even easier:<br />
• Any <strong>Zen</strong> property that has its ZENLOCALIZE parameter set to 1 (true) automatically generates<br />
a Message Dictionary entry. Caché generates the Message Dictionary using similar conventions<br />
as when you use textid="" in and other localizable CSP tags. That is:<br />
- The message text is the string value of the property<br />
- The message ID is the 32–bit CRC of the text<br />
- The domain takes the value of the DOMAIN class parameter<br />
- The language takes the value of the browser default language (at runtime)<br />
• The <strong>Zen</strong> datatype class, %ZEN.Datatype.caption, has a default value of 1 (true) for its ZENLOCAL-<br />
IZE parameter, so any property defined as having a type of %ZEN.Datatype.caption is automatically<br />
localized as described above.<br />
• For these conventions to work, the <strong>Zen</strong> page class that defines the property must provide a value<br />
for the DOMAIN class parameter.<br />
20.2.1 Localization for Built-In Components<br />
Essentially what happens when ZENLOCALIZE is true is that, when <strong>Zen</strong> generates the %CreatePage<br />
method from your description, <strong>Zen</strong> inserts the call to $$$Text on your behalf (without your<br />
needing to worry about setting the arguments properly). If you are using a component with a property<br />
that uses a <strong>Zen</strong> datatype with ZENLOCALIZE set to 1 (such as %ZEN.Datatype.caption), and you<br />
place this component within a element in XData Contents, and your page has a DOMAIN<br />
parameter value defined, then the code that <strong>Zen</strong> generates to set this property in %CreatePage automatically<br />
calls $$$Text. For example:<br />
<br />
Generates code like this in %CreatePage:<br />
Set bttn.caption = $$$Text("OK")<br />
On the other hand, if you programmatically build pages (without using ) there is no automatic<br />
localization of component properties, even if ZENLOCALIZE is true. In this case you must call $$$Text<br />
yourself.<br />
400 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Localization<br />
20.2.2 Localization for Custom Components<br />
If you are creating a new component, you can define properties that should be localized as datatype<br />
%ZEN.Datatype.caption:<br />
Property title As %ZEN.Datatype.caption;<br />
Within your component simply use ..title to refer to the property. You do not need $$$Text within<br />
your custom component code unless you have some static text that you wish to localize. Whenever a<br />
references your component, your property is automatically localized in the same way as builtin<br />
<strong>Zen</strong> components. For example:<br />
<br />
Generates code like this in %CreatePage:<br />
Set MyCmp = $$$Text("AAA")<br />
<strong>Using</strong> <strong>Zen</strong> 401
21<br />
<strong>Zen</strong> Reports<br />
<strong>Zen</strong> provides an extensible framework for specifying database reports in XHTML or PDF format.<br />
Report output in PDF format might look like the following sample.<br />
It takes three steps to generate <strong>Zen</strong> report output:<br />
<strong>Using</strong> <strong>Zen</strong> 403
<strong>Zen</strong> Reports<br />
1. The developer creates a <strong>Zen</strong> report class and, within it, provides two XML documents:<br />
• XData ReportDefinition describes the data<br />
• XData ReportDisplay describes the display<br />
2. The developer or end-user generates output by entering the report class URI in a browser, or by<br />
invoking the GenerateReport method from the command line or from within the application.<br />
The type of output must be specified:<br />
• XHTML can be viewed in a browser<br />
• PDF creates printer-friendly pages<br />
3. The report class guides the data and display information through one of the two processing<br />
sequences shown in the following figure: XHTML or PDF.<br />
How a <strong>Zen</strong> Report Class Produces a Report<br />
404 <strong>Using</strong> <strong>Zen</strong>
Building a Report<br />
The two main processing sequences for <strong>Zen</strong> reports are as follows:<br />
To XHTML<br />
To PDF<br />
For XHTML output, XData ReportDefinition causes a query to be run. <strong>Zen</strong> formats the data<br />
from this query as XML. Meanwhile, XData ReportDisplay generates an XSLT transformation<br />
called the To-HTML stylesheet. <strong>Zen</strong> applies this XSLT transformation to the XML file. The<br />
result is the XHTML output file.<br />
For PDF output, XData ReportDefinition causes a query to be run. <strong>Zen</strong> formats the data from<br />
this query as XML. Meanwhile, XData ReportDisplay generates an XSLT transformation<br />
called the To-XSLFO stylesheet. <strong>Zen</strong> sends this XSLT transformation and the XML file to<br />
a third-party rendering tool, which uses them to generate a report in XSL-FO format. The<br />
third-party tool then renders the XSL-FO as PDF.<br />
The next several topics in this chapter explain how to develop a <strong>Zen</strong> report class:<br />
• Building a Report<br />
• <strong>Zen</strong> Report Parameters<br />
• XData ReportDefinition<br />
• XData ReportDisplay, which may contain:<br />
- Layout and Display Elements<br />
- Stylesheet Control Elements<br />
The chapter then describes how to process the class to produce XHTML or PDF reports:<br />
• <strong>Zen</strong> Reports from a Web Browser<br />
• Configuring <strong>Zen</strong> for PDF Output<br />
• Troubleshooting <strong>Zen</strong> Reports<br />
• <strong>Zen</strong> Reports from a Command Line<br />
21.1 Building a Report<br />
This topic explains <strong>Zen</strong> report class structure by building a class in gradual steps.<br />
If you have a new Caché installation, you must first generate data records for the SAMPLES namespace.<br />
You only need to do this once per Caché installation. Enter the following URI in the browser:<br />
<strong>Using</strong> <strong>Zen</strong> 405
<strong>Zen</strong> Reports<br />
http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
Now you may begin the exercise as follows:<br />
1. Start Caché Studio.<br />
2. Choose File > Change Namespace or F4.<br />
3. Choose the SAMPLES namespace.<br />
4.<br />
Choose File > New or Ctrl-N or the<br />
5. Select the Custom tab.<br />
6. Click the New <strong>Zen</strong> Report icon.<br />
icon.<br />
7. Click OK.<br />
The <strong>Zen</strong> Report Wizard presents the fields shown in the following table. For this exercise, enter<br />
the values shown in the right-hand column of the table.<br />
Field<br />
Package Name<br />
Class Name<br />
Application<br />
Report Name<br />
Description<br />
Click Next.<br />
Meaning<br />
The package that will<br />
contain the report class.<br />
The report class name.<br />
The package and class<br />
name of the application<br />
that this report belongs to.<br />
The logical name of this<br />
report within its<br />
application.<br />
Any text that you want to<br />
use to describe the report.<br />
Value to Enter<br />
MyApp<br />
ReportDemo<br />
MyReport<br />
Sample of building a new<br />
report.<br />
8. The wizard prompts you to enter an SQL query to provide data for the report. Type:<br />
SELECT ID,Customer,Num,SalesRep,SaleDate<br />
FROM ZENApp_Report.Invoice ORDER BY SalesRep,Customer<br />
Click Finish.<br />
The New Report Wizard creates and displays a <strong>Zen</strong> report page class with pre-defined parameter<br />
values and the XML blocks XData ReportDefinition and XData ReportDisplay.<br />
406 <strong>Using</strong> <strong>Zen</strong>
9. Find the following text in the XData ReportDefinition block. Place the cursor between this comment<br />
and the closing element:<br />
<br />
10. A report consists of one or more nested groupings. Define the first grouping inside the XData<br />
ReportDefinition by adding the following element at the cursor position, before :<br />
<br />
<br />
<br />
<br />
Building a Report<br />
11.<br />
12.<br />
Choose Build > Compile or Ctrl-F7 or the icon.<br />
Choose View > Web Page or the icon. If you have difficulty viewing the <strong>Zen</strong> report page from<br />
Studio, start a browser session and enter the class name as follows:<br />
http://localhost:57772/csp/samples/MyApp.ReportDemo.cls<br />
Where 57772 is the Web server port number that you have assigned to Caché.<br />
The XML view of your report data displays as follows. It has structure, but no content:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
13. Add an element to the within XData ReportDefinition:<br />
<br />
<br />
<br />
<br />
<br />
14. Compile the class and view the report. The XML output appears as follows. Each <br />
element now includes an attribute, name, whose value is the SalesRep field returned by the SQL<br />
query:<br />
<strong>Using</strong> <strong>Zen</strong> 407
<strong>Zen</strong> Reports<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
15. Add an element to the group within XData ReportDefinition:<br />
<br />
<br />
<br />
<br />
<br />
<br />
16. Compile the class and view the report. The XML output appears as follows. Each <br />
element now includes an element called . The value within is the sum of all the<br />
Num field values for the corresponding SalesRep field returned by the SQL query:<br />
<br />
<br />
<br />
833<br />
<br />
<br />
774<br />
<br />
<br />
983<br />
<br />
<br />
826<br />
<br />
<br />
824<br />
<br />
<br />
825<br />
<br />
<br />
17. Add more , , and elements within XData ReportDefinition:<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
408 <strong>Using</strong> <strong>Zen</strong>
18. Compile the class and view the report. The XML output now displays a much larger data set for<br />
each sales person. The aggregate elements , , and appear at the end of<br />
each record.<br />
19. Now that you have structured the report data as XML, you can specify how to display this data<br />
in XHTML or PDF format.<br />
Find the following text in the XData ReportDisplay block. Place the cursor between this comment<br />
and the closing element:<br />
<br />
20. At the cursor position, add a element to enclose the display items within the report. Within<br />
the place a that displays a title for the report. Also add the title attribute to the <br />
element to set the title of the browser window:<br />
<br />
<br />
Tutorial Sales Report<br />
<br />
<br />
21. Change the DEFAULTMODE class parameter value from "xml" to "html".<br />
22. Compile the class and view the report.<br />
23. Add a table to XData ReportDisplay as follows:<br />
<br />
<br />
Tutorial Sales Report<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Where:<br />
Building a Report<br />
• is a reference to the element in the generated<br />
XML.<br />
• is the syntax for referring to the attribute name.<br />
• is the syntax for referring to the element .<br />
<strong>Using</strong> <strong>Zen</strong> 409
<strong>Zen</strong> Reports<br />
24. Compile the class and view the report.<br />
25. Highlight the heading by formatting it using a pre-defined style class. Change the element in<br />
XData ReportDisplay as follows:<br />
Tutorial Sales Report<br />
26. Compile the class and view the report.<br />
27. Consider adding the following display modifications within XData ReportDisplay. Some of these<br />
changes affect style and layout; others add data to the display:<br />
<br />
<br />
Tutorial Sales Report<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
28. Compile the class and view the report.<br />
21.2 <strong>Zen</strong> Report Parameters<br />
A <strong>Zen</strong> report class may define the class parameters listed in the following table.<br />
410 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Report Parameters<br />
Report Class Parameters<br />
Class Parameter<br />
DATASOURCE<br />
Description<br />
(Optional) Identifies an XML document that contains the data<br />
for the <strong>Zen</strong> report. This string can be the URI of any valid XML<br />
document. Relative URIs are handled with respect to the current<br />
URI.<br />
If DATASOURCE is an empty string, the class generates its own<br />
XML document using the specification in its XData ReportDefinition<br />
block. If a <strong>Zen</strong> report class has both a non-empty, valid<br />
DATASOURCE string and an XData ReportDefinition block, the<br />
DATASOURCE parameter takes precedence over the XData<br />
block.<br />
The DATASOURCE string can refer to an XML document created<br />
by another <strong>Zen</strong> report class in the same namespace. Use the<br />
$MODE=xml query parameter to specify that you want to use the<br />
XML output from that class:<br />
Parameter DATASOURCE="MyApp.Report.cls$MODE=xml";<br />
DEFAULTMODE<br />
Default output mode for the report. This value is used only if the<br />
URI parameter $MODE is not specified. Possible values are:<br />
• "html" — Report display in XHTML format<br />
• "pdf" — Report display in PDF format<br />
• "tohtml" — To-HTML stylesheet in XSLT format<br />
• "toxslfo" — To-XSLFO stylesheet in XSLT format<br />
• "xml" — Report data in XML format<br />
• "xslfo" — Report pre-display in XSL-FO format<br />
If there is no DEFAULTMODE and no $MODE, the default is<br />
"html".<br />
<strong>Using</strong> <strong>Zen</strong> 411
<strong>Zen</strong> Reports<br />
Class Parameter<br />
HTMLSTYLESHEET<br />
Description<br />
Identifies the to-HTML stylesheet that controls XHTML output<br />
for the <strong>Zen</strong> report. This string can be the URI of any valid XSLT<br />
stylesheet. Relative URIs are handled with respect to the current<br />
URI.<br />
If HTMLSTYLESHEET is an empty string, the class generates<br />
a to-HTML stylesheet using the specification in its XData<br />
ReportDisplay block. If a <strong>Zen</strong> report class has both a non-empty,<br />
valid HTMLSTYLESHEET string and an XData ReportDisplay<br />
block, the HTMLSTYLESHEET parameter takes precedence<br />
over the XData block.<br />
The HTMLSTYLESHEET string can refer to a to-HTML<br />
stylesheet created by another <strong>Zen</strong> report class in the same<br />
namespace. Use the $MODE=tohtml query parameter to specify<br />
that you want to use the to-HTML output from that class:<br />
Parameter HTMLSTYLESHEET="MyApp.Report.cls$MODE=tohtml";<br />
REPORTNAME<br />
REPORTXMLNAMESPACE<br />
XSLFOSTYLESHEET<br />
Controls the filename suggested by the browser when you ask<br />
to save a report in XHTML or PDF format.<br />
(Optional) XML namespace to be used in the generated XML<br />
report.<br />
Identifies the to-XSLFO stylesheet that controls PDF output for<br />
the <strong>Zen</strong> report. This string can be the URI of any valid XSLT<br />
stylesheet. Relative URIs are handled with respect to the current<br />
URI.<br />
If XSLFOSTYLESHEET is an empty string, the class generates<br />
a to-XSLFO stylesheet using the specification in its XData<br />
ReportDisplay block. If a <strong>Zen</strong> report class has both a non-empty,<br />
valid XSLFOSTYLESHEET string and an XData ReportDisplay<br />
block, the XSLFOSTYLESHEET parameter takes precedence<br />
over the XData block.<br />
The XSLFOSTYLESHEET string can refer to a to-XSLFO<br />
stylesheet created by another <strong>Zen</strong> report class in the same<br />
namespace. Use the $MODE=toxslfo query parameter to<br />
specify that you want to use the to-XSLFO output from that class:<br />
Parameter HTMLSTYLESHEET="MyApp.Report.cls$MODE=toxslfo";<br />
412 <strong>Using</strong> <strong>Zen</strong>
XData ReportDefinition<br />
21.3 XData ReportDefinition<br />
The XData ReportDefinition block specifies the data to gather for the report. It also describes how to<br />
format this data as XML. An XData ReportDefinition block may contain references to the following<br />
variable:<br />
• %val — the value of the field attribute in the same element<br />
And may contain the following XML elements:<br />
• — Identifies the query that returns the data.<br />
Contains the following elements in any order or quantity:<br />
- — Writes an XML element to the output XML file<br />
- — Writes an XML attribute to the output XML file<br />
- — Calculates sums and averages for reporting purposes<br />
Contains 0 or 1 of the following:<br />
- — Groups items together so that operations can be performed on the group<br />
The following is a sample XData ReportDefinition block:<br />
XData ReportDefinition<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
}<br />
You can omit or override the XData ReportDefinition block if you provide a valid value for the<br />
DATASOURCE class parameter. If you provide both, the DATASOURCE value takes precedence.<br />
<strong>Using</strong> <strong>Zen</strong> 413
<strong>Zen</strong> Reports<br />
You can also omit XData ReportDefinition if you only plan to use this <strong>Zen</strong> report class to generate<br />
XSLT stylesheets.<br />
21.3.1 The %val Variable<br />
%val is a variable that you can use only in an XData ReportDefinition block.<br />
You can use %val in the expression attribute for , , or . %val represents<br />
the value of the field from the field attribute in the same element. You can see this in the following<br />
example:<br />
<br />
Or in :<br />
<br />
also supports %val. You can use %val in a breakOnExpression attribute to represent the<br />
value of the field from the breakOnField value.<br />
21.3.2 <br />
The element is the top level container within an XData ReportDefinition block.<br />
Within an XData ReportDefinition block, a may contain multiple , ,<br />
and elements in any order, but without nesting them. A may contain one .<br />
Each may contain one . Only one may exist at each level of nesting within<br />
the .<br />
requires a name attribute and some combination of query attributes. supports the<br />
same attributes as .<br />
Important:<br />
There is a different element for use within an XData ReportDisplay block.<br />
21.3.3 <br />
The element is valid within a or in an XData ReportDefinition block.<br />
Each adds an XML element to the XML document. has the attributes listed in<br />
the following table.<br />
414 <strong>Using</strong> <strong>Zen</strong>
XData ReportDefinition<br />
Attribute<br />
expression<br />
Description<br />
(Optional) Can be used to process the field value before outputting it. The<br />
language of the expression must be Caché ObjectScript. Within the<br />
expression, the %val variable represents the field value. For example, in a<br />
<strong>Zen</strong> report class with a GetDisplayURL method:<br />
<br />
The expression attribute can be used without the field attribute to return<br />
static data such as the report run time:<br />
<br />
field<br />
name<br />
Specifies which resultset field to get the data from.<br />
Generates an XML element of this name in the output. An entry like this:<br />
<br />
Yields an XML element like this:<br />
July<br />
21.3.4 <br />
The element is valid within a or in an XData ReportDefinition block.<br />
works just like , but the data it captures is rendered as an attribute of the containing<br />
or element.<br />
21.3.5 <br />
The element may appear within a or . performs a calculation<br />
over every record in the resultset returned by the query for the XData ReportDefinition block.<br />
has the attributes listed in the following table.<br />
<strong>Using</strong> <strong>Zen</strong> 415
<strong>Zen</strong> Reports<br />
Attribute<br />
class<br />
method<br />
Description<br />
If the type is CLASS, the class attribute must specify the package and class<br />
name of a class that extends %ZEN.Report.CustomAggregate.<br />
You can create your own subclasses of %ZEN.Report.CustomAggregate, or<br />
there are several built-in aggregate classes that you can reference.<br />
If the type is CUSTOM, the method attribute must specify the name of a<br />
server-side method within the <strong>Zen</strong> report class. The method must have the<br />
following form:<br />
ClassMethod MyAgg(pMode As %String,<br />
pAccumValue As %String,<br />
pValue As %String,<br />
pCount As %Integer)<br />
As %String<br />
{<br />
Quit<br />
$Case(pMode,"Start":0,"Accum":pAccumValue+(pValue*2),"End":pAccumValue)<br />
}<br />
type<br />
Specifies which kind of aggregation to perform. Valid values include the following<br />
case-sensitive strings:<br />
• "SUM" — the sum of all values<br />
• "COUNT" — the total number of records<br />
• "AVG" — the average of all values<br />
• "MAX" — the maximum value in the set<br />
• "MIN" — the minimum value in the set<br />
• "CLASS" — (see the class attribute)<br />
• "CUSTOM" — (see the method attribute)<br />
21.3.5.1 Built-in Aggregate Classes<br />
The following are the built-in custom aggregate classes:<br />
• %ZEN.Report.Aggregate.CountDistinct<br />
The number of distinct values in a set of data, as opposed to a simple COUNT.<br />
• %ZEN.Report.Aggregate.Median<br />
The median of a set of numerical data, as opposed to a simple AVG (average). The median is a<br />
number with half of the data set of greater value than it, and half of lesser value.<br />
416 <strong>Using</strong> <strong>Zen</strong>
For a data set with an odd size, the median is a member of the data set. For a data set with an even<br />
size, the median is a value halfway between two members of the data set.<br />
• %ZEN.Report.Aggregate.Mode<br />
The statistical mode (most frequent observation) of a set of data.<br />
• %ZEN.Report.Aggregate.StDev<br />
The standard deviation of the values processed.<br />
XData ReportDefinition<br />
21.3.5.2 Creating a New Aggregate Class<br />
If you need a new type of aggregate, you can develop and use a custom aggregate class as follows:<br />
1. Subclass %ZEN.Report.CustomAggregate<br />
2. Override the following methods:<br />
• GetResult is invoked after every record has been processed to return the final value of the<br />
aggregate.<br />
• ProcessValue is called sequentially on each record returned by the report query or queries.<br />
3. Save and compile the class as myPackage.myClassName<br />
4. When referencing this calculation in the element, use these attributes:<br />
• type="CUSTOM"<br />
• class="myPackage.myClassName"<br />
The following example may be useful to you if you are creating your own aggregate class. This is the<br />
code for the built-in custom aggregate class %ZEN.Report.Aggregate.CountDistinct:<br />
<strong>Using</strong> <strong>Zen</strong> 417
<strong>Zen</strong> Reports<br />
/// Aggregate for counting the number of distinct values in a set of data<br />
Class %ZEN.Report.Aggregate.CountDistinct Extends %ZEN.Report.CustomAggregate<br />
{<br />
/// Array of values processed<br />
Property Values As array Of %String;<br />
/// Running count of distinct values processed<br />
Property Count As %Integer [ InitialExpression = 0 ];<br />
/// Processes each new value<br />
Method ProcessValue(pValue As %String) As %Status<br />
{<br />
If ..Values.GetAt(pValue) {<br />
// seen it already<br />
} Else {<br />
Do ..Values.SetAt(1,pValue)<br />
Set ..Count=..Count+1<br />
}<br />
}<br />
Quit $$$OK<br />
}<br />
/// Return the count of distinct values processsed<br />
Method GetResult() As %String<br />
{<br />
Quit ..Count<br />
}<br />
21.3.6 <br />
Within an XData ReportDefinition block, the element indicates that <strong>Zen</strong> should perform the<br />
same set of operations on all records from the resultset that match a specified criteria. If the <br />
specifies no criteria, <strong>Zen</strong> performs the operations on every record in the resultset. The elements<br />
contained within the element specify what to do. A may contain multiple ,<br />
, and elements in any order, but without nesting them.<br />
A may contain one . Each may contain one . Only one <br />
may exist at each level of nesting within the . You can see this convention in the sample XData<br />
ReportDefinition block.<br />
and have the general-purpose attributes listed in the following table.<br />
418 <strong>Using</strong> <strong>Zen</strong>
XData ReportDefinition<br />
Attribute<br />
breakOnExpression<br />
Description<br />
Provides an expression to apply to the value of the field specified<br />
by breakOnField. The language of the expression must be Caché<br />
ObjectScript. The %val variable gets the value of the raw data,<br />
and then the result of breakOnExpression string is returned.<br />
For example, suppose you want to group by month, and you have<br />
a method in the <strong>Zen</strong> report class called GetMonth which takes a<br />
date and returns the month.Then you could provide a like<br />
this:<br />
<br />
...<br />
<br />
breakOnField<br />
name<br />
The phrase breakOnField means “If you encounter this field, stop<br />
to examine its value.” All of the records in the resultset that contain<br />
the same value in the field specified by breakOnField are processed<br />
together.<br />
If the breakOnField attribute is omitted, or its value is left blank,<br />
the processes every record in the resultset in the same<br />
way.<br />
If you are breaking on a field, the query for the report should be<br />
ordered by that field. Field breaking examines the results sequentially<br />
and creates a break whenever the specified field changes.<br />
So if the query is not ordered by the field, a break may occur<br />
unexpectedly.<br />
The generates an XML element of this name in the output.<br />
If you do not provide a value for name, the generates a<br />
name based on the <strong>Zen</strong> report class name.<br />
A <strong>Zen</strong> report or may specify a query. The following table lists the attributes that<br />
support queries.<br />
<strong>Using</strong> <strong>Zen</strong> 419
<strong>Zen</strong> Reports<br />
Attribute<br />
OnCreateResultSet<br />
queryClass<br />
queryName<br />
runtimeMode<br />
sql<br />
Description<br />
(Optional) The name of a server-side callback method to call to<br />
create a %ResultSet object. The OnCreateResultSet value must be<br />
the name of a server-only method defined in the <strong>Zen</strong> report class.<br />
(Optional) The name of the class containing the query. You must<br />
also provide a value for queryName.<br />
(Optional) The name of the class query that will provide the<br />
%ResultSet for this list. You must also provide a value for<br />
queryClass.<br />
SQL runtime mode to apply to the %ResultSet object used to fetch<br />
results for this report. The default runtimeMode of 2 is appropriate<br />
for most cases and usually does not need to be changed. Possible<br />
values are: 0 for LOGICAL mode, 1 for ODBC mode, and 2 for<br />
DISPLAY mode.<br />
(Optional) Server-side SQL query to get contents of the <br />
list.<br />
This attribute has the underlying data type %ZEN.Datatype.sql. This<br />
means it cannot be accessed from the client. Its value is encrypted<br />
(using the current session key) when it is sent to the client. If this<br />
value is returned to the server, it is automatically decrypted. This<br />
makes it possible to place sensitive data on the client for future<br />
processing on the server, without letting a user view this data.<br />
For additional details, plus examples, see the <strong>Zen</strong> Tables chapter as follows:<br />
• How to use query attributes with or :<br />
- Specifying an SQL Query (sql)<br />
- Referencing a Class Query (queryClass, queryName)<br />
- <strong>Using</strong> a Callback Method (OnCreateResultSet)<br />
• How to provide elements within or :<br />
- Query Parameters<br />
420 <strong>Using</strong> <strong>Zen</strong>
XData ReportDisplay<br />
21.4 XData ReportDisplay<br />
The previous topic explained how to structure the XML data upon which the <strong>Zen</strong> report is based. This<br />
topic explains how to write a specification for displaying this data. The specification consists of an<br />
XData ReportDisplay block in the <strong>Zen</strong> report class.<br />
Styles in the XData ReportDisplay block are independent of the output format. At runtime, the choice<br />
of format depends on a parameter supplied by the caller in one of the following ways:<br />
• In a browser URI string (see Reports in a Web Browser)<br />
• At the Terminal command line (see <strong>Zen</strong> Reports from the Command Line)<br />
The exact value of the parameter depends on whether it is being used in the browser or at the command<br />
line. However, its meaning is the same in each environment. It instructs the <strong>Zen</strong> report class to create<br />
report output in one of the following formats:<br />
• XHTML — The <strong>Zen</strong> report class creates an XSLT stylesheet and uses this stylesheet to transforms<br />
its XML data into an XHTML report.<br />
• PDF — The <strong>Zen</strong> report class creates an XSLT stylesheet, then passes this XSLT stylesheet and<br />
the XML data file to a third-party rendering tool, which produces XSL-FO and then PDF output.<br />
An XData ReportDisplay block may contain the following XML elements:<br />
• — Identifies the title. Contains these elements (in the following order):<br />
- — general page characteristics, primarily for PDF output<br />
- — page headers, used in PDF and optionally in HTML<br />
- — page footers, used in PDF and optionally in HTML<br />
- — the container for elements that control:<br />
• Graphical layout (see Layout and Display Elements)<br />
• Style and appearance (see Stylesheet Control Elements)<br />
The following is a simple example that uses very few of the available elements:<br />
<strong>Using</strong> <strong>Zen</strong> 421
<strong>Zen</strong> Reports<br />
XData ReportDisplay<br />
{<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Tests<br />
<br />
<br />
<br />
<br />
<br />
}<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
You can omit the XData ReportDisplay block entirely, if you provide a valid value for the HTML-<br />
STYLESHEET and XSLFOSTYLESHEET class parameters. For details, see <strong>Zen</strong> Report Parameters.<br />
If you provide both an XData ReportDisplay block and parameter values, the parameter values take<br />
precedence.<br />
You can also omit XData ReportDisplay if you only plan to use this <strong>Zen</strong> report class to generate XML<br />
data files.<br />
422 <strong>Using</strong> <strong>Zen</strong>
XData ReportDisplay<br />
21.4.1 Dimension and Size<br />
An XData ReportDisplay block allows you to specify sizes (widths, heights, lengths, etc.) in a variety<br />
of units, just as you would in HTML or XSL-FO syntax. 2in, 5cm, 12px, 14pt, 3em, or 75% are all<br />
valid sizes. Generally, <strong>Zen</strong> measures percentage values with respect to the containing element.<br />
21.4.2 <br />
The element is the top level container in an XData ReportDisplay block.<br />
Important:<br />
There is a different element for use within an XData ReportDefinition block.<br />
Within an XData ReportDisplay block, may contain the following elements only. It must<br />
contain them in the following order and quantities:<br />
• (0 or 1)<br />
• (0 or 1)<br />
• (0 or 1)<br />
• (1 is required)<br />
A element that appears in an XData ReportDisplay block has the attributes listed in the following<br />
table.<br />
Attribute<br />
name<br />
style<br />
title<br />
Description<br />
The report name, which should match the top-level element name in the XML<br />
data for the report.<br />
If the XData ReportDefinition block from the same <strong>Zen</strong> report class is used<br />
to generate this XML, then the name attribute for the element in<br />
XData ReportDisplay should match the name attribute for the element<br />
in XData ReportDefinition.<br />
If style="none", the standard <strong>Zen</strong> stylesheet is not rendered, otherwise it is.<br />
The standard stylesheet is a collection of available style classes that includes<br />
p.banner1, table.table1, td.table1, th.table1, ..., th.table6, as well as table, td,<br />
and th.grid.<br />
For more on style classes, see the element.<br />
The report title, used for items such as the PDF filename or XHTML page<br />
title.<br />
<strong>Using</strong> <strong>Zen</strong> 423
<strong>Zen</strong> Reports<br />
21.4.3 <br />
The element applies primarily to PDF output. specifies physical layout<br />
characteristics such as page dimensions and margins. can contain multiple ,<br />
, and elements for custom styling.<br />
The element can be omitted from a , even if PDF output is intended. The result<br />
in this case is an 8.5x11 inch page with 1.25–inch left and right margins and 1–inch top and bottom<br />
margins.<br />
If more than one element is included in the , all but the first are ignored.<br />
has the attributes listed in the following table.<br />
Attribute<br />
footerHeight<br />
headerHeight<br />
height<br />
marginBottom<br />
marginLeft<br />
Description<br />
Like headerHeight, but refers to the .<br />
HTML length value that specifies a block of empty space to be reserved<br />
beneath the top margin, but above the main body of the report.<br />
headerHeight should be specified if this report has a <br />
element indicating a header to appear on every page.<br />
HTML length value that specifies the page height.<br />
HTML length value that specifies the bottom margin<br />
HTML length value that specifies the left margin.The margin is contained<br />
within the width of the page, so the width of the available area of the<br />
page is:<br />
width - (marginLeft + marginRight)<br />
marginRight<br />
marginTop<br />
width<br />
HTML length value that specifies the right margin.<br />
HTML length value that specifies the top margin<br />
HTML length value that specifies the page width.<br />
21.4.3.1 <br />
The element renders style information into a CSS class in the XHTML report, and into<br />
equivalent XSLT stylesheet information for the PDF report.<br />
elements can only occur as children of . Multiple elements may be present.<br />
Each element has the attribute listed in the following table.<br />
424 <strong>Using</strong> <strong>Zen</strong>
XData ReportDisplay<br />
Attribute<br />
name<br />
Description<br />
Identifies a style class. Style class names are of the form tag.class, as in<br />
cascading style sheets (CSS). Possible names include:<br />
• table (referring to general table layout)<br />
• th (table header cells)<br />
• td (table cells)<br />
• a (links)<br />
• p (paragraphs)<br />
For more on style classes, see the class attribute as described in Layout<br />
and Display Elements.<br />
The element contains elements that specify the styling information for the class. <br />
can only occur as a child of . It specifies a piece of style information for that class. has<br />
the attributes listed in the following table.<br />
Attribute<br />
name<br />
value<br />
Description<br />
The attribute name. This corresponds to a CSS attribute name (color,<br />
background-color, font-size, font-family, width, etc). <strong>Zen</strong> simply passes the<br />
attributes on to CSS and XSL-FO, so the user can specify anything; it<br />
is up to the browser or PDF rendering tool to be able to interpret the attribute.<br />
The value to assign to the attribute.<br />
To provide the equivalent of the CSS document fragment given here:<br />
th.myTable {<br />
background-color: blue;<br />
color: white;<br />
}<br />
The following element is needed:<br />
<br />
<br />
<br />
<br />
21.4.3.2 <br />
The element applies to XHTML output only. When producing the XSLT stylesheet for<br />
PDF output, the class simply ignores any elements.<br />
<strong>Using</strong> <strong>Zen</strong> 425
<strong>Zen</strong> Reports<br />
Multiple elements may be present within a element. Each <br />
element has has the attribute listed in the following table.<br />
Attribute<br />
href<br />
Description<br />
URI of an external CSS stylesheet to include in the HTML stylesheet.<br />
The href string can be a comma-delimited list of URIs, and each will be<br />
included; this the same as providing multiple elements.<br />
Some browsers struggle when the file referenced does not end in .css.<br />
21.4.3.3 <br />
The element applies to the XSLT stylesheet for PDF output only. When producing the<br />
HTML version of the report, the class simply ignores any elements.<br />
Multiple elements may be present within a element. Each <br />
element has the attribute listed in the following table.<br />
Attribute<br />
href<br />
Description<br />
Filename of an external XSLT file to include in the to-XSLFO stylesheet.<br />
This feature is potentially very powerful, but XSLT can be difficult to write.<br />
In practice, the main purpose of the element is for the external<br />
XSLT stylesheet to contain elements, which can do the<br />
same work as CSS classes.<br />
To continue the previous example, to import the th.myTable class from external files, the<br />
element would look something like this:<br />
<br />
<br />
<br />
<br />
With myStyle.css containing:<br />
th.myTable {<br />
background-color: blue;<br />
color: white;<br />
}<br />
And myStyle.xsl containing:<br />
<br />
blue<br />
white<br />
<br />
426 <strong>Using</strong> <strong>Zen</strong>
Layout and Display Elements<br />
21.4.4 <br />
The element, if present in the , must occur before the element.<br />
can contain the same layout and display elements as , but everything contained<br />
within is rendered in the blank space provided by the element headerHeight<br />
attribute.<br />
XHTML reports do not support page-by-page headers, so in XHTML reports the contents of <br />
are simply rendered at the beginning of the report.<br />
21.4.5 <br />
The element, if present in the , must occur before the element.<br />
is like . However, elements are not displayed in XHTML<br />
reports.<br />
21.4.6 <br />
The element is the required child of . It has no attributes, but contains the bulk of the<br />
report information. contains elements that control:<br />
• Graphical layout — see Layout and Display Elements<br />
• Style and appearance — see Stylesheet Control Elements<br />
21.5 Layout and Display Elements<br />
This topic describes the elements that display the visual content of the report. Any of these elements<br />
may be a child of , , , or . The elements are:<br />
• — Bar chart<br />
• — Group of items for a table row or column<br />
• — Group of items for a page footer<br />
• — Group of items for repeated actions<br />
• — Group of items for a page header<br />
• — Image<br />
• — Data value<br />
<strong>Using</strong> <strong>Zen</strong> 427
<strong>Zen</strong> Reports<br />
• — Horizontal line<br />
• — Line chart<br />
• — Bulleted or numbered list<br />
• — Raw text of any length<br />
• — Page break<br />
• — Pie chart<br />
• — Table<br />
Each of these elements has the three attributes described in the following table. It may have other<br />
attributes also; the next several topics describe them.<br />
Report Display Attributes<br />
Attribute<br />
class<br />
Description<br />
CSS style class to apply to the element. Style classes are defined by the<br />
element, and some are given by the standard style sheet.<br />
When specifying a value for the class attribute, do not include the element<br />
name that is given when creating the class. For example, if you have a style<br />
class named table.myTable that you want to use, in the specify:<br />
<br />
Parent elements propagate their class attribute value to children that do not<br />
have a class specified. So if you define table.myTable, th.myTable, and<br />
td.myTable, you only need to give the element a class attribute.You<br />
can even put a class attribute on the element to give a class for<br />
every element in the report (at least, for those that do not override it with a<br />
class attribute of their own).<br />
style<br />
Similar to the style attribute in CSS, this attribute may provide a semicolondelimited<br />
list of attribute:value pairs. For example:<br />
style="fill: yellow; font-size: 6pt ;"<br />
Information contained within the style attribute takes precedence over style<br />
information given by the class.<br />
width<br />
HTML length value that defines the element’s width. The exact meaning<br />
depend on the individual element. If widths are omitted, the PDF rendering<br />
tool can produce unexpected results.<br />
428 <strong>Using</strong> <strong>Zen</strong>
Layout and Display Elements<br />
21.5.1 <br />
The element renders all of its child elements sequentially. It can be used anywhere in the<br />
as a kind of spanning element, but it is most useful as a container within a . In general,<br />
a treats every child element as a new row or column, so the element can be used to<br />
group multiple elements into a single row or column.<br />
The element may contain any of the same common display elements as .<br />
has the common display attributes style, width, and class.<br />
21.5.2 <br />
Within an XData ReportDisplay block, the element allows the <strong>Zen</strong> report class to respond to<br />
the hierarchically structured data that is typical of XML.<br />
Important:<br />
There is a different element for use within an XData ReportDefinition block.<br />
is a display element, so has the common display attributes style, width, and class.<br />
also has the attributes listed in the following table.<br />
Attribute<br />
line<br />
Description<br />
HTML length value that specifies the thickness of the line to be drawn<br />
between each iteration of the group. If line is 0, no line is drawn.<br />
<strong>Using</strong> <strong>Zen</strong> 429
<strong>Zen</strong> Reports<br />
Attribute<br />
name<br />
Description<br />
Required. displays the contents of each element in the XML data<br />
whose name matches this attribute. So if your XML data contains<br />
elements, your XData ReportDisplay block could contain:<br />
...<br />
The elements within the container determine how the display<br />
handles the data within the container. can contain<br />
any of the common display elements listed at the beginning of this topic.<br />
elements can be nested. Suppose each elements<br />
contains multiple elements. To specify how to display each sale<br />
within the display for each sales representative, you would provide something<br />
like:<br />
<br />
<br />
...<br />
<br />
...<br />
<br />
To display a group as a table, see the group attribute of .<br />
pagebreak<br />
If true, put a page break after each iteration of the group.<br />
This attribute has the underlying data type %ZEN.Datatype.boolean. It has the<br />
value "true" or "false" in XData Contents, 1 or 0 in server-side code, true or<br />
false in client-side code. See Datatype Classes.<br />
21.5.3 and <br />
The and elements are simple containers used for clarity, but they can be useful to<br />
organize style within the report. Each can propagate its class attribute to its children.<br />
and have no attributes in addition to the common display attributes style, width,<br />
and class.<br />
21.5.4 <br />
The element inserts an image into the report.<br />
In addition to the common display attributes style, width, and class, has the attributes listed in<br />
the following table.<br />
430 <strong>Using</strong> <strong>Zen</strong>
Layout and Display Elements<br />
Attribute<br />
height<br />
src<br />
width<br />
Description<br />
HTML length value that specifies the image height.<br />
URI for source of the image. If the src attribute begins with an exclamation<br />
point, it is interpreted as an XPath expression just as in the field attribute of<br />
the element. This allows you to dynamically generate URIs within<br />
the XML data, and then use these customized URIs as the image source.<br />
When using ! to dynamically generate the image URI, the resulting string<br />
must be an absolute URI or it will not appear in the PDF report.<br />
HTML length value that specifies the image width.<br />
21.5.5 <br />
The element outputs literal values or data from the XML into the report. must have<br />
exactly one of its value, field, or special attributes specified.<br />
In addition to the common display attributes style, width, and class, has the attributes listed in<br />
the following table.<br />
Attribute<br />
field<br />
Description<br />
If the field attribute is specified, the renders the value of that<br />
field in the XML data. field is actually used as an XPath expression, so<br />
if you have the data:<br />
MegaPlex<br />
Systems<br />
To get the value of the id attribute you need the XPath expression:<br />
field= "@id"<br />
Whereas to obtain the value of the element you need the<br />
XPath expression:<br />
field="customer"<br />
The field attribute is interpreted with respect to the current <br />
matched. For an within , only<br />
attributes and children of are available.<br />
formatNumber<br />
String specifying the number format to use. This string uses the same<br />
conventions as the XSLT format-number function, such as ###.# for<br />
a three-digit number with one decimal place.<br />
<strong>Using</strong> <strong>Zen</strong> 431
<strong>Zen</strong> Reports<br />
Attribute<br />
link<br />
special<br />
Description<br />
Optional hyperlink to place around the item’s data. If the link attribute<br />
begins with an exclamation point, it is interpreted as an XPath<br />
expression just as in the field attribute. This allows you to dynamically<br />
generate URIs within the XML data, and then use these customized<br />
URIs in the display. If link is specified, the item’s style class will use the<br />
"a" option.<br />
If the special attribute is specified, the renders a pre-defined<br />
piece of dynamic data. Possible values for special are:<br />
• number — gives the record number within the group.<br />
• page-number — inserts the page number within a PDF report. Is<br />
rendered as '##' in XHTML.<br />
• page-count — inserts the number of pages within a PDF report. It<br />
is rendered as '##' in XHTML.<br />
• page-number-of — inserts the page number in the form '2 of 18'. It<br />
is rendered as '## of ##' in XHTML.<br />
• page-number-/ — inserts the page number in the form '2/18'. It is<br />
rendered as '##/##' in XHTML.<br />
References to the total page count can be slow in extremely large PDF<br />
reports. If speed is essential and you run into problems with speed,<br />
avoid page-count, page-number-of, and page-number-/.<br />
value<br />
If the value attribute is specified, the renders it as a literal value.<br />
21.5.6 <br />
The element inserts a line break into the report. This can either be a visible horizontal line or<br />
an empty line break.<br />
In addition to the common display attributes style, width, and class, has the attributes listed in<br />
the following table.<br />
Attribute<br />
align<br />
color<br />
Description<br />
Alignment within the report page. Possible values are "left", "right", and<br />
"center".<br />
CSS color value that specifies the line color. color only applies to solid or<br />
dashed lines<br />
432 <strong>Using</strong> <strong>Zen</strong>
Layout and Display Elements<br />
Attribute<br />
count<br />
length<br />
lineHeight<br />
pattern<br />
thickness<br />
Description<br />
The number of line breaks to draw.This is the same as repeating the <br />
element.<br />
HTML length value that specifies the line length. length only applies to solid<br />
or dashed lines.<br />
HTML length value that specifies how much space to leave for displaying<br />
the line. This is not the same as the line thickness when pattern is "solid"<br />
or "dashed". lineHeight applies to "empty" lines as well.<br />
Despite using this attribute, line spacing can vary between XHTML and<br />
XSL-FO (that is, PDF). This can be overcome using and elements.<br />
Possible values are "empty", "solid", and "dashed"<br />
HTML length value that specifies the line thickness. The default value is<br />
1px. thickness only applies to solid or dashed lines.<br />
21.5.7 <br />
The element is used to display an itemized or ordered list within a <strong>Zen</strong> report.<br />
The style attribute on the applies to its bullets or numbers.<br />
In addition to the common display attributes style, width, and class, has the attributes listed in<br />
the following table.<br />
Attribute<br />
group<br />
image<br />
startvalue<br />
type<br />
Description<br />
Required. group identifies the entry that provides the data for this<br />
list. The group value in must match the name value of some <br />
in XData ReportDefinition.<br />
The URI of an image to use as a custom bullet. If you provide an image<br />
value, the type attribute is ignored.<br />
The first number value for ordered lists. startvalue is always specified as an<br />
integer. If type is "A" and startvalue is "3", the first element in the list is<br />
labeled "C".<br />
The bullet or numbering style to use for list items. Possible values are:<br />
"none", "circle", "square", "disc", "1", "A", "a", "I", "i". PDF reports do not<br />
support "square" or "circle".<br />
<strong>Using</strong> <strong>Zen</strong> 433
<strong>Zen</strong> Reports<br />
21.5.8 <br />
The element renders a large block of static content. It treats its contents as raw text and uses the<br />
"p" option for its style class.<br />
has no attributes in addition to the common display attributes style, width, and class.<br />
21.5.9 <br />
The element inserts a page break in PDF output. It inserts a dashed line in the XHTML<br />
report on screen, and causes a page break when you print the XHTML report.<br />
21.5.10 <br />
The element outputs a table into the report.<br />
In addition to the common display attributes style, width, and class, has the attributes listed<br />
in the following table.<br />
Attribute<br />
align<br />
altcolor<br />
group<br />
Description<br />
Aligns the table within the report. Possible values are "left," "right," and<br />
"center".<br />
CSS color value that specifies the background color of the alternate rows<br />
(2, 4, 6, etc.).This is only possible when orient is "col" and group is specified.<br />
A table can be used to display a group of data. If the group attribute is<br />
specified, the table displays a row or column in the table for each item in<br />
the group. If no group is specified, there is only one row or column in the<br />
table (plus an optional header and optional footer row or column).<br />
434 <strong>Using</strong> <strong>Zen</strong>
Layout and Display Elements<br />
Attribute<br />
layout<br />
Description<br />
Possible layout values are "auto" and "fixed". For PDF output, the XEP<br />
rendering tool supports both "auto" and "fixed" formats. FOP supports "fixed"<br />
only.<br />
When layout is "fixed", it is important that you specify a width for each column.<br />
The code produces a good result from minimal width information, but<br />
you can gain closer control as follows:<br />
• If orient is "col," then each child of the table class should have a width<br />
attribute specified.<br />
• If orient is "row", then only one child of the table needs to have its widths<br />
specified. However, if that element within the table has a or<br />
child element to define a header column or footer column,<br />
it is necessary that these elements also specify their width.<br />
orient<br />
Each element contained within the table is treated as either a row or column,<br />
depending on the value of the orient attribute. If orient is "row," each child<br />
element of table will be placed in a new row. Similarly, if orient is "col" each<br />
child element will be placed in a new column. Possible values are "row"<br />
and "col". The default is "col".<br />
Every cell the table renders uses the "td" option for its style class, except for the header cells, which<br />
use "th".<br />
21.5.10.1 <br />
To include a caption for a row or column of the table, an element within a table can contain a <br />
element.<br />
The element works just like , and has the same attributes. When you place it as a<br />
child of an element within a table, it indicates that that row or column has a header, which it gets from<br />
the value of the element.<br />
When you have nested tables, it is possible for the inner table to have element within it, but<br />
that does not mean the is something for that table to display. It actually refers to giving the<br />
inner table a caption within the outer table.<br />
21.5.10.2 <br />
The element is the same as , except that it creates a footer for the row or column.<br />
<strong>Using</strong> <strong>Zen</strong> 435
<strong>Zen</strong> Reports<br />
21.6 Charts in <strong>Zen</strong> Reports<br />
Important:<br />
Like <strong>Zen</strong> Charts, charts in <strong>Zen</strong> reports use SVG for graphics. Support for SVG is built<br />
into Firefox 1.5 or later. If you are using Internet Explorer 6.0 or later, you must<br />
download the free SVG Viewer from Adobe to use charts in <strong>Zen</strong> reports.<br />
The syntax for placing charts in <strong>Zen</strong> reports is identical to the syntax for placing charts on <strong>Zen</strong> pages,<br />
with exceptions as noted in this topic. <strong>Zen</strong> reports support the , and <br />
elements only. <strong>Zen</strong> reports support chartPivot, but not chartStacked. does not support<br />
markers or filled line charts in <strong>Zen</strong> reports. Also, <strong>Zen</strong> report charts are not interactive.<br />
When used in <strong>Zen</strong> reports, the , and elements support the following<br />
attributes:<br />
Attribute<br />
<strong>Zen</strong> report<br />
attributes<br />
Chart<br />
attributes<br />
dataFields<br />
dataGroup<br />
seriesColors<br />
seriesCount<br />
Description<br />
General-purpose report display attributes: style, width, and class.<br />
General-purpose attributes that apply to any chart (see <strong>Zen</strong> Charts) plus<br />
the unique attributes that apply to , or .<br />
All charts: Comma-delimited list of fields to acquire data from. If a<br />
dataGroup is also provided, only the first data field in dataFields is used.<br />
Pie charts: A pie chart looks at the first field specified by dataFields and<br />
totals the value that each series has for this field. Each series then gets<br />
a slice proportional to its percentage of the total for this field.<br />
All charts: Specifies the group that provides the data elements for the<br />
chart.<br />
Pie charts: If dataGroup is specified, the pie chart determines the value<br />
for a series by summing the dataFields for each element in the<br />
dataGroup.<br />
Comma-delimited list of CSS color values used for data series. The<br />
colors can be acquired dynamically by using the form "!fieldname".<br />
Number of data series to display on this chart. If "", this is computed<br />
automatically from the chart’s data source.<br />
436 <strong>Using</strong> <strong>Zen</strong>
Stylesheet Control Elements<br />
Attribute<br />
seriesGroup<br />
seriesNames<br />
seriesSize<br />
Description<br />
All charts: The group that provides the list of series for the chart.<br />
Pie charts: seriesGroup is required. If series were specified statically,<br />
the series would be looking at the same data, and so the pie chart would<br />
be divided evenly no matter what.<br />
Comma-delimited list of names used to label each data series in the<br />
legend box. Series names can be acquired dynamically by beginning<br />
the value with a ! character. If seriesGroup is provided, only the first<br />
series name field is considered.<br />
Number of items within each data series to display on this chart. If<br />
omitted, <strong>Zen</strong> computes this number automatically from the chart’s data<br />
source.<br />
A or in a <strong>Zen</strong> report may contain and elements. When used<br />
in <strong>Zen</strong> reports, and support the following attributes:<br />
Attribute<br />
Axis<br />
attributes<br />
labelValues<br />
Description<br />
General-purpose attributes for chart axes.<br />
All charts: Comma-delimited list of label values of category axes. If left<br />
blank, the category number is used.<br />
Pie charts: labelValues cannot be specified on the chart, as pie charts<br />
do not have axes.<br />
21.7 Stylesheet Control Elements<br />
The following elements are valid anywhere within the element of an XData ReportDisplay<br />
block.<br />
21.7.1 <br />
The element can contain the same common display elements as , but everything contained<br />
within is rendered in the XSL-FO (that is, PDF) report only.<br />
is useful for correcting issues where the XHTML report and PDF report do not look alike due to<br />
inherent page differences, such as page breaks.<br />
<strong>Using</strong> <strong>Zen</strong> 437
<strong>Zen</strong> Reports<br />
21.7.2 <br />
The element is similar to , but renders its contents in the XHTML report only.<br />
21.7.3 <br />
The element writes directly to the stylesheet, instead of to the report.<br />
The element is a common display element, in the sense that it may legally appear anywhere<br />
within a or element. However, can be most useful within<br />
or . For example:<br />
<br />
<br />
This is HTML! ]]><br />
<br />
<br />
<br />
<br />
This is XSL-FO ]]><br />
<br />
<br />
21.8 <strong>Zen</strong> Reports from a Web Browser<br />
The XHTML and PDF reports can be viewed in a browser by entering the URI of the <strong>Zen</strong> report .cls<br />
file. To specify the output type, use a $MODE parameter in the query string. In the following examples,<br />
57772 is the port assigned to the Caché server:<br />
• To view the HTML report:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=html<br />
The report displays in HTML format.<br />
• To view the PDF report, first use the instructions in Configuring <strong>Zen</strong> for PDF Output, then provide<br />
the following URI:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=pdf<br />
The report displays in PDF format. Depending on your settings, the browser might first prompt<br />
you to save the file. If so, click Save to view the PDF.<br />
• To view raw data for a report in XML format:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=xml<br />
Colorized XML displays in the browser.<br />
438 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Reports from a Web Browser<br />
You can override the current DATASOURCE setting for the report class by providing a $DATA-<br />
SOURCE parameter in the URI.<br />
Note:<br />
The examples above use 57772, the default port number assigned to the Caché server. The<br />
port number in your configuration might be different. You can double-check the port number<br />
by navigating to the System Management Portal [Home] > [Configuration] > [Memory and<br />
Startup] page.<br />
21.8.1 Sample XHTML Output<br />
<strong>Using</strong> <strong>Zen</strong> 439
<strong>Zen</strong> Reports<br />
21.8.2 Sample XML Data View<br />
21.9 Configuring <strong>Zen</strong> for PDF Output<br />
When you load a <strong>Zen</strong> report class into a browser with a request to view the output as PDF, Caché calls<br />
out to the command line to run a third-party PDF rendering tool. The rendering tool applies the XSLT<br />
stylesheet to the XML data to transform the XML into XSL-FO. Finally, the tool transforms the XSL-<br />
FO into PDF.<br />
This works only if you have performed the required configuration steps, as follows:<br />
1. Install an XSL-FO to PDF rendering tool. Two of the available options are:<br />
• An open source project from Apache called FOP. You can download it from the following<br />
Web site:<br />
http://xmlgraphics.apache.org/fop<br />
To install, simply extract the files from the kit.<br />
440 <strong>Using</strong> <strong>Zen</strong>
• The XEP product from RenderX. You can download a free trial version that produces a<br />
RenderX watermark on each output page, or you can buy the XEP product. See this Web site<br />
for details:<br />
http://www.renderx.com/tools/xep.html<br />
To install, follow the instructions in the kit.<br />
2. Set the Caché global ^%SYS("zenreport","transformerpath") to location of the batch<br />
file or shell script that calls the rendering tool. Once you have installed FOP or XEP, this file is<br />
already present on your system. Find its location, then set the global accordingly:<br />
• For FOP, something like:<br />
Set ^%SYS("zenreport","transformerpath")="C:\fop-0.92beta\fop.bat"<br />
• Or similarly, for XEP:<br />
Set ^%SYS("zenreport","transformerpath")="C:\XEP\XEP.bat"<br />
Troubleshooting <strong>Zen</strong> Reports<br />
3. (Optional) You can create custom configuration files for FOP as described in:<br />
http://xmlgraphics.apache.org/fop/0.92/configuration.html<br />
If you want the Caché callout to FOP to use a custom configuration file, you can set the global<br />
^%SYS("zenreport","transformerconfig") to the path of the configuration file. Configuration<br />
files are important for adding fonts to FOP. You must first create font metrics, and then<br />
register them with FOP. The process is described on the FOP Web site at:<br />
http://xmlgraphics.apache.org/fop/0.92/fonts.html<br />
Note:<br />
PDF rendering can consume a lot of memory. If you run into trouble, you might want to<br />
modify the FOP.bat or XEP.bat file to increase the amount of memory available to the Java<br />
Virtual Machine. The respective products provide documentation that explains how to do<br />
this.<br />
21.10 Troubleshooting <strong>Zen</strong> Reports<br />
When specifying $MODE=html or $MODE=pdf you can also set the query parameter $LOG=1. This<br />
allows you to view the output of the transformation from XML to XHTML or the transformation from<br />
XML via XSLT to XSL-FO to PDF, respectively. This information can be useful when the transformation<br />
fails. For example:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=pdf&$LOG=1<br />
<strong>Using</strong> <strong>Zen</strong> 441
<strong>Zen</strong> Reports<br />
Where 57772 is the port number assigned to the Caché server.<br />
XSL-FO to PDF Transformation Log<br />
Note:<br />
Syntax errors in ReportDisplay are sometimes reported as FOP errors without being caught<br />
on the Caché side. $LOG=1 can be useful for exploring this type of bug.<br />
You can also display diagnostic information for a <strong>Zen</strong> report by providing special values for the<br />
$MODE query parameter when you supply the .cls URI to the browser. For example:<br />
• To view the XSLT stylesheet that turns XML into XHTML:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=tohtml<br />
• To view the XSLT stylesheet that turns XML into XSL-FO:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=toxslfo<br />
• To view the XSL-FO stylesheet before PDF rendering:<br />
http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=xslfo<br />
Note:<br />
The examples above use 57772, the default port number assigned to the Caché server. The<br />
port number in your configuration might be different. You can double-check the port number<br />
by navigating to the System Management Portal [Home] > [Configuration] > [Memory and<br />
Startup] page.<br />
442 <strong>Using</strong> <strong>Zen</strong>
XSL-FO Prior to PDF Rendering<br />
<strong>Zen</strong> Reports from a Command Line<br />
21.11 <strong>Zen</strong> Reports from a Command Line<br />
You can run a <strong>Zen</strong> report from the Terminal command line as follows:<br />
1. Change to the namespace containing the <strong>Zen</strong> report class:<br />
ZN "mySpace"<br />
2. Create an instance of the <strong>Zen</strong> report class:<br />
Set report=##class(myPackage.myClassName).%New()<br />
3. Run the report:<br />
Do report.GenerateReport("C:\Temp\mySample.pdf",2)<br />
Where:<br />
• C:\Temp\mySample.pdf is the pathname of the output file<br />
• 2 is an integer that tells <strong>Zen</strong> which type of report output to generate.<br />
Possible values include:<br />
- 0 — XML<br />
- 1 — XHTML<br />
<strong>Using</strong> <strong>Zen</strong> 443
<strong>Zen</strong> Reports<br />
- 2 — PDF. This works only if you have already used the instructions in the topic Configuring<br />
<strong>Zen</strong> for PDF Output.<br />
And for debugging purposes:<br />
- 3 — To-HTML stylesheet<br />
- 4 — To-XSLFO stylesheet<br />
• You may also provide an optional third parameter value of 1 (true):<br />
Do report.GenerateReport("C:\Temp\mySamplePDF.log",2,1)<br />
If so, the output file contains the transformation log rather than the report. This log is similar<br />
to the result in the browser when you supply the query parameter $LOG=1.<br />
444 <strong>Using</strong> <strong>Zen</strong>
22<br />
<strong>Zen</strong> Wizards<br />
This chapter describes the Caché Studio wizards that <strong>Zen</strong> provides:<br />
• Wizards for creating new application, component, page, or report classes.<br />
• Studio Assist (word completion) to help you rapidly add components to page classes.<br />
• Wizards for adding charts, elements, methods, and styles to page classes.<br />
22.1 New <strong>Zen</strong> Application Wizard<br />
Note:<br />
For background information, see <strong>Zen</strong> Application Concepts and <strong>Zen</strong> Application Programming.<br />
The <strong>Zen</strong> Tutorial chapter provides a sample New <strong>Zen</strong> Application Wizard session in the topic<br />
Creating a <strong>Zen</strong> Application.<br />
You can use the New <strong>Zen</strong> Application Wizard as follows:<br />
1. Start Studio.<br />
2.<br />
Choose File > New or Ctrl-N or the icon.<br />
3. Click the Custom tab.<br />
4. Click the New <strong>Zen</strong> Application icon.<br />
5. Click OK. The <strong>Zen</strong> Application Wizard dialog displays.<br />
6. Enter data in the following fields:<br />
• Package Name — Package that will contain the new application class.<br />
• Class Name — Class name of the new application class.<br />
<strong>Using</strong> <strong>Zen</strong> 445
<strong>Zen</strong> Wizards<br />
• Application Name — Logical name of the application.<br />
• Description — Any text that you want to use to describe the application.<br />
7. Click Finish. The dialog closes and your new <strong>Zen</strong> application class displays in Studio.<br />
8. Modify the <strong>Zen</strong> application class as desired.<br />
To supply style definitions that apply to all pages in this application, use the <strong>Zen</strong> Style Wizard to<br />
edit XData Style or set the CSSINCLUDES class parameter.<br />
9.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
icon.<br />
22.2 New <strong>Zen</strong> Component Wizard<br />
Note:<br />
For background information, see Custom Components.<br />
You can use the New <strong>Zen</strong> Component Wizard as follows:<br />
1. Start Studio.<br />
2.<br />
Choose File > New or Ctrl-N or the<br />
3. Click the Custom tab.<br />
4. Click the New <strong>Zen</strong> Component icon.<br />
icon.<br />
5. Click OK. The <strong>Zen</strong> Component Wizard dialog displays.<br />
6. Enter data in the following fields:<br />
• Package Name — Package that will contain the new component class.<br />
• Class Name — Class name of the new component class.<br />
• Type — Choose a parent class for the component:<br />
- component — See Creating Custom Components<br />
- composite — See Building Composite Components<br />
- control — See <strong>Zen</strong> Controls and Custom Components<br />
- svgComponent — See <strong>Zen</strong> and SVG and Creating a Custom Meter<br />
• XML Namespace — If the component is a composite, you must reference this namespace when<br />
you place the component on a <strong>Zen</strong> page, using the syntax . A<br />
446 <strong>Using</strong> <strong>Zen</strong>
namespace also helps to organize other types of custom component; see the chapter Custom<br />
Components, topic XML Namespace.<br />
• Description — Any text that you want to use to describe the component.<br />
7. Click Finish. The dialog closes and your new <strong>Zen</strong> component class displays in Studio.<br />
8. Modify the <strong>Zen</strong> component class as desired:<br />
New <strong>Zen</strong> Page Wizard<br />
• Be sure to implement the %DrawHTML method. The wizard provides a template for this<br />
method in the class.<br />
• If you want to supply style definitions for the custom component, consult the chapter Custom<br />
Components, topic Custom Style. You can use the <strong>Zen</strong> Style Wizard to add style definitions.<br />
9.<br />
Choose Build > Compile or Ctrl-F7 or the<br />
icon.<br />
22.3 New <strong>Zen</strong> Page Wizard<br />
Note:<br />
For background information, see <strong>Zen</strong> Application Concepts and <strong>Zen</strong> Application Programming.<br />
The <strong>Zen</strong> Tutorial chapter provides a sample New <strong>Zen</strong> Page Wizard session in the topic Creating<br />
a <strong>Zen</strong> Page.<br />
You can use the New <strong>Zen</strong> Page Wizard as follows:<br />
1. Start Studio.<br />
2.<br />
Choose File > New or Ctrl-N or the icon.<br />
3. Click the Custom tab.<br />
4. Click the New <strong>Zen</strong> Page icon.<br />
5. Click OK. The <strong>Zen</strong> Page Wizard dialog displays.<br />
6. Enter data in the following fields:<br />
• Package Name — Package that will contain the new page class.<br />
• Class Name — Class name of the new page class.<br />
• Application — Package and class name of the application that this page belongs to.<br />
• Page Name — Logical name of this page within its application.<br />
• Domain — Domain this page will use for localization of caption text.<br />
<strong>Using</strong> <strong>Zen</strong> 447
<strong>Zen</strong> Wizards<br />
• Description — Any text that you want to use to describe the page.<br />
• Page type — Choose one of the following:<br />
- Page — Normal page class.<br />
- Subclass of Template Page — Subclass of a template page class. If you choose this option,<br />
the Super class combo box displays. If you click the down-arrow in this box, a list of<br />
page class names displays. The list is alphabetical by package name. Choose a page class<br />
from this listp;.<br />
7. Click Next.<br />
8. Choose an initial page layout:<br />
• Column 2 — Two columns, plus space for a title along the top<br />
• Title Page — Space for a title along the top<br />
• Default — No pre-defined layout<br />
9. Click Finish. The dialog closes and your new <strong>Zen</strong> page class displays in Studio.<br />
10. Modify the <strong>Zen</strong> page class as desired:<br />
• To supply style definitions for the page, use the <strong>Zen</strong> Style Wizard to edit XData Style.<br />
• To supply page contents, edit XData Contents. Within XData Contents you may add components<br />
using Studio Assist or the <strong>Zen</strong> Element Wizard. A wizard is also available for adding<br />
charts.<br />
• To add server-side and client-side methods, use the <strong>Zen</strong> Method Wizard.<br />
11.<br />
12.<br />
Choose Build > Compile or Ctrl-F7 or the icon.<br />
Choose View > Web Page or the icon. The page displays in the browser.<br />
22.4 New <strong>Zen</strong> Report Wizard<br />
Note:<br />
For background information and a sample wizard session, see <strong>Zen</strong> Reports.<br />
You can use the New <strong>Zen</strong> Report Wizard as follows:<br />
1. Start Studio.<br />
448 <strong>Using</strong> <strong>Zen</strong>
New <strong>Zen</strong> Report Wizard<br />
2.<br />
Choose File > New or Ctrl-N or the icon.<br />
3. Select the Custom tab.<br />
4. Click the New <strong>Zen</strong> Report icon.<br />
5. Click OK. The <strong>Zen</strong> Report Wizard dialog displays.<br />
6. Enter data in the following fields:<br />
• Package Name — Package that will contain the report class.<br />
• Class Name — Report class name.<br />
• Application — Package and class name of the application that this report belongs to.<br />
• Report Name — Logical name of this report within its application.<br />
• Description — Any text that you want to use to describe the report.<br />
7. Click Next. The wizard prompts for an SQL query to provide data for the report.<br />
8. Type an SQL query into the text box<br />
9. Click Finish. The dialog closes and your new <strong>Zen</strong> report class displays in Studio.<br />
10. Find the following text in the XData ReportDefinition block:<br />
<br />
Delete this comment. Add a element between and the closing element.<br />
Note:<br />
For background information, see the <strong>Zen</strong> Reports topic XData ReportDefinition.<br />
11. Find the following text in the XData ReportDisplay block.<br />
<br />
Delete this comment. Add a element between and the closing element.<br />
Note:<br />
For background information, see the <strong>Zen</strong> Reports topic XData ReportDisplay.<br />
12. Set the DEFAULTMODE class parameter value to indicate the report output format.<br />
13. Modify the <strong>Zen</strong> report class as desired.<br />
14.<br />
15.<br />
Choose Build > Compile or Ctrl-F7 or the icon.<br />
Choose View > Web Page or the icon. The report displays in the browser.<br />
<strong>Using</strong> <strong>Zen</strong> 449
<strong>Zen</strong> Wizards<br />
22.5 Studio Assist<br />
Note:<br />
The <strong>Zen</strong> Tutorial chapter explores Studio Assist in the topics Hello World and Creating a<br />
<strong>Zen</strong> Page.<br />
You can use Studio Assist (word completion as you type) within <strong>Zen</strong> classes as follows:<br />
1. Start Studio.<br />
2. Open a <strong>Zen</strong> page or report class.<br />
3. Position the cursor in one of the following elements:<br />
• XData Contents, between and <br />
• XData ReportDefinition, between and <br />
• XData ReportDisplay, between and <br />
4. Begin typing. At the first meaningful character, Studio provides a context-sensitive list of appropriate<br />
XML elements and attributes. This list includes the built-in <strong>Zen</strong> components as well as any<br />
custom or composite components that you have defined.<br />
5. To choose an item from this list, click on it and press Enter.<br />
6. Studio completes the word and adds it to the code.<br />
22.6 <strong>Zen</strong> Chart Wizard<br />
Note:<br />
For background information, see <strong>Zen</strong> Charts.<br />
Every chart is an SVG component as described in <strong>Zen</strong> and SVG. This means that charts follow the<br />
layout and style conventions for SVG components, with the additional characteristics described in <strong>Zen</strong><br />
Charts. Most importantly, a <strong>Zen</strong> chart must appear within an container. Remember this<br />
when adding a chart to XData Contents.<br />
You can use the <strong>Zen</strong> Chart Wizard as follows:<br />
1. Start Studio.<br />
2. Open the class.<br />
3. Position the cursor inside XData Contents.<br />
4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />
450 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Chart Wizard<br />
5. Select the <strong>Zen</strong> Chart Wizard.<br />
6. Click OK. The <strong>Zen</strong> Chart Wizard dialog displays.<br />
7. The Type field presents a list of chart types.<br />
• barChart — See Bar Charts<br />
• diffChart — See Difference Charts<br />
• hilowChart — See High/Low Charts<br />
• lineChart — See Line Charts<br />
• pieChart — See Pie Charts<br />
• xyChart — See Scatter Diagrams<br />
8. Choose a chart type.<br />
9. Click Next. The <strong>Zen</strong> Chart Wizard displays a split screen:<br />
• At left is an illustration of how the current attributes affect chart style.<br />
• At right is a list of attributes. Above this list, you can click Chart, X Axis, or Y Axis to view<br />
the attributes for these different aspects of the chart.<br />
10.<br />
To provide a value for any attribute, click in the field beside it. A popup button displays in<br />
the field. Click on the popup button. The <strong>Zen</strong> Value Editor dialog pops up. The entry field in this<br />
dialog is sensitive to the data type of the property. For example:<br />
• If the type is boolean, the dialog provides a checkbox.<br />
• If one value must be selected from a set, the dialog displays radio buttons.<br />
• If the type is a CSS style definition, the CSS Declaration Editor pops up.<br />
• If the type is a JavaScript expression, a text area offers room to type the entry.<br />
In all cases, a brief description of the property appears on the dialog, below the entry field. For<br />
details, and for descriptions of how the individual properties work together, you can find documentation<br />
in the chapter <strong>Zen</strong> Charts.<br />
Click OK to save your changes and return to the <strong>Zen</strong> Chart Wizard. The list of chart attributes now<br />
contains your entry. You may repeat this step as often as needed to supply attributes for this chart.<br />
11. To accept the result of all your changes to this chart definition, click Finish. The <strong>Zen</strong> Chart Wizard<br />
dialog closes and the completed chart definition appears in the XData Contents block of your <strong>Zen</strong><br />
page class.<br />
<strong>Using</strong> <strong>Zen</strong> 451
<strong>Zen</strong> Wizards<br />
22.7 <strong>Zen</strong> Element Wizard<br />
Note:<br />
For background information, see <strong>Zen</strong> Layout.<br />
You can use the <strong>Zen</strong> Element Wizard as follows:<br />
1. Start Studio.<br />
2. Open the class.<br />
3. Position the cursor inside XData Contents.<br />
4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />
5. Select the <strong>Zen</strong> Element Wizard.<br />
6. Click OK. The <strong>Zen</strong> Element Wizard dialog displays.<br />
7. In the Element field, click the down-arrow to display a dropdown list of <strong>Zen</strong> components. This<br />
list includes the built-in <strong>Zen</strong> components as well as any custom or composite components that<br />
you have defined. Components in this list are sorted alphabetically by package name, so the order<br />
is:<br />
• Auxiliary components, such as for <br />
• Built-in <strong>Zen</strong> components, such as <br />
• User-defined components, such as composites or custom components<br />
8. Click on a component name.<br />
9. Click Next. The <strong>Zen</strong> Element Wizard displays an alphabetical list of the properties of the component<br />
that you selected.<br />
10. To provide a value for any property, click the Edit button beside its name. The <strong>Zen</strong> Value Editor<br />
dialog pops up. The entry field in this dialog is sensitive to the data type of the property. For<br />
example:<br />
• If the type is boolean, the dialog provides a checkbox.<br />
• If one value must be selected from a set, the dialog displays radio buttons.<br />
• If the type is a CSS style definition, the CSS Declaration Editor pops up.<br />
• If the type is a JavaScript expression, a text area offers room to type the entry.<br />
In all cases, a brief description of the property appears on the dialog, below the entry field. For<br />
details, and for descriptions of how the individual properties work together, you can find documentation<br />
in this manual, particularly:<br />
452 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Method Wizard<br />
• <strong>Zen</strong> Layout<br />
• <strong>Zen</strong> Style<br />
• <strong>Zen</strong> Tables<br />
• <strong>Zen</strong> and SVG<br />
• <strong>Zen</strong> Charts<br />
• <strong>Zen</strong> Forms<br />
• <strong>Zen</strong> Controls<br />
• Model View Controller<br />
• <strong>Zen</strong> Navigation<br />
• Popup Windows and Dialogs<br />
• Other <strong>Zen</strong> Components<br />
• Custom Components<br />
Click OK to save your changes and return to the <strong>Zen</strong> Element Wizard. The list of properties now<br />
contains your entry. You may repeat this step as often as needed to supply values for properties<br />
of this component.<br />
11. To accept the result of all your changes to this component definition, click Finish. The <strong>Zen</strong> Element<br />
Wizard dialog closes and the completed component definition appears in the XData Contents<br />
block of your <strong>Zen</strong> page class.<br />
22.8 <strong>Zen</strong> Method Wizard<br />
Note:<br />
For background information, see <strong>Zen</strong> Application Programming. The <strong>Zen</strong> Tutorial chapter<br />
provides sample <strong>Zen</strong> Method Wizard sessions in the topics Step 3: Client-side Method and<br />
Step 5: Server-side Method.<br />
You can use the <strong>Zen</strong> Method Wizard as follows:<br />
1. Start Studio.<br />
2. Open a <strong>Zen</strong> page class.<br />
3. Position the cursor at the end of the class, but before the final closing brace }.<br />
4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />
5. Select the <strong>Zen</strong> Method Wizard.<br />
<strong>Using</strong> <strong>Zen</strong> 453
<strong>Zen</strong> Wizards<br />
6. Click OK. The <strong>Zen</strong> Method Wizard dialog displays.<br />
7. Choose a method Scope, either instance or class.<br />
8. Choose a Location where the method will execute, and enter a Method Name.<br />
By convention, method execution and names are related as follows. See the chapter <strong>Zen</strong> Tutorial,<br />
topic <strong>Zen</strong> Naming Conventions for details:<br />
Location Choice<br />
runs on the client<br />
runs on the server<br />
is only available on the server<br />
is a server-side callback for a component<br />
Method Type<br />
Client-only<br />
<strong>Zen</strong> method<br />
Server-only utility<br />
Server-only callback<br />
Naming<br />
Convention<br />
myMethod<br />
MyMethod<br />
%MyMethod<br />
MyMethod<br />
9. If you choose the option is a server-side callback for a component in the previous step, the <strong>Zen</strong><br />
Method Wizard dialog adds a Server-side callback field. This field offers a dropdown list of<br />
attributes whose value is the name of a server-side callback method. These include attributes such<br />
as OnSubmitForm or OnDrawContent. Choose a component and attribute from<br />
this list.<br />
The Server-side callback entry adds a comment to your method body, reminding you which component<br />
and attribute you intend to associate with this callback method. You must still add the<br />
relevant attribute to the component definition in XData Contents, but the reminder can be useful<br />
as you work with the class.<br />
10. In the Description field, enter any text that you want to use to describe the method.<br />
11. Leave the Try/Catch box checked if you want the wizard to write a try/catch error processing<br />
template into your method. For details, see the <strong>Using</strong> Caché ObjectScript chapter, Error Processing.<br />
In a client-side method the template looks like this:<br />
Method mMethod() [Language = JavaScript]<br />
{<br />
try {<br />
alert('Client Method');<br />
// TODO: implement<br />
}<br />
catch (ex) {<br />
zenExceptionHandler(ex,arguments);<br />
}<br />
}<br />
In a server-side method the template looks like this<br />
454 <strong>Using</strong> <strong>Zen</strong>
<strong>Zen</strong> Style Wizard<br />
Method MyMethod() [<strong>Zen</strong>Method]<br />
{<br />
Try {<br />
// TODO: implement<br />
&js<br />
}<br />
Catch(ex) {<br />
&js<br />
}<br />
Quit<br />
}<br />
To skip this feature, uncheck the Try/Catch box.<br />
12. Click Finish. The dialog closes and your new method definition displays within the <strong>Zen</strong> page class<br />
in Studio.<br />
13. Implement the method as desired.<br />
22.9 <strong>Zen</strong> Style Wizard<br />
Note:<br />
For background information, see <strong>Zen</strong> Style.<br />
You can use the <strong>Zen</strong> Style Wizard as follows:<br />
1. Start Studio.<br />
2. Open the class whose XData Style block you want to edit.<br />
3. Within the XData Style block, position the cursor between and .<br />
4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />
5. Select the <strong>Zen</strong> Style Wizard.<br />
6. Click OK. A list of pre-defined styles appears. This list is organized alphabetically by component<br />
name. As discussed in the chapter <strong>Zen</strong> Style, topic Overriding Built-in Styles, some of the component<br />
names may be unfamiliar. These are the parent classes for components that you actually place<br />
on the <strong>Zen</strong> page. For example, to edit styles for tablePane (the child) you must select styles from<br />
the list provided for simpleTablePane (the parent).<br />
7. Scroll down the list to see the styles that it offers.<br />
8. Select the radio button next to the name of the CSS style you want to edit.<br />
9. Click Next. The <strong>Zen</strong> Style Wizard echoes your selection and provides a sample of its current<br />
appearance.<br />
10. Click Edit. The CSS Declaration Editor displays. You can add, remove, or edit statements as many<br />
times as needed to define the CSS rule.<br />
<strong>Using</strong> <strong>Zen</strong> 455
<strong>Zen</strong> Wizards<br />
11. To add a CSS name-value pair:<br />
• Click on the item --New-- in the CSS Declarations text box.<br />
• Click the down-arrow on the Property box to display an alphabetized list of CSS argument<br />
names (background-color, font-weight, width, etc). Click on a name to choose it.<br />
• Either type a CSS value in the Value field or click the Edit button to display the CSS Value<br />
Editor.<br />
• The CSS Value Editor is sensitive to the values that can be entered for the CSS argument you<br />
chose. If there is a fixed list of options, you can choose them from a dropdown list. If there<br />
is the option of typing in a value other than the fixed list, you can do that too.<br />
• If you choose a compound CSS style argument such as border-top, the editor prompts you<br />
for each choice independently, for example:<br />
- width — thin, medium, thick, 1px, 2px, 3px, 4px, inherit<br />
- style — none, hidden, dotted, dashed, solid, double, groove, ridge, inset, outset, inherit<br />
- color — A dropdown list of standard CSS color names including black, blue, red, darkred,<br />
etc. Alternatively you can click the Browse button to display a detailed color choice<br />
dialog where you can make a visual color selection. When you click on a color sample<br />
in this dialog and click OK, <strong>Zen</strong> provides this color to your CSS statement as an HTML<br />
color value.<br />
The result is then something like this: border-top: 1px solid #70DFF0;<br />
• Click OK to save your changes and return to the CSS Declaration Editor. The CSS Declarations<br />
text box now contains the new name-value pair, as well as any others you have previously<br />
added.<br />
12. To remove a CSS name-value pair:<br />
• Click on the corresponding line in the CSS Declarations text box.<br />
• Click the Remove button to the right of the Property box.<br />
• Click OK to save your changes and return to the CSS Declaration Editor. The CSS Declarations<br />
text box no longer displays the name-value pair that you removed.<br />
13. To edit a CSS name-value pair:<br />
• Click on the corresponding line in the CSS Declarations text box.<br />
• Either type a CSS value in the Value field or click the Edit button to display the CSS Value<br />
Editor.<br />
• Use the CSS Value Editor to choose and enter values as in step 11.<br />
456 <strong>Using</strong> <strong>Zen</strong>
• Click OK to save your changes and return to the CSS Declaration Editor. The CSS Declarations<br />
text box now contains the modified version of the name-value pair, as well as any others you<br />
have previously added.<br />
14. When you are satisfied with your modifications in the CSS Declaration Editor dialog, click OK.<br />
The <strong>Zen</strong> Style Wizard echoes your choices and displays a sample of the resulting style. After<br />
examining this sample you may do one of the following:<br />
• To resume changes to this style definition, return to step 10.<br />
<strong>Zen</strong> Style Wizard<br />
• To accept the result of all your changes to this style definition, click Finish. The <strong>Zen</strong> Style<br />
Wizard dialog closes and the completed style definition appears in the XData Style block of<br />
your class.<br />
<strong>Using</strong> <strong>Zen</strong> 457
Index<br />
Symbols<br />
$$$Text, 396<br />
$$$TextHTML, 396<br />
$$$TextJS, 396<br />
$DATASOURCE, 439<br />
$LOG, 441<br />
$MODE, 438<br />
&html<br />
%Attr, 348<br />
%DrawHTML, 343<br />
OnDrawCell, 82<br />
OnDrawContent<br />
expando, 281<br />
html element, 47<br />
%application, 365<br />
%Attr, 348<br />
%composite, 365<br />
%DrawHTML, 28, 343<br />
%GetEventHandlers, 348<br />
%id, 252<br />
%MakeId, 346<br />
%OnGetSubtitle, 301<br />
%OnGetTitle, 301<br />
%OnSubmit, 164<br />
%page, 366<br />
%query, 365<br />
%seriesCount, 252<br />
%seriesNames, 252<br />
%session, 365<br />
%this, 366<br />
%url, 365<br />
%val, 414<br />
%zenContext, 367<br />
A<br />
action, 175<br />
aggregate, 415<br />
AJAX, 376<br />
align<br />
components, 57<br />
line, 432<br />
table, in reports, 434<br />
altcolor, 434<br />
animate, 113<br />
APPLICATION, 364<br />
APPLICATIONNAME, 362<br />
applications, 31<br />
programming, 361<br />
security, 391<br />
wizard, 445<br />
see also %application<br />
APPLYBUTTON, 302<br />
att, 425<br />
Attr<br />
see %Attr<br />
attribute, 415<br />
autoExecute, 92<br />
AUTOLOGOUT, 364<br />
autoRefresh, 225<br />
autoValidate, 158<br />
auxColumn, 198<br />
axes, 152<br />
B<br />
backgroundStyle<br />
charts, 146<br />
radialNavigator, 123<br />
svgFrame, 105<br />
backgroundTimerInterval, 379<br />
bandLower, 146<br />
bandLowerStyle, 146<br />
bandUpper, 146<br />
bandUpperStyle, 146<br />
barChart, 131<br />
baseValue, 152<br />
block, 429<br />
body, 427<br />
bodyHeight, 84<br />
breakOnExpression, 419<br />
breakOnField, 419<br />
browsers, 4<br />
button, 174<br />
buttonCaption, 193<br />
buttonImage, 193<br />
buttonImageDown, 193<br />
buttonTitle, 194<br />
<strong>Using</strong> <strong>Zen</strong> 459
C<br />
Caché Server Pages, 25<br />
calendar, 202<br />
caption<br />
button, 174<br />
checkbox, 179<br />
datatype, and localization, 400<br />
expando, 282<br />
links, 264<br />
locatorLink, 266<br />
menus, 269<br />
radialNode, 124<br />
radioButton, 184<br />
reports, 435<br />
submit, 175<br />
tab, 279<br />
tablePane, 84<br />
captionClass, 179<br />
radioButton, 184<br />
radioSet, 183<br />
case-sensitivity, 22<br />
cellAlign, 51<br />
cellSize, 51<br />
cellStyle<br />
condition, 85<br />
groups, 51<br />
cellTitle, 82<br />
cellVAlign, 52<br />
chartFilled, 130<br />
chartPivot<br />
barChart, 132<br />
hilowChart, 135<br />
lineChart, 130<br />
charts, 127<br />
axis attributes, 152<br />
barChart, 131<br />
common attributes, 145<br />
diffChart, 133<br />
hilowChart, 135<br />
lineChart, 129<br />
ongetData, 143<br />
pieChart, 138<br />
reports, 436<br />
wizard, 450<br />
xAxis, 152<br />
xyChart, 136<br />
yAxis, 152<br />
chartStacked<br />
barChart, 132<br />
lineChart, 130<br />
checkbox, 178<br />
childIndent<br />
dynaTree, 320<br />
expando, 282<br />
choiceColumn, 198<br />
class<br />
attribute<br />
for aggregate, 416<br />
in reports, 428<br />
element, in reports, 424<br />
clearSnapshot, 88<br />
client and server, 25<br />
clientType, 170<br />
code examples, 23<br />
colExpression, 82<br />
colName<br />
column, 82<br />
condition, 85<br />
color, 432<br />
color definitions, 337<br />
colorList, 180<br />
colorPane, 311<br />
colorPicker, 180<br />
colorSelect, 300<br />
cols, 177<br />
column, 81<br />
columnHeaders, 199<br />
columnName, 214<br />
combobox, 191<br />
comboType, 194<br />
components<br />
common attributes, 57<br />
concepts, 37<br />
layout, 43<br />
security, 392<br />
wizard, 446<br />
see also SVG components<br />
composite, 328<br />
see also %composite<br />
condition, 57, 85<br />
containerStyle, 58<br />
CONTAINS, 86<br />
content, 306<br />
controlClass, 170<br />
controller<br />
see Model View Controller<br />
460 <strong>Using</strong> <strong>Zen</strong>
controllerId<br />
charts, 144<br />
data views, 226<br />
dynaGrid, 215<br />
forms, 159, 166<br />
meters, 113<br />
controls, 155<br />
button, 174<br />
calendar, 202<br />
checkbox, 178<br />
colorPicker, 180<br />
combobox, 191<br />
common attributes, 169<br />
dataCombo, 195<br />
dataListBox, 189<br />
dateText, 205<br />
dynaForm, 243<br />
dynaGrid, 207<br />
fileUpload, 179<br />
hidden, 207<br />
image, 174<br />
label, 176<br />
listBox, 188<br />
password, 177<br />
radioButton, 183<br />
radioSet, 180<br />
select, 185<br />
submit, 175<br />
text, 176<br />
textarea, 177<br />
controlStyle, 170<br />
count, 433<br />
createComponent, 288<br />
CSP, 25<br />
CSS<br />
cascade of styles, 63<br />
custom components, 334<br />
overriding styles, 65<br />
style wizard, 455<br />
cssinclude, 425<br />
CSSINCLUDES<br />
application class, 362<br />
page class, 364<br />
currCol, 312<br />
currColumn<br />
dynaGrid, 215<br />
tablePane, 97<br />
currPage<br />
dynaGrid, 215<br />
tablePane, 88<br />
currRow<br />
colorPane, 312<br />
dynaGrid, 215<br />
currSlice, 312<br />
currTab, 275<br />
D<br />
dashboards, 101<br />
dataBinding<br />
controls, 170<br />
data views, 226<br />
meters, 113<br />
dataCombo, 195<br />
dataController, 222<br />
dataFields, 436<br />
dataGlobal, 320<br />
dataGroup, 436<br />
dataListBox, 189<br />
dataSource, 73<br />
DATASOURCE, 411<br />
see also $DATASOURCE<br />
dateText, 205<br />
dayList, 203<br />
defaultGroupId, 166<br />
DEFAULTMODE, 411<br />
defaultSeries, 223<br />
defs, 336<br />
delay, 194<br />
demo applications, 7<br />
dialog windows, 299<br />
dictionary, message, 396<br />
diffChart, 133<br />
disabled<br />
controls, 170<br />
groups, 52<br />
links, 264<br />
menus, 269<br />
svgFrame, 105<br />
svgGroup, 109<br />
displayColumns, 199<br />
displayList<br />
combobox, 192<br />
radioSet, 181<br />
select, 186<br />
document, 424<br />
DOMAIN<br />
and dialogs, 302<br />
<strong>Using</strong> <strong>Zen</strong> 461
and localization, 400<br />
page class parameter, 364<br />
dragCanvas, 105<br />
DrawHTML<br />
see %DrawHTML<br />
dropdownHeight, 194<br />
dropdownWidth, 194<br />
dynaForm, 166<br />
control labels, 241<br />
control selection, 243<br />
dynaGrid, 207<br />
DYNAMICPROPERTIES, 253<br />
dynaTree, 316<br />
dynaView, 322<br />
E<br />
editable, 194<br />
editMode, 105<br />
element<br />
in reports, 414<br />
on pages<br />
layout, 43<br />
wizard, 452<br />
emptyCaption, 183<br />
enclosingClass, 58<br />
enctype, 159<br />
endYear, 203<br />
EQ, 86<br />
escape, 298<br />
events<br />
%GetEventHandlers, 348<br />
charts<br />
get chart labels, 147<br />
update chart, 143<br />
user clicks, 151<br />
colorPane, 313<br />
controls, 171<br />
dataController, 224<br />
dynaGrid, 216<br />
dynaTree, 321<br />
dynaView, 324<br />
eventHandler, 341<br />
expando, 283<br />
forms, 159<br />
link, 264<br />
lookoutMenu, 278<br />
menus<br />
submenus, 271<br />
user clicks, 270<br />
meters, 114<br />
modalGroup, 297<br />
ownerDraw, 125<br />
radialNavigator, 123<br />
radialNode, 124<br />
SVG components, 110<br />
svgFrame, 106<br />
tablePane<br />
row and column selection, 96<br />
user key clicks, 95<br />
tabs, 275<br />
timer, 309<br />
zenEvent, 367<br />
examples, 23<br />
expandable, 277<br />
expanded<br />
expando, 282<br />
lookoutMenu, 278<br />
expando, 279<br />
expression, 415<br />
runtime, 368<br />
EXTEQ, 86<br />
extraColumnWidth, 84<br />
F<br />
face, 312<br />
field attribute<br />
for element, 415<br />
for item, 431<br />
fieldSet, 309<br />
fileSelect, 300<br />
fileUpload, 179<br />
filterEnum, 90<br />
filterEnumDisplay, 90<br />
filterLabel, 90<br />
filterOp, 91<br />
filterQuery, 91<br />
filtersDisabled, 92<br />
filterTitle, 91<br />
filterType, 91<br />
filterValue, 91<br />
findElement, 347<br />
findSVGElement, 347<br />
firstDayOfWeek, 203<br />
fixedHeaders, 84<br />
462 <strong>Using</strong> <strong>Zen</strong>
fixedMonth, 203<br />
fo, 437<br />
footer, 430<br />
footerHeight<br />
document, 424<br />
formatNumber, 431<br />
forms, 155<br />
common attributes, 158<br />
controls, 169<br />
dynamic, 166<br />
Model View Controller, 228<br />
submit, 164<br />
validation, 162<br />
frameAlign, 307<br />
frameBorder, 307<br />
frameStyle, 105<br />
fuelGauge, 115<br />
G<br />
gapWidth, 203<br />
getComponentById, 286<br />
getDialogValue, 301<br />
GetEventHandlers<br />
see %GetEventHandlers<br />
getRowData, 88<br />
graphics<br />
dynamic, using SVG, 101<br />
static images<br />
clickable, 174<br />
display-only, 307<br />
gridLabel, 215<br />
gridStyle, 147<br />
gridX, 105<br />
gridY, 106<br />
groupByClause, 74<br />
groupClass, 52<br />
groups<br />
in reports<br />
list, 433<br />
table, 434<br />
XData ReportDefinition, 418<br />
XData ReportDisplay, 429<br />
on pages<br />
common attributes, 50<br />
dialog windows, 299<br />
dynaForm, 166<br />
expando, 279<br />
fieldSet, 309<br />
form, 158<br />
forms, 155<br />
hgroup, 48<br />
layout, 48<br />
menus, 267<br />
modal groups, 285<br />
page, 45<br />
pane, 54<br />
repeatingGroup, 313<br />
svgGroup, 109<br />
tabs, 271<br />
vgroup, 49<br />
groupStyle, 52<br />
groupTitle, 297<br />
GT, 86<br />
GTEQ, 87<br />
H<br />
header, 82, 430<br />
headerHeight<br />
document, 424<br />
headerLayout, 93<br />
height<br />
components, 58<br />
document, 424<br />
gridRow, 212<br />
img, 431<br />
SVG components, 110<br />
help<br />
menus, 269<br />
hgroup, 48<br />
see also groups<br />
hidden, 207<br />
column, 82<br />
components, 58<br />
gridColumn, 214<br />
gridRow, 212<br />
SVG components, 110<br />
highLampColor<br />
fuelGauge, 116<br />
lightBar, 118<br />
speedometer, 120<br />
<strong>Using</strong> <strong>Zen</strong> 463
highStyle, 117<br />
hilowChart, 135<br />
hmenu, 270<br />
HOMEPAGE, 362<br />
horizontal, 48<br />
href<br />
cssinclude, 426<br />
link, 264<br />
locatorLink, 266<br />
xslinclude, 426<br />
HTML, 3<br />
see also &html<br />
html element<br />
for page titles, 47<br />
for static HTML content, 305<br />
in reports, 438<br />
HTMLSTYLESHEET, 412<br />
hubStyle, 123<br />
I<br />
id<br />
components, 58<br />
locatorLink, 266<br />
modelId, 224<br />
SVG components, 111<br />
see also %id<br />
iframe, 307<br />
image<br />
attribute, for list, 433<br />
element, on pages, 174<br />
menus, 269<br />
imageContracted<br />
dynaTree, 320<br />
expando, 282<br />
imageExpanded<br />
dynaTree, 320<br />
expando, 282<br />
imageHeight, 269<br />
imageWidth, 269<br />
img, 430<br />
import, 58<br />
independentOdometer, 120<br />
indicatorLamp, 116<br />
initialExecute, 73<br />
invalid, 171<br />
invalidDateMessage, 206<br />
invalidMessage<br />
controls, 171<br />
forms, 159<br />
item, 431<br />
itemCount, 191<br />
J<br />
JavaScript, 14, 375<br />
JSINCLUDES<br />
application class, 362<br />
page class, 364<br />
K<br />
key, 159<br />
L<br />
label<br />
components, 59<br />
dynaForm, 241<br />
element, in forms, 176<br />
gridColumn, 214<br />
gridRow, 212<br />
meter components, 113<br />
labelAngle, 152<br />
labelClass, 59<br />
labelPosition, 52<br />
labelStyle<br />
axes, 152<br />
charts, 147<br />
components, 59<br />
meter components, 114<br />
labelsVisible, 147<br />
labelUnits, 152<br />
labelValues, 437<br />
language, application locale and, 395<br />
lastUpdate, 99<br />
layout<br />
components, 43<br />
groups, 52<br />
svgFrame, 106<br />
svgGroup, 109<br />
table, in reports, 435<br />
see also style<br />
legend, 311<br />
legendHeight, 149<br />
legendLabelStyle, 150<br />
legendStyle, 150<br />
legendVisible, 150<br />
legendWidth, 150<br />
464 <strong>Using</strong> <strong>Zen</strong>
legendX, 150<br />
legendY, 150<br />
length, 433<br />
lightBar, 118<br />
line<br />
between groups, 429<br />
for line breaks, 432<br />
lineChart, 129<br />
lineHeight, 433<br />
link<br />
column, 93<br />
element, in navigation, 263<br />
item, 432<br />
menus, 269<br />
linkCaption, 93<br />
linkConfirm, 94<br />
linkResource, 270<br />
list, 433<br />
listBox, 188<br />
common attributes, 189<br />
listHeight, 189<br />
listWidth, 189<br />
loadingMessage, 199<br />
localization, 395<br />
locatorBar, 265<br />
locatorLink, 266<br />
LOG<br />
see $LOG<br />
logo<br />
fuelGauge, 116<br />
speedometer, 120<br />
longdesc, 307<br />
lookoutMenu, 275<br />
lowLampColor<br />
fuelGauge, 116<br />
lightBar, 118<br />
speedometer, 120<br />
lowStyle, 117<br />
LT, 87<br />
LTEQ, 87<br />
M<br />
mainLabel, 123<br />
mainLabelStyle, 123<br />
majorGridLines, 153<br />
majorGridStyle, 153<br />
majorUnits, 153<br />
makeId, 346<br />
see also %MakeId<br />
marginBottom<br />
charts, 146<br />
document, 424<br />
marginLeft<br />
charts, 146<br />
document, 424<br />
marginRight<br />
charts, 146<br />
document, 424<br />
marginTop<br />
charts, 146<br />
document, 424<br />
markerScale, 149<br />
markerShapes, 149<br />
markerStyle, 149<br />
markersVisible, 149<br />
maxDate<br />
calendar, 203<br />
dateText, 206<br />
maxlength<br />
combobox, 194<br />
fileUpload, 179<br />
password, 177<br />
text, 176<br />
maxRows<br />
radioSet, 182<br />
select, 187<br />
tables, 74<br />
maxValue, 153<br />
menu, 267<br />
menuItem, 268<br />
menuSeparator, 271<br />
message dictionary, 396<br />
meters, 112<br />
common attributes, 113<br />
custom, 353<br />
fuelGauge, 115<br />
indicatorLamp, 116<br />
lightBar, 118<br />
smiley, 119<br />
speedometer, 119<br />
trafficLight, 121<br />
method<br />
aggregate, 416<br />
conventions, 375<br />
wizard, 453<br />
<strong>Using</strong> <strong>Zen</strong> 465
minDate<br />
calendar, 204<br />
dateText, 206<br />
minorGridLines, 153<br />
minorGridStyle, 153<br />
minorUnits, 153<br />
minValue, 153<br />
modalGroup, 285<br />
MODE<br />
see $MODE<br />
modelClass, 223<br />
modelId, 224<br />
Model View Controller, 219<br />
month, 204<br />
monthList, 204<br />
multiColumn, 199<br />
multiSelect, 97<br />
MVC, 219<br />
N<br />
name<br />
att, 425<br />
components, 59<br />
CSS style class, in reports, 425<br />
element, 415<br />
group<br />
XData ReportDefinition, 419<br />
XData ReportDisplay, 430<br />
locatorLink, 266<br />
report, 423<br />
SVG components, 111<br />
naming conventions, 22<br />
navigation<br />
tables, 89, 95<br />
NEQ, 87<br />
nextPage<br />
forms, 159<br />
submit, 176<br />
nodeStyle, 123<br />
normalStyle, 117<br />
nowrap, 84<br />
O<br />
odometerValue, 120<br />
offsetX, 106<br />
offsetY, 106<br />
okCaption, 297<br />
onaction, 297<br />
onactivate, 271<br />
onblur, 171<br />
onchange<br />
colorPane, 313<br />
controls, 171<br />
dynaTree, 321<br />
dynaView, 324<br />
forms, 159<br />
onchangecell, 216<br />
onclick<br />
controls, 171<br />
dynaTree, 321<br />
dynaView, 324<br />
link, 264<br />
menus, 270<br />
radialNode, 124<br />
SVG components, 110<br />
onclickcolumn, 216<br />
onclickrow, 216<br />
oncontract<br />
expando, 283<br />
lookoutMenu, 278<br />
oncreate, 224<br />
OnCreateResultSet<br />
group, in reports, 420<br />
tablePane, 77<br />
ondblclick<br />
colorPane, 313<br />
controls, 171<br />
dynaTree, 321<br />
dynaView, 324<br />
tablePane, 97<br />
ondefault, 160<br />
ondelete, 224<br />
ondragCanvas, 106<br />
ondrawcell, 216<br />
OnDrawCell, 82<br />
OnDrawContent<br />
expando, 283<br />
html, 307<br />
OnDrawFilter, 91<br />
OnDrawItem, 191<br />
oneditcell, 216<br />
onelementClick, 151<br />
onerror, 224<br />
OnExecuteResultSet, 77<br />
onexpand<br />
expando, 283<br />
466 <strong>Using</strong> <strong>Zen</strong>
lookoutMenu, 278<br />
onfocus, 171<br />
ongetData, 143<br />
ongetLabelX, 147<br />
ongetLabelY, 147<br />
OnGetNodeInfo, 321<br />
OnGetPropertyInfo, 166<br />
OnGetQuickLinks, 266<br />
OnGetSubtitle<br />
see %OnGetSubtitle<br />
OnGetTitle<br />
see %OnGetTitle<br />
OnGetViewContents, 324<br />
onheaderClick, 97<br />
onhideGroup, 297<br />
onhideTab, 275<br />
oninvalid, 160<br />
onkeydown, 172<br />
onkeypress<br />
controls, 172<br />
tablePane, 95<br />
onkeyup, 172<br />
OnLoadForm, 160<br />
onmousedown, 172<br />
onmouseout, 172<br />
onmouseover, 172<br />
onmouseup, 172<br />
onmouseWheel, 106<br />
onmoveItem, 106<br />
onmultiselect, 97<br />
onnotifyController, 224<br />
onnotifyView<br />
charts, 144<br />
data views, 226<br />
dynaGrid, 217<br />
forms, 160, 167<br />
meters, 114<br />
onPopupAction, 299<br />
onrender, 125<br />
onrenderPlotArea, 148<br />
onreset, 160<br />
onresizeItem, 107<br />
onsave, 224<br />
onselectItem, 107<br />
onselectNode, 123<br />
onselectrow, 97<br />
onshowGroup, 297<br />
onshowHelp, 271<br />
onshowTab, 275<br />
onsubmit<br />
controls, 172<br />
forms, 161<br />
see also %OnSubmit<br />
OnSubmitForm, 160<br />
ontimeout, 309<br />
onvalidate<br />
controls, 172<br />
forms, 161<br />
onzoom, 107<br />
option<br />
combobox, 192<br />
listBox, 188<br />
optionValue, 184<br />
orderByClause, 75<br />
orient, 435<br />
originalValue, 172<br />
ownerDraw, 125<br />
P<br />
p, 434<br />
page, 31<br />
element, 45<br />
programming, 363<br />
security, 392<br />
template page, 53<br />
wizard, 447<br />
see also %page<br />
pagebreak<br />
attribute, for group, 430<br />
element, in reports, 434<br />
pagefooter, 427<br />
pageheader, 427<br />
PAGENAME, 364<br />
pageSize, 88<br />
PAGETITLE, 364<br />
pane, 54<br />
dialog window, 301<br />
see also groups<br />
panel<br />
see fieldSet<br />
paneName, 54<br />
parameters<br />
dynaTree, 318<br />
dynaView, 322<br />
queries, 80<br />
SVG page references, 108<br />
<strong>Zen</strong> application class, 362<br />
<strong>Using</strong> <strong>Zen</strong> 467
<strong>Zen</strong> component class, 329<br />
<strong>Zen</strong> datatype, 338<br />
<strong>Zen</strong> page class, 363<br />
<strong>Zen</strong> page URI, 373<br />
<strong>Zen</strong> report class, 410<br />
paramName<br />
dynaTree, 318<br />
dynaView, 323<br />
password, 177<br />
pattern, 433<br />
PDF<br />
as report output, 403<br />
configuring <strong>Zen</strong> for PDF output, 440<br />
pieChart, 138<br />
pieScale, 138<br />
plotAreaStyle, 148<br />
plotBy, 138<br />
plotStyle, 148<br />
plotToEdge, 148<br />
popup windows<br />
dialogs, 299<br />
modal groups, 285<br />
predicate, 86<br />
preserveAspectRatio, 111<br />
preserve mode, exceptions to, 27<br />
Q<br />
query<br />
dataCombo, 196<br />
list box<br />
dataListBox, 190<br />
select, 187<br />
property parameters for, 254<br />
radioSet, 182<br />
repeatingGroup, 314<br />
report, 420<br />
to define a table, 73<br />
see also %query<br />
queryClass<br />
group, in reports, 420<br />
radioSet, 182<br />
select, 187<br />
tables, 76<br />
queryName<br />
group, in reports, 420<br />
radioSet, 182<br />
select, 187<br />
tables, 76<br />
R<br />
radialNavigator, 122<br />
radialNode, 122<br />
radioButton, 183<br />
radioSet, 180<br />
rangeLower, 114<br />
rangeUpper, 114<br />
readOnly<br />
controls, 172<br />
gridColumn, 214<br />
gridRow, 213<br />
readOnlyMessage, 161<br />
READONLYMODEL, 253<br />
rect, 109<br />
refLineStyle, 134<br />
remember<br />
expando, 283<br />
tab groups, 275<br />
repeatingGroup, 313<br />
see also tables<br />
REPORTNAME, 412<br />
reports, 403<br />
common attributes, 428<br />
wizard, 448<br />
XData ReportDefinition, 413<br />
XData ReportDisplay, 421<br />
REPORTXMLNAMESPACE, 412<br />
required, 173<br />
requiredMessage, 173<br />
RESOURCE, 364<br />
rowCount, 99<br />
rowLabelWidth, 217<br />
rowName, 213<br />
rows<br />
dynaView, 324<br />
textarea, 177<br />
rowSelect, 97<br />
rowStyle, 86<br />
runtime expression, 368<br />
runtimeMode, 420<br />
rx, 110<br />
S<br />
SAMPLES, 23<br />
scaleFactor, 114<br />
scrolling, 307<br />
scrollIntoView, 194<br />
468 <strong>Using</strong> <strong>Zen</strong>
searchKeyLen, 199<br />
security<br />
<strong>Zen</strong> application, 391<br />
<strong>Zen</strong> component, 392<br />
<strong>Zen</strong> page, 392<br />
seed<br />
column, 82<br />
html, 307<br />
modalGroup, 297<br />
select, 185<br />
selectedIndex<br />
combobox, 195<br />
dynaTree, 321<br />
dynaView, 324<br />
listBox, 189<br />
radialNavigator, 123<br />
tablePane, 97<br />
selectedItem, 151<br />
selectedItemStyle, 151<br />
selectedRows, 98<br />
selectedSeries, 151<br />
seriesColors<br />
charts, 148<br />
reports, 436<br />
seriesCount<br />
charts, 142<br />
reports, 436<br />
see also %seriesCount<br />
seriesGroup, 437<br />
seriesNames<br />
charts, 148<br />
reports, 437<br />
see also %seriesNames<br />
seriesSize<br />
charts, 142<br />
reports, 437<br />
server and client, 25<br />
session<br />
see also %session<br />
show, 295<br />
showColumnLabels, 217<br />
showEmpty<br />
dataCombo, 199<br />
select, 186<br />
showFilters, 93<br />
showPercentage, 138<br />
showQuery, 77<br />
showRowLabels, 217<br />
showRowNumbers, 84<br />
showRowSelector, 98<br />
showTabBar, 275<br />
showTime<br />
calendar, 204<br />
dateText, 206<br />
showValueInTooltip, 84<br />
showZebra, 85<br />
size<br />
combobox, 195<br />
dateText, 207<br />
fileUpload, 179<br />
password, 177<br />
select, 187<br />
text, 176<br />
slice, 59<br />
smiley, 119<br />
snapshot mode, for tables, 87<br />
snapToGrid, 107<br />
sortOrder, 96<br />
spacer, 49<br />
special, 432<br />
speedometer, 119<br />
sql<br />
group, in reports, 420<br />
radioSet, 182<br />
select, 187<br />
tables, 74<br />
sqlLookup<br />
dataCombo, 200<br />
dataListBox, 191<br />
src<br />
iframe, 308<br />
image, 175<br />
img, 431<br />
srcDisabled, 175<br />
STARTSWITH, 87<br />
startvalue, 433<br />
startYear, 204, 205<br />
streamId, 175<br />
Studio, 7<br />
<strong>Using</strong> <strong>Zen</strong> 469
style<br />
attribute<br />
column, 83<br />
gridColumn, 214<br />
gridRow, 213<br />
in reports, 423, 428<br />
link, 264<br />
option element, in combobox, 193<br />
option element, in listBox, 189<br />
radialNode, 124<br />
rect, 110<br />
components, 57<br />
element<br />
XData Style, 66, 334<br />
XData SVGStyle, 336<br />
inheritance, 62<br />
wizard, 455<br />
see also layout<br />
submit, 175<br />
see also %OnSubmit<br />
subtitle<br />
dialog windows, 301<br />
titleBox, 46<br />
summary, 435<br />
svgAutoSize, 107<br />
SVG components, 101<br />
common attributes, 110<br />
custom style, 336<br />
svgFrame, 102<br />
svgGroup, 109<br />
svgHeight, 107<br />
svgPage, 108<br />
svgSpacer, 109<br />
svgWidth, 108<br />
T<br />
tab, 278<br />
tabGroup, 272<br />
tableName, 75<br />
tableNavigator, 95<br />
tableNavigatorBar, 95<br />
tablePaneId, 95<br />
tables<br />
in reports, 434<br />
on pages, 72<br />
see also repeatingGroup<br />
tabResource, 279<br />
targetCol, 86<br />
template page, 53<br />
text<br />
element, 176<br />
language localization, 395<br />
listBox, 189<br />
option element<br />
combobox, 193<br />
listBox, 189<br />
see also $$$Text<br />
see also $$$TextHTML<br />
see also $$$TextJS<br />
textarea, 177<br />
thickness, 433<br />
this, 366<br />
see also %this<br />
thresholdLower, 114<br />
thresholdUpper, 114<br />
timeCaption, 205<br />
timeout, 309<br />
timer, 308<br />
title<br />
axes, 153<br />
charts, 150<br />
column, 83<br />
components, 59<br />
dialog windows, 301<br />
fieldSet, 311<br />
gridColumn, 214<br />
gridRow, 213<br />
links, 265<br />
locatorLink, 266<br />
page, 45<br />
radialNavigator, 124<br />
report, 423<br />
titleBox, 46<br />
titleBox, 46<br />
titleList, 183<br />
titlePane, 46<br />
titleStyle<br />
charts, 150<br />
radialNavigator, 124<br />
titleBox, 46<br />
titleX, 150<br />
titleY, 150<br />
trafficLight, 121<br />
translation, 395<br />
type<br />
aggregate, 416<br />
list, 433<br />
470 <strong>Using</strong> <strong>Zen</strong>
U<br />
style, 334<br />
style element, 66<br />
unrestricted, 195<br />
url<br />
see %url<br />
useKeys, 96<br />
USERPACKAGES, 364<br />
application class, 362<br />
USERSVGPACKAGES, 364<br />
application class, 362<br />
useSnapshot, 88<br />
V<br />
val<br />
see %val<br />
valign, 59<br />
value<br />
att, 425<br />
colorPane, 313<br />
condition, 86<br />
controls, 173<br />
dialog windows<br />
retrieving, 299<br />
returning, 301<br />
item, 432<br />
meters, 115<br />
modal groups, 290<br />
option element<br />
combobox, 193<br />
listBox, 189<br />
parameter element<br />
dynaTree, 318<br />
dynaView, 323<br />
SVG page references, 108<br />
table queries, 80<br />
radialNode, 124<br />
tablePane, 98<br />
valueColumn<br />
dataCombo, 200<br />
tablePane, 98<br />
valueList<br />
combobox, 192<br />
radioSet, 181<br />
select, 186<br />
vertical, 48<br />
vgroup, 49<br />
see also groups<br />
view<br />
see Model View Controller<br />
viewBoxHeight, 111<br />
viewBoxWidth, 111<br />
viewType, 324<br />
vmenu, 270<br />
W<br />
whereClause, 75<br />
width<br />
attribute, in reports, 428<br />
column, 83<br />
components, 59<br />
document, 424<br />
gridColumn, 214<br />
img, 431<br />
SVG components, 111<br />
wizards, 7, 445<br />
write, 438<br />
WRITE<br />
%Attr, 348<br />
%DrawHTML, 343<br />
OnDrawCell, 82<br />
OnDrawContent<br />
expando, 281<br />
html element, 47<br />
X<br />
x, 111<br />
xAxis, 152<br />
XData Contents, 44<br />
XData dialogBody, 301<br />
XData for panes, 54<br />
XData ReportDefinition, 413<br />
XData ReportDisplay, 421<br />
XData Style, 61<br />
XData SVGDef, 336<br />
XData SVGStyle, 336<br />
XHTML, 403<br />
XMLNamespace, 12<br />
xmlns, 45<br />
XSL-FO, 403<br />
XSLFOSTYLESHEET, 412<br />
xslinclude, 426<br />
XSLT, 403<br />
<strong>Using</strong> <strong>Zen</strong> 471
xyChart, 136<br />
Y<br />
y, 111<br />
yAxis, 152<br />
Z<br />
ZENATTRS, 253<br />
zenContext<br />
see %zenContext<br />
ZENCONTROL, 253<br />
ZENDISPLAYCOLUMN, 253<br />
ZENENCRYPT, 338<br />
zenEvent, 367<br />
ZENEXPRESSION, 339<br />
ZENGROUP, 254<br />
ZENHIDDEN, 254<br />
ZENLABEL<br />
and data models, 241<br />
datatype parameter, 254<br />
zenLaunchPopupWindow<br />
colorSelect, 301<br />
fileSelect, 300<br />
popup windows, 298<br />
utility function, 373<br />
zenLink<br />
popup windows, 298<br />
utility function, 373<br />
ZENLOCALIZE<br />
and localization, 400<br />
datatype parameter, 339<br />
<strong>Zen</strong>Method, 375<br />
zenPage, 366<br />
ZENREADONLY, 254<br />
ZENSETTING, 339<br />
ZENSIZE, 254<br />
ZENSQL, 254<br />
ZENSQLLOOKUP, 254<br />
zenSynchronousMode, 373<br />
ZENTAB, 254<br />
zenThis, 366<br />
ZENTITLE, 254<br />
ZENURL, 373<br />
zoom, 108<br />
zoomLevels, 108<br />
zoomWithWheel, 108<br />
472 <strong>Using</strong> <strong>Zen</strong>