BUI logoDWC logoCSS API

Introduction

Cascading Style Sheets (CSS) is one of the primary languages used in modern AJAX web applications, along with HTML and JavaScript. Together, these three languages provide a “separation of concerns” that allows programmers, content authors, and UI designers to collaborate on web content while allowing each of these groups to focus on their primary strengths.

While HTML provides authors with the ability to write structured content and JavaScript allows programmers to respond to user input, CSS is perhaps the most visible aspect of a web application. Proper application of CSS can help transform a web page into an eye-popping user experience. An extreme example of this can be found at www.csszengarden.com. This site serves a single HTML page, and graphic designers use CSS to apply different styles to the original content to give it a completely different look. For example, compare the original HTML page with this styled page or another styled page. The differences are striking, and it goes a long way to show the power of CSS to provide a unique look to a web page.

In order to use CSS, the HTML of a page has to be predictable and well-documented. The analogy is a content author who provides a well-structured document to the UI designer. The UI designer can begin adding styles and transforming a bunch of text into a usable, beautiful application. With a BUI application, the content author is actually a mixture of BBjServices and a BBj program. BBjServices generates the HTML of a BUI application based on the operations a program executes on the SYSGUI device. The BUI CSS API provides server-based tools to allow a UI designer to apply a stylesheet to the web page of a BUI application, well-defined CSS selectors to apply styles to general and specific elements, and the ability to change between different states at runtime to allow dynamic effects in response to user actions or program changes.

The rest of this document will describe the BASIS tools used to bring this kind of styling to your BUI application.

 Click here to see dozens of BUI demos and their source code.

Server

Before getting into the details about what CSS to write, we must begin by showing how to get our CSS styles to the client. There are several ways to accomplish this. Let’s begin with a small CSS page:

example.css:

.BBjButton {
	background-color: red;
	background-image: none;
}

.fancy {
	background-color: lightGrey;
	-moz-border-radius: 15px;
	border-radius: 15px;
}

Enterprise Manager

The easiest way to add a CSS file to a BUI application is through the Enterprise Manager interface. First, add a resource on the BUI Configuration - Resources tab:

Then, use the CSS field on the Applications tab to choose the stylesheet:

Be sure to click the [Save] button at the top of the screen to apply your changes to the server.

BBjAPI

The BBjAPI has access to the BBjAppServer object. This object allows making changes to a number of BUI settings, in addition to adding stylesheets. Here is an example of how to perform the same steps as above with the BBjAppServer API:

admin$ = "admin"
adminPwd$ = "admin123"

REM ' Get the BBjAdmin object and the BBjAppServer object
bbjAdmin! = bbjapi().getAdmin(admin$, adminPwd$)
bbjAppServer! = bbjAdmin!.getWebAppServer()

REM ' Get a BBjResourceURL for the style sheet
resourceUrl! = bbjAppServer!.addStyleSheet("/usr/local/bbj/css/example.css")

REM ' Get the currently published application. This can only be used for information
REM ' purposes, and must be copied to a new configuration before editing
app! = bbjAppServer!.getApplication("test")
appCfg! = app!.toAppConfig()
appCfg!.setStyleSheet(resourceUrl!)
newApp! = appCfg!.buildApplication("test")

REM ' Now we unpublish the old application, and publish the new one with the stylesheet:
bbjAppServer!.unpublish(app!.getName())
bbjAppServer!.publish(newApp!)

AdminAPI

The same thing can be accomplished through the Java-based Admin API.

admin$ = "admin"
adminPwd$ = "admin123"

USE com.basis.api.admin.BBjAdminFactory
USE com.basis.api.admin.BBjAdminWebApplication
REM ' Get the BBjAdminBase object and the BBjAdminWebAppServer object
bbjAdmin! = com.basis.api.admin.BBjAdminFactory.getBBjAdmin(admin$, adminPwd$)
bbjAppServer! = bbjAdmin!.getWebAppServer()

REM ' Get a BBjAdminResourceUrl for the style sheet. Here, we specify the MIME type
resourceUrl! = bbjAppServer!.addResource("/usr/local/bbj/css/example.css", "text/css")

REM ' This gets a mutable copy of the application configuration. Set the style sheet
REM ' on this copy
app! = bbjAppServer!.getApplication("test")
app!.setStyleSheet(resourceUrl!)

REM ' Now, unpublish the old one, and publish the new one.
bbjAppServer!.unpublish(app!.getString(BBjAdminWebApplication.NAME))
bbjAppServer!.publish(app!)

Client

Now that the application refers to the stylesheet, the contents of the stylesheet can affect the appearance of the controls in the application.

Syntax Introduction

