3 The widget system in ninja <= 1.2.x was somewhat different from the widget
4 system used afterwards. This document will explain how to port your widgets.
7 In old-style widgets, you usually needed to create a javascript file with the
10 $(document).ready(function() {
11 var my_widget = new widget('my_widget', 'widget-content');
14 If that was all your javascript file contained, you can now safely remove it. If
15 it did more things, you may no longer initialize the widget yourself, but must
16 instead wait for the widget system to load your widget:
18 widget.register_widget_load('my_widget', function() {
22 If your javascript also kept track of your custom configuration options, that,
23 too, can likely be removed - see EXTRA SETTINGS.
25 If you do custom things to your javascript, you may need to adjust it, should
26 you want to make it possible to create multiple instances of the widget. This is
27 described in MULTI INSTANCE WIDGETS.
31 Old widgets that supported ajax refreshes all had to copy-paste the following:
33 <?php defined('SYSPATH') OR die('No direct access allowed.'); ?>
34 <?php if (!$ajax_call) { ?>
35 <div class="widget editable movable collapsable removable closeconfirm" id="widget-<?php echo $widget_id ?>">
36 <div class="widget-header"><span class="<?php echo $widget_id ?>_editable" id="<?php echo $widget_id ?>_title"><?php echo $title ?></span></div>
37 <div class="widget-editbox">
38 <?php echo form::open('ajax/save_widget_setting', array('id' => $widget_id.'_form', 'onsubmit' => 'return false;')); ?>
40 <label for="<?php echo $widget_id ?>_refresh"><?php echo _('Refresh (sec)') ?>:</label>
41 <input size="3" type="text" name="<?php echo $widget_id ?>_refresh" id="<?php echo $widget_id ?>_refresh" value="<?php echo $refresh_rate ?>" />
42 <div id="<?php echo $widget_id ?>_slider"></div>
43 <!-- EXTRA CONTROLS HERE -->
45 <?php echo form::close() ?>
47 <div class="widget-content">
49 <!-- WIDGET CONTENT HERE -->
50 <?php if (!$ajax_call) { ?>
55 With the new widget system, you should remove everything from this file that
56 isn't content. That is, the only thing you should keep in the view, is what you
57 had where it says <!-- WIDGET CONTENT HERE --> - everything else should go. Any
58 extra controls will need to be migrated to the controller - see EXTRA SETTINGS
63 This is the old template for the controller, i.e. the file that had the name of
64 your widget. Not all widgets had all of this, but most of them had most of it:
66 <?php defined('SYSPATH') OR die('No direct access allowed.');
67 class My_widget_Widget extends widget_Core {
68 public function __construct()
70 parent::__construct();
72 # needed to figure out path to widget
73 $this->set_widget_name(__CLASS__, basename(__FILE__));
76 public function index($arguments=false, $master=false)
78 # required to enable us to assign the correct
79 # variables to the calling controller
80 $this->master_obj = $master;
82 # fetch widget view path
83 $view_path = $this->view_path('view');
85 if (is_object($arguments[0])) {
86 $current_status = $arguments[0];
87 array_shift($arguments);
89 $current_status = new Current_status_Model();
92 if (!$current_status->data_present()) {
93 $current_status->analyze_status_data();
96 $widget_id = $this->widgetname;
97 if (isset($arguments['refresh_interval'])) {
98 $refresh_rate = $arguments['refresh_interval'];
101 $title = _('My Widget');
102 if (isset($arguments['widget_title'])) {
103 $title = $arguments['widget_title'];
106 # let view template know if wrapping div should be hidden or not
107 $ajax_call = request::is_ajax() ? true : false;
113 # fetch widget content
114 require_once($view_path);
116 if(request::is_ajax()) {
117 # output widget content
118 echo json::encode( $this->output());
120 $this->js = array('/js/my_widget');
121 $this->css = array('/css/my_widget');
122 # call parent helper to assign all
123 # variables to master controller
124 return $this->fetch();
129 This is the new-style equivalent:
131 <?php defined('SYSPATH') OR die('No direct access allowed.');
132 class My_widget_Widget extends widget_Base {
133 public function __construct($model)
135 parent::__construct($model);
137 * Do any global initiation here
141 public function index()
143 # fetch widget view path
144 $view_path = $this->view_path('view');
146 $current_status = $this->get_current_status();
147 $arguments = $this->get_arguments();
153 $this->js = array('/js/my_widget');
154 $this->css = array('/css/my_widget');
160 * The widget must inherit from widget_Base instead of widget_Core.
161 * The constructor now takes an argument, index takes none.
162 * You must not use require_once to include the view if you intend to allow
163 multiple widget instances.
164 * Still no file endings on javascript and css resources.
167 This used to be a free-form div in the view, however, it was mostly just
168 cut'n'pasted from widget to widget, so we have implemented the redundant stuff
169 once, so you won't have to. You now add a method to the controller, options, and
170 have it return an array of your extra options. This is the last example widget
171 again, but with two extra settings:
173 <?php defined('SYSPATH') OR die('No direct access allowed.');
174 class My_widget_Widget extends widget_Base {
175 public function options() {
176 $options = parent::options();
177 $options[] = new option('my_widget', // your widget name (or something else unique)
178 'option1', // a unique option name
179 _('My first option'), // your label
180 'input', // option type - input, checkbox, dropdown, etc
181 array('size'=>5), // extra attributes for the field
182 'default1'); // default value
183 $options[] = new option('my_widget',
192 public function index()
194 # fetch widget view path
195 $view_path = $this->view_path('view');
197 $current_status = $this->get_current_status();
198 $arguments = $this->get_arguments();
209 * This will automatically create javascript to save any changes and refresh the
210 page on changes. If you want to do this manually, you must call
211 should_render_js(false) on the option object.
212 * If you want to, you can return a pure HTML string of the widget settings you
213 want to keep track of. That way, you will get to do everything yourself.
215 - MULTI INSTANCE WIDGETS -
216 For simple widgets, to enable multiple instances you will only have to add one
217 single line of code to the constructor: "protected $duplicatable = true;". This
218 is a simple hello world widget that can be duplicated:
220 <?php defined('SYSPATH') OR die('No direct access allowed.');
221 class My_widget_Widget extends widget_Base {
222 protected $duplicatable = true;
223 public function index()
225 print "Hello world!";
229 If your widget is more complicated, you will probably have to change more
232 First, it's likely that your widget includes fields with the id attribute. Doing
233 so is no longer valid - you must either create a globally unique name using both
234 the widget's name and instance id, or you should use a class attribute instead.
236 Then, in your javascript, you must take care to use a combined selector to
237 retrieve the HTML node you want to for the correct widget instance. In the past,
238 a common pattern in javascript files was the following:
240 $(document).ready(function() {
241 var my_widget = new widget('my_widget', 'widget-content');
242 $('#my_widget_setting').change(function() {
243 my_widget.save_custom_val($(this).val(), 'my_widget_setting');
248 Again, if do_something is only a widget reload, you can remove this code
249 completely. If you do more things, you need to take more care.
251 This is how the above should be written with new-style, multi-instance widgets:
253 widget.register_widget_load('my_widget', function() {
254 var my_widget = this;
255 $('#'+my_widget.widget_id+' .my_widget_setting').change(function() {
256 my_widget.save_custom_val($(this).val(), 'my_widget_setting');
261 That is, you can safely search for the class within the widget instance id.