How to Style an ADF Checkbox

December 6, 2016

By: Andreja Sambolec – Application Consultant

Sometimes, you want to customize your checkbox component by changing the background color.

This can be done using CSS and :after and :before pseudo classes on checkbox elements.

This is what a checkbox looks like:

code

The condition necessary to be able to change the background color:

The element must precede the

The steps to style a checkbox:

#1 Hide the checkbox

input[type=checkbox] {
opacity: 0;
}

#2 Use :checked and :before pseudo classes to style checkbox

.checkbox input[type=checkbox]:checked + label::before{
content: 'ON';
background-color: #428bca;
}

Read more on these steps here.

So, how do you apply these steps to ADF components?

To display a checkbox component in ADF, we are using af:selectBooleanCheckbox element:

<af:selectBooleanCheckbox value=”#{bindings.InternalApplication1.inputValue}”

text=”#{bindings.InternalApplication1.label}”

styleClass=”checkbox”

shortDesc=”#{bindings.InternalApplication1.hints.tooltip}”

id=”sbc1″

disabled=”true”/>

There are two options to set the label:

  1. Using label attribute– it’s placed before input component
  2. Using text attribute – it’s placed after input component

When using text, the result is:

<td valign=”top” nowrap=”” class=”AFPanelFormLayoutContentCell”>

<span class=”af_selectBooleanCheckbox_content”>

<span class=”af_selectBooleanCheckbox_content-input”>

<input id=”r1:0:sbc4::content” name=”r1:0:sbc4″ class=”af_selectBooleanCheckbox_native-input” type=”checkbox” value=”t” checked=”” onclick=”this.focus()”>

<label for=”r1:0:sbc4::content” class=”p_OraHiddenLabel”></label>

</span>

<label for=”r1:0:sbc4::content” class=”af_selectBooleanCheckbox_item-text”>Refugee</label>

</span>

</td>

 

When using label, the result is:

 

<tr class=”checkbox af_selectBooleanCheckbox p_AFDisabled” id=”r1:0:sbc1″ _adftrc=”r1:0:sbc1::icon-style”>

<td class=”af_selectBooleanCheckbox_label af_panelFormLayout_label-cell”>

<label class=”af_selectBooleanCheckbox_label-text” for=”r1:0:sbc1::content” id=”r1:0:sbc1::contentlabelId”>Internal Application</label>

</td><td valign=”top” nowrap=”” class=”AFPanelFormLayoutContentCell”>

<span class=”af_selectBooleanCheckbox_content”>

<span class=”af_selectBooleanCheckbox_content-input”>

<input id=”r1:0:sbc1::content” name=”r1:0:sbc1″ disabled=”” class=”af_selectBooleanCheckbox_native-input” type=”checkbox” value=”t” checked=”” onclick=”this.focus()” aria-labelledby=”r1:0:sbc1::contentlabelId”>

</span></span>

</td></tr>

 

We can see that only the option with text works because the label is set after the input element.

If you have the readOnly attribute set to ‘true’, replace it with ‘disabled=true’. This will make it easier to style.

This is what the CSS should look like:

/**hide checkbox*/
.checkbox input[type="checkbox"] {
opacity: 0;
width: 0px;
}

/*style label to display checkbox*/
.checkbox .p_OraHiddenLabel {
position: relative;
left: inherit;
font-size: 12px;
top: inherit;
content: "";
display: inline-block;
position: relative;
width: 17px;
height: 17px;
left: inherit;
margin-left: 0px;
border: 1px solid #cccccc;
border-radius: 3px;
background-color: #428bca;
border-color: #428bca;
}

/*style for unchecked state
Set the content to have no issues with moving elements when switching between states – the content is hidden, but save space for it.
*/

.checkbox input[type="checkbox"]:not(:checked) + label:before {
content: "ON";
color: #428bca;
display: inline-block;
}

/*style for checked state*/
.checkbox input[type="checkbox"]:checked + label:before {
font-family: 'FontAwesome';
content: "\f00c";
display: inline-block;
}

/*styling disabled chheckbox*/
.checkbox input[type="checkbox"]:disabled + label {
background-color: #428bca;
border-color: #428bca;
opacity: 0.65;
}

/**/
af|selectBooleanCheckbox::item-text {
margin: 0px 1px;
padding-right: 3px;
padding-left: 2px;
vertical-align: middle;
margin-left: 1px;
left: -167px;
position: relative;
}

/**hide checkbox*/
.checkbox input[type="checkbox"] {
opacity: 0;
width: 0px;
}

af|selectBooleanCheckbox::content {
line-height: 19px;
}

The end result:

adf-blog


Friendly URLs in WebCenter Sites

March 4, 2015

By: Darek Blankenbuhler – Application Consultant

Having friendlier, cleaner looking URLs has always been a challenge in WCS. In the past it would require a developer to write a Java class. Once the class had been written it would need to be configured and deployed on every instance of WebCenter Sites in your setup. If you wanted a second assembler for another asset type or blobs that would require even more configuration and coding to work properly. Suffice it to say that in the past making a friendlier URL was a difficult task especially if friendly URLs were not set up during the initial build. This has all changed with the advent of WebCenter Sites 11.1.1.8. Friendly URLs have been built right into the Advanced Interface and no longer require as much specialized knowledge. An administrator can find this new feature in the Admin tab under Asset Types inside the Asset that is being configured.

Fr1

Today I want to set up a new pattern for the Page Asset type. As you can see there are no URL patterns set for pages yet. So, I will go ahead and click Add New, and I will be brought to the following page:

Fr2

Now I am ready to start creating my first URL pattern. As you can see I can be as generic or as specific as I want to be. No longer do I have to worry about writing my templates and URL assembler to work together to render the final product. The system will go ahead and take care of that for me. The URL is comprised of the different attribute values available to the asset. In the case that the Subtype is set to “Any” I will only have access to the default basic attributes that come along with every asset type that is created. By selecting a subtype I can now use attributes that are a part of that asset type in the URL.

