Archive | Bootstrap RSS for this section

XPages Tip: Adding a Bootstrap Class to All Labels via the Theme (Redux)

In this post, I showed how to set all labels in an application to include a class to pick up Bootstrap styling so it could be applied application-wide and not require touching every label control individually. However, there’s a quirk with label rendering that may make it not apply universally as desired. In this post, I’ll explain the issue and how to use another theme setting to easily fix it.

Updating all Labels via the Theme

This code in the theme will apply the control-label class to all label components in the application. This allows me to apply a Bootstrap style class to all labels without having to update each label control individually on every XPage and custom control.

<control>
  <name>Text.Label</name>
  <property mode="concat">
    <name>styleClass</name>
    <value>control-label</value>
  </property>
</control>

The Bootstrap styling will be applied to label tags that have the control-label class.

The Problem with Label Rendering

However, there’s an issue with the way labels are rendered that may not make it work consistently.

Any labels that do not have a for attribute specified will actually be rendered as span tags and the styling will not be picked up. (Labels that have the for attribute specified will be rendered as label tags and work as expected.)

In another post, I described the effects of different modes on theme property application. In this post, we’ll see a practical example of the effects.

Theme to the Rescue (Again)

Fortunately, there’s an easy way to add another property setting to the theme to handle this.

There isn’t a tagName attribute on a label, so you can’t directly modify the output tag this way, but for is a property of the control, so you can use the theme to add it to all labels.

1. Overriding the Property

One option is to override the for property on all labels. Lines 7-10 were added below to do so.

<control>
  <name>Text.Label</name>
  <property mode="concat">
    <name>styleClass</name>
    <value>control-label</value>
  </property>
  <property mode="override">
    <name>for</name>
    <value>dummyTarget</value>
  </property>	
</control>

This puts the for property in place and assumes it needs to figure out the client-side ID of the element that’s been specified. This is a dummy value, but it does the job.

<label id="view:_id1:_id3:_id51:office_Label1" class="control-label" for="view:_id1:_id3:_id51:dummyTarget">Office</label>

However, it does the job too ambitiously. It removes any existing for property, so it would break the association with the specified input control, which may cause other issues with the application and most certainly would cause issues with a screen reader.

2. Concatenating the Value

Changing line 7 to concatenate instead of overriding the value gives us a bit better behavior.

<property mode="concat">

This mode will append the property value to any value that currently exists for the attribute. It will also add the attribute and value if it doesn’t exist.

<label id="view:_id1:_id3:_id51:label17" class="control-label" for="view:_id1:_id3:_id51:dummyTarget">Payment #</label>

This also does the job, but it causes two values to be in the for property if one already existed (although it doesn’t try to generate a client-side ID when it’s appended).

<label id="view:_id1:_id3:_id51:office_Label1" class="control-label" for="view:_id1:_id3:_id51:office1 dummyTarget">Office</label>

This is better than the override method, but still may cause problems.

3. Mode not specified

You can also just not specify the mode.

<property>

In this case it only adds the property and value if the property doesn’t already exist, so it’s the cleanest solution.

This is an example of a label that already had the for attribute specified. It does not get the new dummy value.

<label id="view:_id1:_id3:_id51:office_Label1" class="control-label" for="view:_id1:_id3:_id51:office1">Office</label>

This is an example of a label that did not have the for attribute specified:

<label id="view:_id1:_id3:_id51:requisitionLabel" class="control-label" for="view:_id1:_id3:_id51:dummyTarget">Requisition #</label>
Advertisements

XPages Tip: Displaying Bootstrap Applications Properly on Mobile Devices

Do you have a Bootstrap navigation menu in XPages that collapses properly in a full browser but not on a mobile device? You may need to set a meta tag to force it to display properly. In this post, I’ll show the effects with and without the tag on a mobile device.

Navbar Collapsing

One of the great features of Bootstrap is its built-in responsive UI that scales well to work on screens of varying sizes. The navigation bars collapse nicely into the hamburger menus to make better use of available space on smaller devices.

However, in recent testing of an XPages application with a Bootstrap UI, it was noted that the navigation menus did not collapse properly when viewed on a phone. It was a little confusing because it collapsed as expected on a full browser.

When the navigation bar is set up properly, it should collapse properly on its own when the screen width is below 768 px. I verified that there are no CSS rules overruling that cutoff and that 768px is, in fact, the point where the menu collapses on the full browser.

Bootstrap Navbar Test Page

To test it out, I tried out the Bootstrap Navbar test page

On my laptop with a full browser, it showed the navigation normally.

