Widgets: Frequently asked questions
Here you can find answers to questions on developing and manipulating widgets.
What is a widget?
Widgets provide a way for administrators to customize the space, project, social group and system widgetized pages (Overview tab and the community Home page). They're a simple to create combination of Java code and FreeMarker templates that can be deployed as a plugin.
Is there a way to tell if the view that I'm rendering is in edit mode or in view mode?
The WidgetContext
, which should be available in your FreeMarker template
as widgetContext
, has an isEdit()
method. This method
should give you the ability to show a different view if the widget is being rendered as part
of a editing session.
Is it possible to add widgets to non-overview tab pages?
Not at this time, no.
Is it possible to display widgets outside the application?
Not at this time, no. However, there are a number of ways that you can expose content to other systems, by using either RSS or JSON.
Can you put multiple widgets of the same type on a page?
Yes, although if you do this and your widget uses JavaScript to refer to various parts of
the template, you should append an identifier to the DOM element ID's that you create or
manipulate. An example of how to do that is in the
/template/widget/your-statusupdates.ftl
template, which contains this
line of code at the top of the template:
<#assign idPrefix = StringUtils.randomString(6) />
Then later in the page a <div>
element in the widget can be referred to
like this:
<div id="current-status-${idPrefix}">
Is it possible to get a reference to the current user in the Widget class or widget template?
Yes, the current user is part of the WidgetContext
interface that gets
passed to your plugin's render method. If your widget extends BaseWidget
,
then you can call applyFreemarkerTemplate()
which calls
loadProperties()
and adds the WidgetContext
to the
FreemarkerContext
, and from there you can access the current user.
Also, if you override loadProperties()
then you can add whatever other
run-time props you want to access in your FTL file.
What files do I have to create in order to add a widget via a plugin?
You need a plugin.xml with a <widget>
element pointing to a class that
implements the Widget interface (or that extends BaseWidget
). That's the
bare minimum and assumes no design-time properties. If you want design-time props, then you
need a properties file in the beans folder, and a @PropertyNames
annotation
at the class level that defines the design-time properties.
How does the popularity algorithm in the popularity widget work?
PopularityDeterminationTask
is the class that handles the majority of the
work. It runs every 15 minutes (as configured in spring-taskContext.xml, which means you can
probably change it via a plugin in 2.1 if you want) and works closely with
ActivityManagerImpl
. Every time it runs it does the following things:
- Iterates over the set of containers in the community (spaces, projects, social groups and blogs).
- Calculates the popularity of each item in the in-memory copy of activities that activity
manager maintains for the current day. The score (or popularity) of each item is
calculated by adding together the score of each activity on an item, the scoring is as
follows:
- each view is given 1 point
- each modification (documents only) is given 5 points
- each comment (blogs and documents) or reply (thread) is given 5 points
- Calculates the popularity of items in each container stored in the database (a
popularity score is computed for each item based on the activity that happened that day
every night at midnight; this data is stored in the jivePopularity table) for the last
seven days. The individual day score is adjusted for each day old that the score is
recorded. We call this decay: the computation is done in SQL but if it were done in Java
it would look something like this:
Calendar c = Calendar.getInstance(); c.add(Calendar.DATE, -daysAgo); Date now = new Date(); Date nDaysAgo = c.getTime(); long dateDiff = now.getTime() - nDaysAgo.getTime(); long dateAdjustment = dateDiff / 86400000; long decayedScore = score / (1 + dateAdjustment);
- Add the results of the second and third steps together.
For example, a user published a blog post 2 months ago and through some sort of magic, it got 3 comments every day for the last 2 months (and it's already received 2 comments today that haven't been archived to the jivePopularity table). We only take into account the popularity score for the last seven days so the total score is going to be the sum of the following scores:
Date | Number of comments | Recorded score | Score with decay |
---|---|---|---|
6/5/2008 (today) | 3 | 15 | 15 |
6/4/2008 | 3 | 15 | 7 |
6/3/2008 | 3 | 15 | 5 |
6/2/2008 | 3 | 15 | 3 |
6/1/2008 | 3 | 15 | 3 |
5/31/2008 | 3 | 15 | 2 |
5/30/2008 | 3 | 15 | 2 |
Total Score | 37 |
Finally, each item is added to a SortedSet
, and then copied back to
ActivityManagerImpl
, where it lives until the next time popularity is
calculated fifteen minutes later.
So when you see a widget that shows the most popular items for a given space, project,
social group or blog, you're getting the n
items who have the highest
combined score, which is a combination of comments, replies, edits and views, decayed over
the last seven days.
How do I hide the border of a widget?
The short way is like this:
.jive-widget {border:none !important;}
If you wanted to remove the background on the header:
.jive-widget .jive-widget-header {background:transparent !important;}
But you might want an underline so that people know it is the header:
.jive-widget .jive-widget-header {
background:transparent !important;
border-bottom:1px dashed gray;
}
Note that not all the widgets are controlled by these two pieces of CSS. So further work would be needed in the profile, actions, and other elements.