Fr3

The primary downside to this is the fact that now the “Standard” subtype will have its own pattern. If I only set up the “Standard Page” URL only page assets with the subtype “Standard” will have a friendly URL. It is a good idea to set up a pattern for “Any” type as before going live. Last we will put it all together with the pattern itself. The pattern uses the Java Expression Language to build the URL. As you can see I can put as much or as little information in the URL as I want too. When I have finished configuring the URL, at the bottom of the page I can get a preview URL for existing pages.

fr4

This way I can test to make sure my URLs are going to come out clean looking before I implement the new URLs. Then I can save and I have completed building the URLs. URL Patterns are stored as a part of the asset type. Which means that all I have to do is publish the asset type to get the URL pattern to be pushed between systems – this tool is kept as simple as possible.

All in all, the new URL pattern tool is a powerful and easy to use tool and a welcome addition to WebCenter Sites. Whether it is the ability to generate URLs using any information in the asset or the ability to make the URL assembler as specific as we want. URL assemblers are now much easier to make and implement.

Want to meet us at Collaborate 15 in Vegas to talk about your WebCenter needs? Fill out the contact form and we will work with you to arrange a meeting!


Customizing WebCenter Content: Part 5 – Custom Service

July 2, 2014

By: Dwayne Parkinson – Solution Architect

As we conclude our Blog series on customizing WebCenter Content we are going to finally create a custom WebCenter Content service which will leverage the query and template we created in earlier Blog entries.  Once we have a custom service created, it can be placed on WebCenter Content menus, called from applications, used in iDoc Script and other WebCenter Content services. While our service will perform relatively simple functions, you will see how the same steps can be used to build fairly elaborate customizations.

Create a Custom Service

A Service is yet another type of resource that exists within a custom component, so the first step to creating a custom service is to create a custom component.  We already have a custom component from our previous Blog entries, so using the Component Wizard we’ll open the example component we created in the previous Blog entries and put our service in that component.

To create a service you click the Add button in the Custom Resource Definition pane of the Component Wizard.  On the next screen select the Service checkbox and accept the default names.

cw51

Make sure the service is in the “resources” folder and click on Next.

The next screen will ask for a Table Name which is used to store information about the custom service.  Accept the default table name here as well.

cw52

Finally we get to the point where we can add our custom service and tie all of our work together.  The top half of the screen defines our service while the bottom half tells what actions the service will perform.
cw53

The Name field is the name of your service.  The standard convention in WebCenter Content is for all service names to be in all upper case with words separated by an underscore.  The service name will be what you see in the URL when the service is called.  So in our case the portion of the URL with our service would look something like this: idcplg?IdcService=EXAMPLE_GET_FULL_NAME

The next field designates the class of service.  The class of service is really referring to a Java class and it determines what actions can be performed by the service.  For our example we’ll use the class of Service.

The Template field is used when there is a template to display results of the service.  We are going to use our EXAMPLE_PAGE template resource that we created in a previous Blog entry.  This template is a page that says “Hello World” with standard WebCenter Content page begin, end, etc.

The Service Type field we will leave blank.  The type of Sub-Service is only used when you are creating a service that will only be called from another service.  Our example service will be initiated directly from the URL so we will leave this blank.

The Access Level must have Scriptable checked for your service to execute.

The Subjects Notified is for defining which subsystems within WebCenter Content should be aware of this service.  For our example (and in most cases) this will be blank.

Finally, the Error Message is a text field that defines the error message returned by the service unless one of the actions overrides it.  For our purposes we will leave this blank and now we’re ready to start adding some actions to our service.

Adding Service Actions

The action list defines which actions the service will perform and in what order.  To add an action, click the Add button in the Action section.

cw54

The Type of action indicates what type of resource we will be invoking from our service.  The table below provides information on what each type of action does.

Action Type Description
Select Query Executes a select query, but does not return the results. Instead, the query will return whether the execution succeeded or failed.
Execute Query Executes data manipulation queries (insert, update, delete). The execution will not return any results, but will alter the database.
Java Method Executes a Java method. The method can be contained in the Service or a handler.
Load Option List Loads an option list into local data of the service. The option list is available to use in a template.
Select Cache Query Executes a select query and puts the results into Content Server’s backend data. The output will be available as a ResultSet.

 

Since we will be using the query resource we created in a previous Blog entry to return the full user name, we will use the Select Cache Query.

The next step in adding an action is to specify the name of the action.

cw55

In our case the name of our query was QfullName so we will type that in to the action field.  NOTE: There is a quirk in action field.  When you tab out of the action field the first time it may default back to the first entry from the drop down list and you will need to retype your action name.

The Parameters section specifies the parameters for the action.  Since we’re using a Select Cache Query, the parameter we specify will be used to store the results returned from our query.  By entering FullName, the service will generate a result set with the name FullName.  The result set will contain the results of our query.

The Control Mask is beyond the scope of this Blog, but documentation can be found here: http://docs.oracle.com/cd/E23943_01/doc.1111/e11011/c03_customizing_services.htm#CSSRG2048

The Error Message is the text that will be displayed if this action produces an error.  We will leave it blank and allow system generated errors to be seen.

Now we can click on OK and complete the definition of our service.

Testing the Service

To test our service we must first enable our custom component using the Component Wizard and then restart the content server so our component can be loaded.  Once that’s complete, sign on and change the URL so it calls our EXAMPLE_GET_FULL_NAME service as shown below.

cw56

Notice that there’s a parameter of dName after our service.  This parameter is required by the QfullName query we used so it must be supplied after the service call.

When we call the service you’ll notice that the EXAMPLE_PAGE template is displayed.  This shows us that the template we hooked up to the service is working as expected since we’re seeing our “Hello World” message.