CSS is a simple language. It consists mainly of two different components: selectors and style properties. The style properties are what affect the appearance of HTML elements. There are many different well-defined properties. Some of them are browser-specific, and some of them are not supported on all browsers. Style properties look like the following:

property: value;

An example of this would be the 'color' property, which affects the color of the text of a control:

color: lightGrey;

The available style properties and their values is well beyond the scope of this document, but there are many resources available on the web. The CSS Specifications CSS2.1 and the CSS3Modules are the canonical sources for CSS information.

Selectors make it possible to apply a group of style properties to a particular element in the HTML document. There are two types of selectors: simple selectors and "compound selectors" (referred to in the CSS specification simply as "selectors"). The simple selector most important for BBj controls is the HTML-specific "class selector", which looks like the emphasized text in the following CSS rule set:

.className {

  property1: value1;

  property2: value2;

}

BBj ensures the document contains proper markup so that class selectors uniquely identify many aspects of the familiar GUI controls of a BBj application. This markup can describe either the identity of a GUI control or its state.

Control Names

The name of a control is the easiest way to apply styles to a specific control. Many applications already use the NAME attribute in an ARC file to name controls. This value is propagated to the class attribute of the HTML element representing each control. A program can also set the name of the control programmatically:

ctrl! = ...

REM ' Add the custom class name "CustName" to the HTML element representing ctrl!

ctrl!.setName("CustName")

Styling can be done by simply using a class selector:

.CustName {

  background:lightGrey;

}

Any whitespace in the control name is collapsed to a single space, and each individual word in the name value can be used as a class name. For example, if the name of the control is "Customer Name", the class attribute will contain "Customer Name", which can be selected using:

.Customer.Name {

  background:lightGrey;

}

Control Styles

BBj also includes several new methods to control style names: BBjControl::addStyle() and BBjControl::removeStyle(), along with BBjControl::getStyles() and BBjControl::clearStyles().

Consider the following code snippet and the accompanying CSS snippet below:

REM ' Add two style names, "fancy" and "schmancy", to the class

REM ' attribute of ctrl!'s HTML element

ctrl!.addStyle("fancy")

ctrl!.addStyle("schmancy")

 

REM ' Removes "schmancy" from the class attribute of ctrl!'s HTML element

ctrl!.removeStyle("schmancy")

 

REM ' Removes all styles from the class attribute of ctrl!'s HTML element

ctrl!.clearStyles()

 

/** CSS **/

.fancy {

  background: lightGrey;

}

.schmancy {

  color: Chartreuse;

}

The CSS rules defined for the class names "fancy" and "schmancy" will combine to apply their different style rule sets to the HTML element. Initially, the control's background and text color will use the defaults for that control type. The following describes what happens through the program's progression.

  1. After the two calls to addStyle(), the control's background will be light grey and its text color will be chartreuse.

  2. After the call to removeStyle(), the control's background will remain light grey, but its text color will change back to the default.

  3. Finally, the call to clearStyles() will remove all style names from the HTML element's class attribute that were previously added with addStyle().

It's important to note that any modifications to the class attribute due to setName() are independent from modifications due to addStyle() or removeStyle(). For example, in each of the following snippets of code, the HTML for ctrl! will still include the string "style1" in its class attribute:

 

ctrl!.setName("style1")

ctrl!.removeStyle("style1")

 

ctrl!.addStyle("style1")

ctrl!.setName("style2")

 

ctrl!.addStyle("style1")

ctrl!.setName("style1")

ctrl!.removeStyle("style1")

 

ctrl!.setName("style1")

ctrl!.addStyle("style1")

ctrl!.setName("")

Control Types

Each control also specifies a name based on its BBj Object name. For instance, a BBjButton has the class name "BBjButton". By using the BBj Object name, developers can style the defaults for all instances of a given control type. All controls also have the class name "BBjControl". This allows for styling to apply to a wide range of controls.

Certain types of controls have more fine-grained features. Considerable effort has been made to expose these individual components of a control to make it possible to select them for styling independently. For example, the BBjNavigator control is a control with four buttons and a text field. Using a selector such as .BBjNavigator would allow the stylesheet to add rules to the overall control, but does not give access to the individual buttons. Those are instead provided by using the component selectors:

 

Selector

Component

.BBjNavigator-first

The "first record" button

.BBjNavigator-previous

The "previous record" button

.BBjNavigator-label

The label containing the bound field contents.

.BBjNavigator-next

The "next record" button

.BBjNavigator-last

The "last record" button

The extra class attributes give developers more flexibility over the overall look and feel of the standard BUI look to brand or personalize an application. See BUI CSS Component Styles for details about the component selectors.

Control State