Nav Collapse 1A - Full Browser Over 768px

When I shrunk the screen to be less than 768px wide, it collapsed the navigation properly.

Nav Collapse 1B - Full Browser Under 768px

When I checked it on my phone, it was collapsed properly.

Nav Collapse 1C - Phone - Collapsed

Test Page in XPages

I copied the div that contains the navigation from that test page and pasted into an XPage in my application to see how it worked.

It collapsed as expected in a full browser but not on the phone.

Nav Collapse 2A - Phone - NOT Collapsed in XPages

It is also apparent that the page has been scaled so that it fits fully on the phone.

To verify this, I put a button on the page to tell me the screen width. As expected, it showed a width > 768 px, which is why it did not collapse the menus. It scaled the entire page to fit on the screen, so it did not fall below the threshold of the responsive design media queries.

Nav Collapse 2B - Phone - Screen Width

(This is on a Samsung Galaxy. An iPhone showed it to be roughly 900px.)

And this is just a simple page. Imagine how that looks with a much bigger XPage!

The Difference

Ultimately, the main difference is that the Bootstrap test page contains a meta tag to make sure the device doesn’t shrink to fit the entire page on the screen.

<meta name="viewport" content="width=device-width, initial-scale=1">

In XPages, this can be set at the page level, but it’s easiest to do it application-wide via a theme, within a resources tag.

<resources>
  <metaData>
    <name>viewport</name>
    <content>width=device-width, initial-scale=1.0</content>
  </metaData> 
</resources>

Now, when I reload the Bootstrap test page, it is displayed properly on the phone.

Nav Collapse 3 - Phone - Collapsed in XPages

The button showing the screen with on the phone now shows it to be 360px wide.

Fixing the Width of a Select 2 with a Long Value in a Bootstrap Form Group or Input Group

If you have a Select2 control within a form-group or input-group div in a Bootstrap UI, a long value can cause the Select2 to grow to become wider than its container. In this post, I’ll show how to fix the issue.

The Problem with Large Values

In this demo, I have a form with two columns of fields, each within a well (which makes the container size very clear).

Select2 Long Values - A

In one field, there is a very long value. This usually isn’t an issue when you have explicit control over the options, but if you have an application where a drop-down box’s choices come from a plain text field on other documents, it’s possible.

Select2 Long Values - B

When I select the long value, it limits the amount of text displayed in the box to what will fit on one line, but it expands the size of the Select2 outside of its container.

Select2 Long Values - C

If I remove the second column of fields and re-test, it looks like the Select2 was enlarged to be the same the size as the parent container, which is too big for the area that it’s supposed to be in.

Select2 Long Values - C2

Fixing with CSS

This is a known issue with Select2 inside of a form-group or input-group within Bootstrap.

Fortunately, there’s a simple CSS fix, adapted from this post on github

.form-group .select2-container {
  position: relative;
  z-index: 2;
  float: left;
  width: 100%;
  margin-bottom: 0;
  display: table;
  table-layout: fixed;
}

If you’re using an input-group instead of a form-group, then change the first line to this:

.input-group .select2-container {

Select2 Long Values - D

Updating Select2 Styling to Match Bootstrap Fields

Select2 is an awesome jQuery plugin to enhance the functionality of combo boxes. But if you implement it in an application with a Bootstrap UI, you’ll notice that the styling is not consistent. In this post, I’ll show how to make the styling of Select2 fields consistent with other fields on the form.

Bootstrap Default Styling

Here’s an example of a simple Bootstrap form, including two combo box fields. The styling is very consistent across all of the fields.

Select2 A - Default Drop-Down

Select2 Default Styling

Once I implement Select2 and add the code to initialize combo boxes as Select2 fields, they styling changes. The width and internal padding and line spacing are not consistent with other bootstrap fields. (Click image to enlarge in order to see the difference more clearly.)

Select2 B - Default Select2 Style

Consistent Styling

Fortunately, by inspecting a standard bootstrap field either in the bootstrap CSS or in the browser’s developer tools, I can see the styles in use and replicate them for a more consistent look.

Select2 C - Consistent Select2 Style

Here is the CSS required to make it happen:

.select2-container {
  width:100%;	
}

.select2-container a.select2-choice {
  font-size: 14px;
  height: 38px;
  padding: 8px 12px;
  line-height: 1.42857;
}

.select2-container .select2-choice .select2-arrow {
  padding-top:6px;
}

The first rule makes the field width use 100% of the size of its container, as bootstrap fields do.

The second set of rules sets the font and field styling to make them consistent.

The third rule vertically centers the drop-down arrow for the larger field.

Fixing an Issue with Glyphicons with a Bootswatch Theme in XPages

In this post, I’ll describe an issue that I had with glyphicons when using a Bootswatch theme in XPages and how to fix it.

When you use a Bootswatch theme, you do not need to separately include the original
bootstrap.css file. In fact, it would be inefficient to do so, because the styling is provided by the Bootswatch CSS file.

When adding any additional Javascript libraries or CSS to an XPages application, I generally put them in their own folder under WebContent and then include the library or stylesheet via the application theme.

WebContent

However, I noticed an issue when doing this recently. The Bootswatch theme styling loaded fine, but glyphicons on the page were
not displayed properly; the unrecognized font character symbol was displayed instead.

Glyphicons are loaded as a font (much like Font Awesome), so I looked through the stylesheet to see how the font was included. As you can see, the reference is relative to the current directory, assuming a standard Bootstrap directory structure.

@font-face {
  font-family: 'Glyphicons Halflings';
  src: url('../fonts/glyphicons-halflings-regular.eot');
  src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}

There are two ways to go about fixing this:

  1. You can update the font references to be relative to the actual directory structure.
  2. Much more simply, you can move the bootswatch CSS file into the css directory under the bootstrap directory so the relative font file references work without being modified.

Set Focus on a Field when Showing a Bootstrap 3 Modal

While testing an application that I’m working on, I noticed that the focus is not set on a field within a Bootstrap modal when it’s shown. This is annoying to the user because it requires to tab a number of times (since the focus stays on the button clicked to show the modal) or click into a field in order to start typing. In this post, I’ll show how to force the focus to be set on a specific field when a modal is shown.

Event Delegation

One simple approach is to use jQuery event delegation (here’s a great explanation from Mark Roden). An event handler can be added to the body tag to fire whenever a modal is shown. Within that handler, we can set the focus on a specific field.

$('body').on('shown.bs.modal', '.modal', function () {
  $('[id$=myField]').focus();
})

The first line sets up the event delegation by adding a listener to the body of the page for the event of showing a modal (shown.bs.modal). The second line locates the field named myField and sets focus on it.

The selector in the second line may look a bit strange, but it’s effect is to find the element where the id attribute ends with myField. This is because XPages adds a number of colon-separated prefixes to each element, depending on it’s depth in the page structure. In order to not worry about all of that, the code looks for the element that ends with the name that I assigned to the field.

Here are two other options that you have for achieving the same effect:

  1. Add a unique class name to the field and use $(‘.yourClassName’) as the selector
  2. Use Mark Roden’s x$() function to select an element

Modals and Partial Refreshes

As if there haven’t already been enough (too many?) references to Marky, take a look at this post if you have a modal that needs to perform partial refreshes.

Ultimately, the code I’m actually using in my application looks like this:

$('body').on('shown.bs.modal', '.modal', function () {
  $('FORM').append($('.modal'));
  $('[id$=myField]').focus();
})

Multiple Modals

This method works fine on a page that only has one modal. If you have multiple modals, you’d need to adjust the logic in order to set the field focus as desired. One more generic option would be to change the jQuery selector to just find the first input field on the modal.

Resizing a Bootstrap 3 Modal

The Twitter Bootstrap modal is a very slick dialog that you can easily use within XPages. In this post, I’ll show how to increase the size of modals globally. I’ll also show how to re-center the modal if you resize the body with CSS.

Resizing a Modal

The bootstrap modal uses the class modal-dialog. By default, it is 600px wide.

To widen it, use CSS to increase the width.

.modal-dialog {
  width: 900px;
}

This updates the modal size and allows it to be centered properly when launched.

However, if you increase the size on the modal content area or body, it will not re-center properly. (This may happen if you don’t want to globally resize all modals or if you have a reusable control for modals, but your content changes and you want to re-size some instances.)

.modal-content {
  width: 900px;
}

If you display this modal, you’ll notice that it’s no longer centered.

Modal_NotCentered

Centering a Modal with the Body Resized

In order to center it, you can add another line of CSS to set a negative value for the left margin.

Since the modal is automatically centered based on a width of 600px, you want to move it back to the left by half of the additional width.

Left Margin = (600px – [New Width]) / 2

In this example, the new width is 900px, so the left margin is (600-900)/2 = -150px

Here’s the updated CSS:

.modal-content {
  width: 900px;
  margin-left: -150px;
}

Now the modal will be centered.

Modal_Centered