Of course we also want to know if our service actually returned the full name of the user by executing the QfullName query.  To do that let’s execute our service again and append &IsSoap=1 to the end of the URL as shown below.

cw57

When using the IsSoap parameter, the results are redirected from our EXAMPLE_PAGE template to a SOAP envelope which is nothing more than an XML file.  As you can see, the result set of FullName contains a row that says the full name for user weblogic is Web Logic.  (Remember, we specified FullName as the parameter on our Select Cache Query and that’s how the result set gets its name)

The Finished Product

We would be remiss if we left our discussion of custom components, services and templates without actually displaying the results of our query on our template.  While it’s beyond the scope of this Blog to dive deeply into the iDoc scripting language, thankfully we only need a few lines of iDoc Script.  Within the Component Wizard, highlight the template resource and select our EXAMPLE_PAGE template.  Now we can click on the Launch Editor button in the lower right corner of the screen and add the highlighted lines of iDoc Script to our template.

cw58

Once those three lines are added, the server must be restarted and then we can execute the service again.  With our template changes in place, the service will show the following screen.

cw59

Conclusion

We have covered a lot of ground to merely show Hello World and the full name of a user, but the principles we’ve demonstrated are incredibly powerful.  As you can see, WebCenter Content is not just a piece of software; it’s a framework that can be extended for developing truly custom solutions to meet the unique needs of your organization.

For more information about the possibilities of extending WebCenter Content to meet the requirements for your next project or to request customized training for your development team please contact TEAM Informatics and ask about our extensive WebCenter Content customization capabilities.

 


Customizing WebCenter Content: Part 4 – Query Resources

June 25, 2014

By: Dwayne Parkinson – Solution Architect

The past few Blog entries have covered some WebCenter Content building blocks that are necessary before we begin customizing the system.  In this entry we will explore the query resource which is that last of our basic building blocks before we start gluing everything together and creating our own fully functional custom components.

The query resource allows a component store and execute any number of custom SQL queries. The SQL queries run directly against Content Server’s database. The queries defined in the query resource can be executed from a service, Idoc Script, or Java and are therefore incredibly useful.

Content Server Database

The query resource requires some information about Content Server’s database.  To develop query resources you will need a connection to the Content Server’s database and some sort of SQL tool like Oracle SQL Developer.  Once you have established a connection to your server you should see tables similar to those shown below.

cq1

Content Server Tables in Oracle SQL Developer

Creating a query resource will require knowledge of the existing tables and SQL. A few of the most popular tables used for customizations are:

–       DOCMETA: Metadata (including custom metadata fields) for all content items on the content server.

–       DOCUMENTS: The document name and other document related information.

–       REVISIONS: Information about each revision of a content item such as the document type, title, creation date, author, etc.

–       USERS: Contains information about the user profiles in the system.

The query resource may also define new tables and access those tables, but that’s beyond the scope of this Blog entry.

Content Server Queries

Before creating a query resource for a component, we can look at Content Server’s core query resource for a good reference. Content Server’s core query resource contains hundreds of queries that may be used in a component. The core query resource can be accessed at <install_dir>/ucm/idc/resources/core/query.htm.

cq2

Content Server’s Core Queries

The query resource above is the HTML representation of the query definition. Notice that the table is broken into three columns. The columns are name, queryStr, and parameters. Although with the Component Wizard these will be managed automatically, knowing the columns is useful.

Query Resource Columns

Column Description
name The name column specifies the name for the query. The name needs to be unique. If the name is not unique, it could override an existing query. It is recommended that a convention is used to uniquely identify queries. See the naming standards below.
queryStr The queryStr column specifies the SQL query. The SQL query can update, delete, insert, or select rows from the database. Parameters may be added to the query by using a ‘?’.
parameters The parameters column specifies all of the parameters for the query. The parameters must have a name and data type associated with them. The order of the parameters is important.

Query Naming Conventions

When you are creating a custom component with a query resource, the SQL queries defined in the query resource should have a unique name. Content Server generally follows a standard naming convention to help manage the types of queries. When adding a query resource to a component, it is recommended that a prefix convention is added to the name of the query as well. For example, a query inside of the component ‘exampleComponent’ may be QfullName. The table below shows the standard prefixes throughout Content Server.

Standard Query Naming Convention

Prefix Description
Q SQL queries that select row(s) from a database table.
U SQL queries that update row(s) in a database table.
D SQL queries that delete row(s) from a database table.
I SQL queries that insert a row into a database table.

Adding a Query Resource

Once a component has been created, a query resource can be added from the Add Resource form.  Notice that the query will be stored in an htm page within the /resources folder of the component.

cq3

Add Resource Form

By selecting the query resource, the file name should change to follow the standard “_query.htm” convention.  The query resource can be used to define new queries, override existing queries, and expand existing queries.

An existing query may be loaded and edited by selecting one by name from the list of queries for a particular query resource or a new query may be added.  As expected the Add Query form requires a Query name to be specified.  The Edit Query form does not have the opportunity to specify the query name, but otherwise it is identical.  In both cases you must provide the SQL query text, and optionally specify parameters.

cq5

Adding a Query to the Resource

The Component Wizard will then add the new query to the query resource and behind the scenes a “table” will be created to store the information.  It’s important to note that if you want to rename a query you must manually edit the htm files created by the Component Wizard.  For example if you wanted to change the query above to be QgetFullName once it had been created you would edit the html tables manually.

Beyond the query resource file, the Component Wizard will automatically add the query resource to the glue file as well.

@ResultSet ResourceDefinition4type

filename

tables

loadOrder

query

resources/examplecomponent_query.htm

exampleComponent_Queries

10

@end

The example above shows an example of a query resource, the path to the resource, the query table name, and the load order.

Query Parameters