BBj 11.00 ships with three general states, and a number of specific states. It is expected that over time, this set of published states will grow to accommodate other use-cases. Most of the published and future states can already be identified using other selectors, but BBj provides a consistent API to simplify styling for BBj developers. The list of selectors that are supported as of BBj 11.00 are listed below:

 

Selector

Control

Control State

.bbj-disabled

<all>

setEnabled(0)

.bbj-readonly

<all editable>

setEditable(0)

.bbj-transparent

BBjButton, BBjToolButton

setOpaque(0)

.bbj-checked

BBjRadioButton, BBjCheckBox, BBjCheckableMenuItem

setSelected(1)

.bbj-bordered

BBjCEdit, BBjMenuButton

setBorderPainted(1)

.bbj-vertical

BBjSlider

addVerticalSlider(...)

.bbj-horizontal

BBjSlider

addHorizontalSlider(...)

.bbj-default

BBjButton

Control ID = 1

.bbj-password

BBjEditBox

Control Flag $0400$

.bbj-directories

BBjFileChooser

Control Flag $0008$

.bbj-server

BBjFileChooser

Not Control Flag $0040$

.bbj-client

BBjFileChooser

Control Flag $0040$

.bbj-selected

BBjFileChooser, BBjGrid, BBjTree

Selected item (file, cell item)

Reserved Styles

Any class name beginning with "basis-" is reserved for internal use. Use of selectors that refer to ".basis-xxx" is done at the developer's own risk. The names of these selectors may change or disappear at any time.

Miscellany

Cascade Order

The CSS cascade order defines the importance of rules declared in CSS files. Since our selectors are defined as class names, the precedence rule is very simple:  The more class names a selector has, the more precedence it has. For ties, precedence goes to a rule set declared later in the CSS file.

Best Practices

When defining defaults for controls, use one class name in the selector, e.g., .BBjButton. This allows control customization to always override the defaults.

When styling specific controls, the easiest way to avoid issues with precedence rules is to always use two classes when forming a selector rule. Precedence is then defined completely by the order of two rule sets in the CSS file. One way to do this is to define what is being styled and why it's being styled. For instance, to style disabled BBjButtons, the answer to the question "What is being styled?" is BBjButton, and the answer to the question "Why is it being styled?" is because it's disabled. In this case, use the selector .BBjButton.bbj-disabled. To style a control with a custom name, "what" could be the generic BBjControl and "why" could be "because it needs custom styling defined by 'myCustomName'". In this case, use the generic selector .BBjControl.myCustomName.

To change the look of an entire window, you can use the "descendant selector" syntax, which allows specifying selectors on an HTML element contained within another HTML element by separating them with a space. For instance, to cause controls to have a red outline or a green outline and to be able to change it at runtime, one could add the following rule, where the space is highlighted in yellow:

.BBjWindow.green   .BBjControl {

  outline: 3px solid green;

  outline: 3px solid rgba(0, 255, 0, 0.5);

}

.BBjWindow.red   .BBjControl {

  outline: 3px solid red;

  outline: 3px solid rgba(255, 0, 0, 0.5);

}

What to Avoid

In some cases, BBj controls have created style rules that use more than two selectors, or add styles to the style attribute of the HTML elements. Generally speaking, these style rules are important for correct operation of the control, and should not be overridden.

Avoid using the 'top', 'left', 'right', 'bottom', 'width', 'height', 'position', 'display', 'float' and other similar positioning/sizing CSS properties. These can affect BBj's assumptions about the locations of components, which are often used to calculate widths and heights for BBj programs.

Known Issues

  • The bbj-state control state class names do not always have consistent default style properties when applied to different controls.

  • Changes to a stylesheet associated with a particular application do not immediately appear. To cause changes to propagate to subsequent application launches, use the following program:

 

REM ' Replace "myapp" with your application name, and admin/password with the

REM ' appropriate values.

appName$ = "myapp"

adminUser$ = "admin"

adminPass$ = "password"

 

appServer! = bbjapi().getAdmin(adminUser$, adminPass$).getWebAppServer()

app! = appServer!.getApplication(appName$)

cfg! = app!.toAppConfig()

styleSheetUrl! = cfg!.getStyleSheet()

 

REM ' Set the name to be the same as the existing name

styleSheetUrl!.setSourceFileName(styleSheetUrl!.getSourceFileName())

  • Default background colors in editable controls are currently specified in the style attribute. To override, stylesheet rules will require the CSS '!important' modifier. Here is an example stylesheet:

 

.BBjEditBox {

  background-color: red !important;

}

Other uses of the !important modifier are strongly discouraged. Using it can override styles that will adversely affect the functionality of a BUI program.

See Also

BBj BUI: Getting Started

BUI CSS Component Styles

BUI CSS Component Styles - Examples and Details