The use of parameters is important in queries. Content Server supports the use of parameters in queries by using a “?” place holder for each parameter. Each of the parameters used in the SQL query must associate with a parameter that is defined in the parameter list for the query.

cq6

Adding a Parameter to the Query

The query above requires that a User Name is provided. The query will need to have a parameter added to the list of parameters before it will run successfully. Notice that in the example only one parameter is used, but with multiple parameters the order of the parameters in the list is important and the interface allows the parameters to be shifted up and down by using the Up and Down buttons.

cq7

Adding the Parameter to the Resource

The parameters will need to have a name and type specified. The types that are available are directly associated with the database data types. The type needs to match the data type that exists in the database table.

The name, queryStr, and parameters will then be added to the HTM file which stores the query information. The columns will match all of the information that was specified inside of the Component Wizard’s interfaces.

cq8

The HTML representation of the query resource

Service Query Action

Now that we’ve got a query defined we need some way to execute the query.  As previously mentioned, we could execute the query from Java, iDoc Script or from a Service.  In the next Blog entry we will go into more details on creating a service and executing our query.  For now it’s important to know that when you create a service that executes a query you have to tell the Content Server what to expect when the query is finished because the return results differ.  A query that performs an SQL Update or Insert will return different results than one that performs a Select.

When creating a query service there are three action types that may be used.

Service Query Action Types

Action Type Description
Select Query Executes a select query, but does not return the results. Instead, the query will return whether the execution succeeded or failed.
Execute Query Executes data manipulation queries (insert, update, delete). The execution will not return any results, but will alter the database.
Select Cache Query Executes a select query and puts the results into Content Server’s backend data. The output will be available as a ResultSet.

As you might guess, selecting the right Action Type is a critical step for the query service to operate as expected.

Summary

In the next Blog entry we’ll dive into more detail on how to create a service to execute a query.  Since the entire WebCenter Content platform is built on the concept of executing services, our ability to build services which return and update data from the content server files is incredibly powerful.

For more information on customizing WebCenter Content and customized training to suit the needs of your organization, please contact TEAM Informatics and let us help you increase the ROI on your WebCenter Content investment.


Customizing WebCenter Content Server: Part 3 – Templates

June 18, 2014

By: Dwayne Parkinson – Solution Architect

In Part 2 we covered some of the things that can go into a custom component to help you customize your content server.  In this entry we’ll look at a Template and show how it can be used to customize the WebCenter Content interface.

Templates in Content Server allow custom pages to be created. A template is created inside of a component resource, so you must have a component before you can add a custom template to Content Server.

Create a Custom Component

The first step to creating a custom template is to create a component.  If you’re not familiar with the concept of components, the best way to think of them is as a set of related resources used to customize the system.  As a general rule you create a component to contain resources that are related to a common customization.  For example, if you need to have some custom security processing you would generally have a single component for all of the custom security features.  You would not create separate components for each security feature.  In other words, your component name might be CustomSecurity rather than having separate components called ValidateID, UserLookUp, etc.

Creating a custom component is done by opening the Component Wizard and clicking the add button.  While we won’t cover the details of the Component Wizard here, you can find Oracle documentation on-line that explains the process in more detail http://docs.oracle.com/cd/E29542_01/doc.1111/e26692/components.htm#WCCSA357.

Adding a new component will get us an empty container that we can use to begin adding resources.

The Template Resource

The template resource is a simple text file that defines the template pages within a component. The default extension for these resource text files is HDA.  The Component Wizard helps manage the creation of the template resource.  As shown below, you simply select a Template resource type and add the file.  NOTE:  It is highly recommended that all templates go into a “templates” folder as shown.

ct1

Adding a Template Resource

Behind the scenes the Component Wizard is busy creating some entries in the “glue file” which is a text file that defines all of the component resources.  This glue file is named <componentName>.hda and is located in the following folder:

<install folder>\ucm\cs\custom\<componentName>

For example, if your custom component is called “test” (because we’re creative) the file will be called test.hda and it will be in a folder called ucm\cs\custom\test within the domain folder for the Content Server.

The resulting entries in the glue file are shown below.  They exist to let the content server know that there is a custom resource definition out there that needs to be merged in with the rest of the system.

After creating the initial template definition, the next step is to further define the resource and identify what it should be merged to within the Content Server.  The Component Wizard will manage these relationships in the glue file automatically as you add, update and remove resources.

ct2

Merging to Content Server’s Templates

In the example above, this template resource is going to be merged with the ‘IntradocTemplates’ which is used when creating any content server pages other than search result pages.  For more information on the difference between IntradocTemplates and SearchResultTemplates refer to this bit of documentation
http://docs.oracle.com/cd/E23943_01/doc.1111/e10807/c15_create_custom_comp.htm#BEIGHGAE

Once you’ve selected the Merge Table the Component Wizard again updates the glue file with some MergeRules that tell the Content Server how to merge our new template into the Content Server.  The resulting entries in the file are shown below.

@ResultSet MergeRules
4
fromTable
toTable
column
loadOrder
exampleComponent_Template2
IntradocTemplates
name
10

The Template Page

With our template resource files successfully created, a template page can now be defined within the resource.  A template page is made up of HTML and iDoc Script (see below). The template can copy one of the Content Server’s pages or we could create a completely custom page. While we could create a completely custom page, it is often easiest to use an existing template so our page gets automatically filled in with the necessary iDoc includes (see below).

In this example, we’re going to create a template page called EXAMPLE_PAGE and copy from the doc_info page.  Note the location of the template files.  They will be in a similar location on your content server.

The Class field we’re going to purposely gloss over and simply say that most of the time it’s Document or DocManagement.  For more information on the Class field, reference the Oracle documentation.

Notice that Form Type and File Name are the same as the name of the template.  You will find that the “standard” within the WebCenter Content world is to use all capital letters for the template while Form Types and File Name are generally in camel case or lower case.  NOTE: If you’re using the SearchTemplate only a Form Type of ResultsPage is currently supported.

ct3

Creating a Template Page

Once everything is filled in, the code for the resulting template page is generated by the Component Wizard.

<$include std_doctype_html_decl$><head>
<$defaultPageTitle=lc(“wwContentMgmt”)$>
<$include std_html_head_declarations$>
</head>

<$include body_def$>

<$include std_page_begin$>

<$include std_header$>

<!– Template Contents –>

<$include std_page_end$>

</body>

</html>

By copying from an existing page, all of the necessary includes are automatically generated.

Understanding iDoc Includes

The WebCenter Content server makes extensive use of iDoc “includes” throughout its architecture.  Most developers are familiar with the concept of include files, however where WebCenter Content and iDoc Script depart a little from normal is that includes also reference sections of code within the same file, similar to a procedure call.

Rather than get derailed by the gory details of iDoc Script training, let’s look at our example from above and look at what each of those includes does.  You can then review each of these separate include files to see how the iDoc Script is constructed and how the includes are being referenced.

WebCenter Content stores its core iDoc Script files in the following location:

<install folder>\ucm\idc\resources\core\idoc

These files should never be modified directly.

The std_page.idoc file contains the includes used in the sample page above and if you read through the code you can figure out exactly what’s going to happen.  However to make life easier, the following table gives you a general idea of the purpose of each include.

Standard Template Page Includes

Include Description
std_doctype_html_decl Defines the page’s DTD definitions.
std_html_head_declarations Defines the page’s header declarations. This section contains meta tags, JavaScript, and style declarations.
body_def Defines the body tag. This section can be modified to add additional parts to the body.
std_page_begin Defines the beginning of the page resources. This section can be modified to add to the page before the header.
std_header Defines the header for the page. This section is the navigation and top bar of the page.
std_page_end Defines the page’s footer. This section can be modified to add a custom footer to a page.

 

By understanding each of these includes, figuring out what’s happening in any given section of the page can become easier. For example, the ‘std_header’ include from the template generates something like this:

ct4

The ‘std_header’ include

When thinking about a template page vs. an include, it is valuable to remember that includes are called on a template page. The includes are defined elsewhere like in the std_page.htm file. They are called on template pages or within other includes. You can think of the template page as a canvas and includes are one medium that can be used to paint on that canvas.

It’s important to notice that the Content Server, as if by magic, knows where to find the includes so you don’t have to specify any class paths or folder structures or anything like that.  This is because we’re merging our custom component into the core Content Server.  That process makes our component aware of the resources available on the Content Server.

Hello World

It wouldn’t be a user interface if we didn’t generate a Hello World message right?  Unfortunately we’ll have to wait for a couple more Blog entries to actually see our page, but for now we can at least add the requisite “Hello World” message under the Template Contents comment line in the HTML file shown above.  Since this is an HTML file you can add any HTML compliant code you want, but for now we’ll keep it simple.

Summary

Customizing the interface for WebCenter Content is relatively simple once you know the steps and understand the architecture.  In this part we created a simple template resource with a single page.  In Part 4 we’ll leverage WebCenter Content’s service oriented structure to create a service that will render the page we created.

While it’s difficult to do justice to the full flexibility of WebCenter Content in a few blog entries, I hope this series will help more people dive in and attempt to customize the WebCenter Content server.  Obviously we’re just skimming the surface, so if you would like more information on customizing WebCenter Content please contact TEAM Informatics and ask about our customized training options.

 

 


Customizing WebCenter Content Server: Part 2 – Understanding Components

June 11, 2014

By: Dwayne Parkinson – Solution Architect

In the previous blog entry on customizing WebCenter Content Server we covered the basic content server architecture.  With that architecture in mind we can discuss how customization is done on the content server.

Customizing the content server involves creating custom “components” that run on top of the base architecture.  Components are made up of five types of resources. The resources provide specific functionality and are each managed differently. The table below describes each of the resources.

Types of Component Resources

Resource Type Description
Environment This resource defines variables. The variables can overwrite existing or create new variables for the component.
Resource This resource defines custom content. The resource can create page sections or strings to be used on pages.
Template This resource manages and defines page layout templates. The custom templates can be used with services and override existing templates.
Query This resource defines SQL queries that can be used against Content Servers database. The SQL queries are defined by name, which allows them to be referenced throughout Content Server’s architecture.
Service This resource defines functionality for Content Server. The resource can override core services or add new capabilities to Content Server.

 

Each type of resource is used differently.  These resources and the code contained within them can be part of custom components, but each resource type also has a counterpart within Content Server core files.

Core Files

The core Content Server files contain the same types of resources as are contained in components. For that reason, it is often very useful to look at the core files as examples when creating custom components.  Creating your own custom components allows for customizations to be separated from the core, which is especially handy during the installation of a Content Server update because your customizations will not be lost.

Note: The core files should not be modified to create customizations for Content Server.

The core files are available in the <install_dir>/ucm/idc/resources/core directory.

Covered Core Content Server Files

File Description
idoc/std_page.htm Contains Content Server’s core includes. The file is a good reference when trying to modify Content Server’s interface.
idoc/std_services.htm Contains Content Server’s core services. The file is used to learn more about a specific service.
tables/query.htm Contains Content Server’s core queries. The file can be referenced to find existing queries to use in components.
lang/cs_string.htm Contains Content Server’s system strings. The strings contained in this file are system and errors messages.
lang/ww_strings.htm Contains Content Server’s interface strings. The strings contained in this file are displayed on the web interface.

 

The table above lists a few of the important files that you will find useful when creating custom components. The core folder contains many more files that can be used as references in the development of custom components as well, but they won’t be covered here.

Components Files

Now that we have an understanding of some of the types of resources a component contains, let’s look at the component itself.  A “component” is a predefined folder structure that contains many different files that define and are used by the component.  The content server expects this folder structure to be in place when a component is installed and it will look inside the folder for specific files and expect certain files in certain locations based on how the component is built.  The diagram below depicts some of the most common files that you will find in a component folder structure.

CWC1

You can use the above diagram to help identify different types of files as it specifies the naming convention for each type of file under the name of the file.  The following table shows some of the most common files that a component will contain and a brief description of what they are used for.

Component File Locations and Descriptions

Name File Description
Component File components.hda Specifies the components that are enabled and the location of the corresponding Component Definition File.  It is located in the /config directory.
Component Definition File (Glue File) *.hda A glue file or component definition file.  Points to custom resources defined for a file.  The glue file for a component is typically named ComponentName.hda.  It is located in the root component directory.
 Manifest File manifest.hda This lists the files that make up the component and specifies their locations. It points to resources through the Glue File. The file is always located in the root directory when present, but does not appear until the Component is built.  This is because this file is used for installation of the component.
Environment Resource *_environment.cfg File defines configuration setting for Content Server.  Located in the root component directory.
Resource Resource *_resource.htm Resource file contains includes, strings, static tables, and dynamic tables.  It is located in the resources directory.
Template Resource *_template.hda A template definition file that points to the custom template resource files defined for a component.  Typically located in the templates directory.
Template Page *_template.htm A resource file that defines a function or procedure that is performed by the content server.  Typically located in the resources directory.
Service Resource *_service.htm Defines a function or procedure that is performed by the content server.
Query Resource *_query.htm Defines SQL queries.  These can be specified in a service resource directly but this allows for reusability.

Now that we know a little about the component, let’s look at the folder structure for a component and see what it looks like.

cwc2As you can see, most of the component folders shown here have a resources and a templates folder.  In addition, some files may be in the root component name directory (highlighted).

You may notice some variability in the file structure for different components, however, when using the Component Wizard to create a custom component, there are three directories that are typically created.

            1. <ComponentName>
            2. resources
            3. templates

The <ComponentName> directory contains the glue file and environment resource.  It also contains the resources and templates subdirectory.

The Resources folder contains the component’s resource definitions such as queries, page resources, and services.

The Templates folder contains the template definition file for that component and the template pages.

As you can see from the screenshot, there are often other directories as well including classes, images, publish, etc. A manifest file lists the files that make up the component and specifies their locations.  The file is always located in the /ComponentName directory.

 

Custom Component Locations

When you create or load a custom component you will find the component files by navigating to the following location on your server:

Oracle\Middleware\user_projects\domains\ucm_domain\ucm\cs\custom

From there you will see a folder structure similar to the one shown above.  Exploring this folder structure and reviewing the files will provide a good basis for understanding the next steps in component creation.

When components are moved from system to system, the entire component folder structure is “zipped” up using standard compression programs.  The zipped files can then be transferred between the systems and installed using either Configuration Manager or the Component Manager (see Oracle Documentation for these products).

Summary

Understanding and creating custom components provides tremendous opportunity to leverage your WebCenter Content server in new and exciting ways.  For more information on how to create custom components, please contact TEAM Informatics and ask about our training options, including classes customized to meet your specific needs.


WebCenter Spaces – steps to change the template and skin

April 22, 2014

By: Andreja Sambolec – Application Consultant

Create a new template and skin

If you want to change the default template and skin for your Spaces application, the first step is to create a new template and skin based on the OOTB template which looks similar to the design you want, and apply them to the Spaces application.

In our example we want to have the menu on the top of the page so we created a new template based on the ‘WebCenter Spaces Top Navigation’ template.

 

You can create a new template and skin from the ‘Resources’ tab (Administration-> Spaces-> select Space and select ‘Edit space’).

You can apply your new template and skin using the General tab:

skins1

The default menu looks like this:

skins2

We want to have something like this:

skins3

And this is how the drop-down menu should look:

skins4

 Change the template

We need to change the template because the logo icon has to be on the left side of the menu.

The best way to find what has to be changed is:

  • Create a new portal or ADF application in jDeveloper
  • Create a new .jspx page
  • Copy the templates source code and paste to .jspx file

Now you can easy see the structure of the template and decide what to change.

  1. Using browser ‘Developer Tools’ you can find which component holds the menu:
    skins5
  2. Using jDeveloper you can see the <af:decorativeBox  id =‘db1’ > component  contains  the Global navigation menu and the logo. The component with id set to ‘pt_pgl4’ holds the Top navigation menu.
  3. We decided to replace decorativeBox component with panelGroupLayout component.
    1. Replace af:decorativeBox with af:panelGroupLayut
    2. Delete facet:center
    3. Set layout property for panelGroupLayout to ‘horizontal’
    4. Create two panelGroupLayout components inside of ‘db1’ to hold the logo icon and the menu
    5. Set layout to ‘vertical’ for the second panelGroupLayout
    6. Cut and paste <cust:panelCustomizable id=”pcust1″> inside of the first panelGroupLayout
    7. Cut and paste  <af:panelGroupLayout id=”gtbppgl3″> inside of the second panelGroupLayout
    8. Cut and paste  <af:panelGroupLayout id=”pt_pgl4″> inside of the second panelGroupLayout
    9. Delete the component with id ‘gtbppbl1’
      skins6

This is the result:
skins7

  1. Place the Search input box to the right side:
    1. Using Chrome Developer tool you can see that we need to change the component with id= ‘pcust2’  because this component holds the menu:
      skins8
    2. You will see that the task-flow is used for the search component and it’s placed as the first component inside of ‘pcust2 ‘ so we just need to move it to the last place:
      skins9

New order:
skins10

 

  1. Change Spaces logo using Spaces Settings tab
    skins12
  2. Search for ‘gtbrspmxi1’ component and change the width and the height property for af:image component to 74px and also change the source property to “#{WCPrepareImageURL[spaceContext.space[WCAppContext.currentScope.name].metadata.logo][‘LOGO75’]}”skins13

 

  1. Set the property ‘rendered’ to false for ‘gtbrspmxgl2’ (to hide the link next to logo icon)

The result:
skins14

Change the skin

Next we want to change the menus background color.

The background color for the global menu should be in white.

Steps to change:

  1. Using browser Developer Tool, check which style is used to apply this color

When we deselect the background image for .WCSiteTemplateBackground, .x1r4,

we don’t see the  background color  anymore  on the top of the page .
skins15

  1. So, open the source of your custom skin and add this:

.WCSiteTemplateBackground{

background-image:none;

}
skins16

When you are checking out the styles for some components, you will not see the name of the component but some code, for example, .x106 (the skin is compressed).

You can apply changes using those compressed names or if you know, for example, which component is used you can try with af|commandLink. You could also open the page fragment in jdeveloper and check which component and style class is used and use it in your skin to add changes.

 

Change the navigation model

We also want to add some new pages, so we are going to change the navigation model.

  1. Create a new one based on default one (you can check which model is currently used using the General tab when you are editing your spaces app)
    skins17
  2. Edit your newly created navigation model (add links for your pages – you can create pages later and update Path for links)
    skins18
    skins19
    skins20
  1. Select custom navigation model as the default one for your spaces app
    skins21
    skins22We currently don’t see any sub-menus, so next we are going to change the menu component in our template.

 

Change the Top Menu

 

  1. Using the browser Developer Tool, you can see the menu is placed in the component with id  ‘T:spcNavPanel’.

Search for this component in your template file and you can see a region (task-flow) is used to display the menu.

We are going to replace this region with this code (loop through the navigation model and its children):

  <div class=menu>

    <c:set var=”navNodes”    value=”${navigationContext.defaultNavigationModel.listModel[‘startNode=/, includeStartNode=false’]}” scope=”session”/>

    <ul id=topnav>

      <c:forEach var=”menu” varStatus=”vs” items=”${navNodes}”>

        <li><a href=“/webcenter${menu.goLinkPrettyUrl}”> ${menu.title}</a>

           <c:if test=”${not empty menu.children}”>

             <div class=“submenu”><table width=100%><tr><td>

                <ol class=“blocks-four-up”>

                <c:forEach var=”child” items=”#{menu.children}”>

                 <li>

<p><a href=“/webcenter${child.goLinkPrettyUrl}”>

${child.title}

</a></p>

                 <c:if test=”${not empty child.children}”>

                 <ol>

                 <forEach var=”child1″ items=”#{child.children}”>

                 <li><a href=/webcenter${child1.goLinkPrettyUrl}”>

${child1.title}

</a></li>

                 </c:forEach>

                 </ol>

                 </c:if>

                 </li>

                 </c:forEach>

                 </ol>

              </td></tr></table></div>

            </c:if>

         </li>

      </c:forEach>

    </ul>

  </div>

 

You can find the meaning of EL expressions related to Navigation in this   document:

http://docs.oracle.com/cd/E23943_01/webcenter.1111/e10148/jpsdg_app_els.htm#CHDCBJGJ

 

 

  1. Add this to your skin:

 

.menu ul#topnav{

margin-top: 18px;

padding: 0;

float: left;

width: 880px;

position: absolute;

liststyle: none;

position: relative;

fontsize: 1.2em;

background:url(http://1-ps.googleusercontent.com/h/www.htmldrive.net/edit_media/2010/201007/20100728/Horizontal%20Subnav/images/xtopnav_s.gif.pagespeed.ic.v1mnjAEAt5.webp) repeat-x;

}

.menu ul#topnav li .submenu{  

padding: 15px 0;

position: absolute;

left: 0; top:35px;

display: none;

width: 760px;

background: #282828;;

color: #fff;

z-index:1;

-moz-border-radius-bottomright: 5px;

-khtml-border-radius-bottomright: 5px;

-webkit-border-bottom-right-radius: 5px;

-moz-border-radius-bottomleft: 5px;

-khtml-border-radius-bottomleft: 5px;

-webkit-border-bottom-left-radius: 5px;

}

.menu ul#topnav li{

float: left;

list-style: none;

}

.menu ul#topnav li:hover.submenu{

display:block;

}

.menu ul#topnav li a {

padding: 10px 15px;

display: block;

text-decoration: none;

color: #f0f0f0;

}

.menu.blocks-four-up{

list-style: none;

position:relative:;

}

.menu.blocks-four-up>li {

float: left;

width: 25%;

}

.menu#topnav.blocks-four-up>li ol li{

float: none;

}

.menu ul#topnav li .submenu a {

padding: 10px 0;

display: inline;

color: #f0f0f0;

text-decoration: none;

}

 

  1. To display four (4) submenus in one row, we have to use nth-child selector. If we include the selector in our skin file it’s not going to work, so we can just add it to the template:

<af:resource type=”css”>

.blocks-four-up>li:nth-child(4n+1)

{clear:left;}

</af:resource>

The result:
skins23

 

Next, we want to display the ‘More Info’ menu at the bottom.

How do we know which menu we are going to use as a bottom menu?  We can add some attribute (menuType) to the menu using the navigation model:

skins24

Change the template :

<c:forEach var=”child” items=”#{menu.children}”>

<li>

<c:if test=”${child.attributes.menuType != ‘bottom’}”>

    <p>

    <a href=/webcenter${child.goLinkPrettyUrl}>${child.title}</a>

    </p>

<c:if test=”${not empty child.children}”>

<ol>

    <c:forEach var=”child1″ items=”#{child.children}”>

    <li>

    <a href=/webcenter${child1.goLinkPrettyUrl}>

    ${child1.title}</a>

    </li>

    </c:forEach>

</ol>

</c:if>

</c:if>

<c:if test=”${child.attributes.menuType == ‘bottom’}”>

    <c:set var=”bottomMenu” value=”${child}” scope=”session”/>

</c:if>

</li>

</c:forEach>

</ol>

<p class=“menu_bottom_title”>

 ${bottomMenu.title}

</p>

<ul class=“menu_botom_links”>

<c:forEach var=”child1″ items=”#{bottomMenu.children}”>

    <li>

    <a href=“/webcenter${child1.goLinkPrettyUrl}”>

    ${child1.title}</a>

    </li>

</c:forEach>

</ul>

 

Add/change this to the skin:

.menu ul#topnav li  .submenu.menu_bottom_title{

clear: both;

margin: 0 8px .5em 12px;

padding: .75em 27px 0;

border-top: 1px solid #5e5f62;

font-weight: normal;

font-size: 1.230769em;

line-height: 1.125;

}

.menu.blocks-four-up>li ol{

-webkit-padding-start: 0;

}

.menu.blocks-four-up>li {

float: left;

width: 25%;

padding-bottom: 5px;

}

skins25

Using the same directions, we are going to add some images on the right side of the menu:

  • Create a new link and add attribute ‘menuType’ with value set to ‘image’.
  • Add attribute ‘imageUrl’ with the value which points to your image:
    skins26

Change your template (apply changes related to image in red color):

<td width=85%><ol class=blocks-four-up>

<c:forEach var=”child” items=”#{menu.children}”>

    <li>

    <c:if test=”${ child.attributes.menuType != ‘bottom’ &amp;&amp; child.attributes.menuType != ‘image’}”>

        <p><a href=/webcenter${child.goLinkPrettyUrl}> ${child.title}</a></p>

    <c:if test=”${not empty child.children}”>

    <ol>

    <c:forEach var=”child1″ items=”#{child.children}”>

        <li>

        <a href=/webcenter${child1.goLinkPrettyUrl}> ${child1.title}</a>

        </li>

    </c:forEach>

    </ol>

    </c:if>

    </c:if>

    <c:if test=”${child.attributes.menuType == ‘bottom’}”>

        <c:set var=”bottomMenu” value=”${child}” scope=”session”/>

    </c:if>

    <c:if test=”${child.attributes.menuType == ‘image’}”>

        <c:set var=”linkimage” value=”${child.attributes.imageUrl}” scope=”session”/>

    </c:if>

    </li>

    </c:forEach>

    </ol>

    <p class=menu_bottom_title> ${bottomMenu.title} </p>

    <ul class=menu_botom_links>

    <c:forEach var=”child1″ items=”#{bottomMenu.children}”>

        <li>

        <a href=/webcenter${child1.goLinkPrettyUrl}> ${child1.title}</a>

        </li>

    </c:forEach>

    </ul>

</td>

<td width=“15%” valign=“top”><img src=“${linkimage}”/></td> 

 

 

Finally, we want the submenu to cover the entire page.

To do this:

  1. Create a new div container as child of ‘pt_pgl5’ component:

<af:panelGroupLayout id=”pt_pgl5″ layout=”vertical” styleClass=”WCSiteTemplateBackground”>

            <div id=submenu/>

<af:panelGroupLayout id=”pt_pbl1″ layout=”vertical” inlineStyle=”width:#{attrs.templateFixedWidth}px;margin:0px auto;padding-top:8px;”>

 

We are going to clone the submenu in a mouse over action with this container.

  1. Add javascript to the template:

<af:resource type=“javascript>

function showSubmenu(e){

var childrens = e.parentNode.children;

var  len = childrens.length;

document.getElementById(submenu).innerHTML =;

for (i = 0; i &lt; len; i++) {

if(childrens[i].className==submenu){

newNode=childrens[i].cloneNode(true);

document.getElementById(submenu).appendChild(newNode);

}

}}

</af:resource>

 

  1. Add onMouseOver event to the link

<a href=/webcenter${menu.goLinkPrettyUrl}     onmouseover=showSubmenu(this)>

 

  1. Add this to css:

.menu ul#topnav li:hover.submenu{

display:none;

}

div#submenu.blocks-four-up>li ol li{

float: none;

}

div#submenu.blocks-four-up>li {

float: left;

width: 25%;

padding-bottom: 5px;

}

div#submenu.blocks-four-up{

list-style: none;

position:relative:;

}

div#submenu.blocks-four-up>li ol{

-webkit-padding-start: 0;

}

div#submenu.menu_bottom_title{

clear: both;

margin: 0 8px .5em 12px;

padding: .75em 27px 0;

border-top: 1px solid #5e5f62;

font-weight: normal;

font-size: 1.230769em;

line-height: 1.125;

}

div#submenu div{

padding: 15px 0;

position: relative;

left: 0;

width:1000px;

display: block;

background: #282828;

color: #fff;

margin: 0 auto;

 

}

 

div#submenu  {

width:100%;

top: 90px;

position: absolute;

z-index: 3;

background: #282828;

}

 

div#submenu li{

margin-bottom: .3076923em;

}

 

div#submenu p a{

font-weight:bold

}

 

div#submenu p {

margin-bottom: 3px;

}

div#submenu a{

padding: 10px 0;

display: inline;

color: #f0f0f0;

text-decoration: none;

}

 

div#submenu div>ol {

min-height: 109px;

list-style: none;

}

div#submenu div>ol ol {

padding:0px;

list-style: none;}

div#submenu div>table tr td ol ol {

padding:0px;

list-style: none;

}

skins28

You also need to add an event to clear the container when exiting from the submenu.

Those are the basic steps to change the template and skin of your Portal application.

Using a browser Developer Tool enables you to discover which component has to be changed or what to change in your skin.

 

Any questions? Feel free to contact us.