openerp-dev-web team mailing list archive
-
openerp-dev-web team
-
Mailing list archive
-
Message #06155
lp:~openerp-dev/openobject-client-web/trunk-proto61-dashboard-vda into lp:~openerp-dev/openobject-client-web/trunk-proto61
vda(Open ERP) has proposed merging lp:~openerp-dev/openobject-client-web/trunk-proto61-dashboard-vda into lp:~openerp-dev/openobject-client-web/trunk-proto61.
Requested reviews:
OpenERP R&D Team (openerp-dev)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-client-web/trunk-proto61-dashboard-vda/+merge/59469
Dashboard using jquery.dashboard plugin.
--
https://code.launchpad.net/~openerp-dev/openobject-client-web/trunk-proto61-dashboard-vda/+merge/59469
Your team OpenERP R&D Team is requested to review the proposed merge of lp:~openerp-dev/openobject-client-web/trunk-proto61-dashboard-vda into lp:~openerp-dev/openobject-client-web/trunk-proto61.
=== modified file 'addons/base/static/src/js/views.js'
--- addons/base/static/src/js/views.js 2011-04-26 14:13:34 +0000
+++ addons/base/static/src/js/views.js 2011-04-29 08:50:52 +0000
@@ -42,7 +42,11 @@
if (this.viewmanager) {
this.viewmanager.stop();
}
- this.viewmanager = new openerp.base.ViewManagerAction(this.session, this.element_id, action, true);
+ var sidebar = true;
+ if(action.no_sidebar) {
+ sidebar = false;
+ }
+ this.viewmanager = new openerp.base.ViewManagerAction(this.session, this.element_id, action, sidebar);
this.viewmanager.start();
}
break;
=== added directory 'addons/base_dashboard'
=== added file 'addons/base_dashboard/__init__.py'
--- addons/base_dashboard/__init__.py 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/__init__.py 2011-04-29 08:50:52 +0000
@@ -0,0 +1,1 @@
+import controllers
\ No newline at end of file
=== added file 'addons/base_dashboard/__openerp__.py'
--- addons/base_dashboard/__openerp__.py 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/__openerp__.py 2011-04-29 08:50:52 +0000
@@ -0,0 +1,11 @@
+{
+ "name": "Base Dashboard",
+ "version": "2.0",
+ "depends": ['base'],
+ "js": [
+ 'static/lib/jquery.dashboard/js/jquery.dashboard.js',
+ 'static/src/js/dashboard.js'
+ ],
+ "css": ['static/lib/jquery.dashboard/css/dashboardui.css'],
+ 'active': True
+}
=== added directory 'addons/base_dashboard/controllers'
=== added file 'addons/base_dashboard/controllers/__init__.py'
--- addons/base_dashboard/controllers/__init__.py 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/controllers/__init__.py 2011-04-29 08:50:52 +0000
@@ -0,0 +1,1 @@
+import main
\ No newline at end of file
=== added file 'addons/base_dashboard/controllers/main.py'
--- addons/base_dashboard/controllers/main.py 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/controllers/main.py 2011-04-29 08:50:52 +0000
@@ -0,0 +1,17 @@
+from base.controllers.main import View, clean_action
+import openerpweb
+
+class Dashboard(View):
+ _cp_path = "/base_dashboard/dashboard"
+
+ @openerpweb.jsonrequest
+ def load(self, req, node_attrs):
+
+ action_id = int(node_attrs['name'])
+ actions = req.session.model('ir.actions.actions')
+ result = actions.read([action_id],['type'], req.session.context)
+ if not result:
+ raise _('Action not found!')
+ action = req.session.model(result[0]['type']).read([action_id], False, req.session.context)[0]
+ clean_action(action, req.session)
+ return {'action': action}
\ No newline at end of file
=== added directory 'addons/base_dashboard/static'
=== added file 'addons/base_dashboard/static/data.html'
--- addons/base_dashboard/static/data.html 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/static/data.html 2011-04-29 08:50:52 +0000
@@ -0,0 +1,1 @@
+content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4 content 4
\ No newline at end of file
=== added directory 'addons/base_dashboard/static/lib'
=== added directory 'addons/base_dashboard/static/lib/jquery.dashboard'
=== added directory 'addons/base_dashboard/static/lib/jquery.dashboard/css'
=== added file 'addons/base_dashboard/static/lib/jquery.dashboard/css/dashboardui.css'
--- addons/base_dashboard/static/lib/jquery.dashboard/css/dashboardui.css 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/static/lib/jquery.dashboard/css/dashboardui.css 2011-04-29 08:50:52 +0000
@@ -0,0 +1,261 @@
+.ui-icon {
+ cursor:default;
+}
+.widgetheader {
+ cursor:move;
+}
+
+#layout-dialog .selected {
+ background: no-repeat scroll 0px -51px transparent;
+}
+#layout-dialog .layoutchoice {
+ width: 82px;
+ height: 51px;
+ float:left;
+ list-style-type:none;
+ margin:5px;
+ padding:0;
+}
+.selectedcolumn {
+ border: 3px dashed #aaaaaa;
+}
+.emptycolumn {
+ font-size:20px;
+ font-weight:bold;
+ color: #aaaaaa;
+ padding: 5px 5px 5px 5px;
+}
+
+.dashboard {
+ margin-top: 5px;
+}
+.right {
+ float:right;
+}
+.widgetheader {
+ padding:2px 2px 5px 5px;
+}
+.ui-icon {
+ float:left;
+}
+.widgetcontent {
+ padding:2px 2px 5px 5px;
+}
+.widget {
+ margin-bottom:10px;
+}
+.column {
+ float:left;
+ margin:0 1% -1.5em;
+ padding:0;
+ width:47.5%;
+}
+
+.layout-a .column {
+width:98%;
+}
+.layout-a .column.second, .layout-a .column.third {
+display:none;
+}
+.layout-aa .column {
+width:47.5%;
+}
+.layout-aa .third {
+display:none;
+}
+.layout-ba .column {
+width:68%;
+}
+.layout-ba .first {
+width:27%;
+}
+.layout-ba .third {
+display:none;
+}
+.layout-ab .column {
+width:27%;
+}
+.layout-ab .first {
+width:68%;
+}
+.layout-ab .third {
+display:none;
+}
+.layout-aaa .column {
+ width:30.9%;
+}
+
+body {
+ margin:0;
+ color:#333333;
+ font:12px/1.4 arial,FreeSans,Helvetica,sans-serif;
+}
+
+.headerlink {
+ color:#ffffff;
+}
+
+.headerlinks {
+ text-align:right;
+ margin-right:20px;
+ line-height:24px;
+ text-decoration:underline;
+ font-weight:bold;
+}
+
+.headerbox {
+ height:148px;
+}
+
+.ui-widget-overlay {
+ opacity:0.5;
+}
+
+/*.loading {
+ padding: 50px;
+ text-align: center;
+ background-image:loading.gif;
+}*/
+
+
+#layout-dialog ul {
+ margin:0;
+ padding:0;
+}
+
+#layout-dialog ul li a, #layout-dialog ul li a:link, #layout-dialog ul li a:visited {
+ border:1px solid #BBBBBB;
+ display:block;
+ float:left;
+ margin:0 1em 1em 0;
+ outline:medium none;
+ padding:0.35em;
+ width:auto;
+}
+
+.hidden {
+ display:none;
+}
+
+.controls {
+ border:1px solid #BBBBBB;
+ float:none;
+ margin:0;
+ padding:4px 0;
+}
+
+.controls {
+ width:100px;
+ background:none repeat scroll 0 0 #dddddd;
+ border:1px solid #6A8EB3;
+ color:#000000;
+ margin-top:-1px;
+ padding:4px 0;
+ position:absolute;
+ right:0;
+ z-index:2003;
+}
+
+.controls li {
+ float:none;
+ margin:0;
+ padding:0;
+ list-style-type:none;
+ margin:0 0 0 0.2em;
+ width:auto;
+ position:static;
+}
+
+.controls li a {
+ color:#000000;
+ font-weight:normal;
+ float:none;
+ margin:0;
+ text-decoration:none;
+ width:auto;
+ padding-left:5px;
+}
+
+.hiddenmenu {
+ position:relative;
+}
+
+.dialog .categories {
+ list-style:none outside none;
+ height: 414px;
+}
+
+.dialog .categories li.selected button {
+ color:#FFFFFF;
+ font-weight:800;
+}
+.dialog .categories li button {
+ background:none repeat scroll 0 0 transparent;
+ border:medium none;
+ color:#666666;
+ font-family:"segoe ui",helvetica,arial,sans-serif;
+ font-size:0.8em;
+ padding:0.4em 1.2em;
+ text-align:left;
+ width:100%;
+}
+ul.categories button {
+ cursor:pointer;
+}
+
+.widgetitem {
+ border:2px none white;
+ float:left;
+ font-size:0.77em;
+ height:142px;
+ margin:0;
+ overflow:hidden;
+ padding:0 20px 0 142px;
+ width:152px;
+}
+
+ol.widgets {
+ float:left;
+ list-style:none outside none;
+ margin:-10px;
+ padding:0;
+ width:auto;
+}
+
+.dialog .panel-body {
+ overflow:auto;
+ padding:10px;
+}
+
+.dialog .categories {
+ background:none repeat scroll 0 0 #FFFFFF;
+ border-right:1px solid #F0F0F0;
+ float:left;
+ height:100%;
+ list-style:none outside none;
+ margin:0 1.17em 0 0;
+ padding:10px 0 0;
+ width:25%;
+}
+
+.dialog .categories li.selected {
+ background:none repeat scroll 0 0 #6699CC;
+ color:#FFFFFF;
+}
+
+.widgetitem .add-button {
+ float:left;
+ margin:81px 0 0 -131px;
+ width:auto;
+}
+
+.widgetitem h3 {
+ margin:11px 0 0;
+ padding:0;
+}
+
+.widgetitem img {
+ border:1px solid #999999;
+ float:left;
+ margin:10px 0 0 -132px;
+}
\ No newline at end of file
=== added directory 'addons/base_dashboard/static/lib/jquery.dashboard/js'
=== added file 'addons/base_dashboard/static/lib/jquery.dashboard/js/jquery.dashboard.js'
--- addons/base_dashboard/static/lib/jquery.dashboard/js/jquery.dashboard.js 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/static/lib/jquery.dashboard/js/jquery.dashboard.js 2011-04-29 08:50:52 +0000
@@ -0,0 +1,936 @@
+/*
+ * dashboard 1.0
+ * http://www.gxdeveloperweb.com/dashboard/
+ *
+ * Copyright (c) 2010 Mark Machielsen
+ *
+ * Dual licensed under the MIT and GPL licenses (same as jQuery):
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+
+(function($) { // Create closure.
+
+ // Constructor for dashboard object.
+ $.fn.dashboard = function(options) {
+ // Public properties of dashboard.
+ var dashboard = {};
+ var loading;
+ var widgetDirectoryUrl;
+ dashboard.layout;
+ dashboard.element = this;
+ dashboard.id = this.attr("id");
+ dashboard.widgets = {};
+ dashboard.widgetsToAdd = {};
+ dashboard.widgetCategories = {};
+ dashboard.initialized = false;
+
+ // Public methods
+ dashboard.serialize = function() {
+ dashboard.log('entering serialize function',1);
+ var r = '{"layout": "' + dashboard.layout.id + '", "data" : [';
+ // add al widgets in the right order
+ var i=0;
+ if ($('.' + opts.columnClass).length == 0) dashboard.log(opts.columnClass + ' class not found',5);
+ $('.' + opts.columnClass).each(function() {
+ $(this).children().each(function() {
+ if ($(this).hasClass(opts.widgetClass)) {
+ if (i > 0) { r+= ','; }
+ r+= (dashboard.getWidget($(this).attr("id"))).serialize();
+ i++;
+ }
+ });
+ });
+ r+= ']}';
+ return r;
+ }
+
+ dashboard.log = function(msg, level) {
+ if (level >= opts.debuglevel && typeof console != 'undefined') {
+ var l = '';
+ if (level == 1) l = 'INFO';
+ if (level == 2) l = 'EVENT';
+ if (level == 3) l = 'WARNING';
+ if (level == 5) l = 'ERROR';
+ console.log(l + ' - ' + msg);
+ }
+ }
+
+ dashboard.setLayout = function(layout) {
+ if (layout != null) {
+ dashboard.log('entering setLayout function with layout ' + layout.id,1);
+ } else {
+ dashboard.log('entering setLayout function with layout null',1);
+ }
+ dashboard.layout = layout;
+
+ loading.remove();
+ if (dashboard.layout != null) {
+ if (typeof opts.layoutClass != 'undefined') {
+ this.element.find('.' + opts.layoutClass).addClass(dashboard.layout.classname);
+ } else {
+ this.element.html(dashboard.layout.html);
+ }
+ }
+
+ // make the columns sortable, see http://jqueryui.com/demos/sortable/ for explaination
+ $('.' + opts.columnClass).sortable({
+ connectWith: $('.' + opts.columnClass),
+ opacity: opts.opacity,
+ handle: '.' + opts.widgetHeaderClass,
+ over: function(event, ui) {
+ $(this).addClass("selectedcolumn");
+ },
+ out: function(event, ui) {
+ $(this).removeClass("selectedcolumn");
+ },
+ receive: function(event, ui) {
+ // update the column attribute for the widget
+ var w = dashboard.getWidget(ui.item.attr("id"));
+ w.column = getColumnIdentifier($(this).attr("class"));
+
+ dashboard.log('dashboardStateChange event thrown for widget ' + w.id,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetMoved","widget":w});
+
+ dashboard.log('widgetDropped event thrown for widget ' + w.id,2);
+ w.element.trigger("widgetDropped",{"widget":w});
+ },
+ deactivate: function(event, ui) {
+ // This event is called for each column
+ dashboard.log('Widget is dropped: check if the column is now empty.',1);
+ var childLength = $(this).children().length;
+ if (childLength == 0) {
+ dashboard.log('adding the empty text to the column',1);
+ $(this).html('<div class="emptycolumn">' + opts.emptyColumnHtml + '</div>');
+ } else {
+ if (childLength == 2) {
+ // remove the empty column HTML
+ $(this).find('.emptycolumn').remove();
+ }
+ }
+ },
+ start: function(event, ui) {
+ ui.item.find('.' + opts.widgetTitleClass).addClass('noclick');
+ },
+ stop: function(event, ui) {
+ //sorting changed (within one list)
+ setTimeout(function(){
+ ui.item.find('.' + opts.widgetTitleClass).removeClass('noclick');
+ }, 300);
+ }
+
+ });
+
+ fixSortableColumns();
+
+ // trigger the dashboardLayoutLoaded event
+ dashboard.log('dashboardLayoutLoaded event thrown',2);
+ dashboard.element.trigger("dashboardLayoutLoaded");
+ }
+
+ // This is a workaround for the following problem: when I drag a widget from column2 to column1, sometimes the widget is
+ // moved to column3, which is not visible
+ function fixSortableColumns() {
+ dashboard.log('entering fixSortableColumns function',1);
+ $('.nonsortablecolumn').removeClass('nonsortablecolumn').addClass(opts.columnClass);
+ $('.' + opts.columnClass).filter(function() {return $(this).css("display") == 'none'}).addClass('nonsortablecolumn').removeClass(opts.columnClass);
+ }
+
+ function getColumnIdentifier(classes) {
+ dashboard.log('entering getColumnIdentifier function',1);
+ var r;
+ var s = classes.split(" ");
+ for (var i = 0;i < s.length;i++) {
+ if (s[i].indexOf(opts.columnPrefix) === 0) { r = s[i] };
+ };
+ return r.replace(opts.columnPrefix,'');
+ }
+
+ dashboard.loadLayout = function() {
+ dashboard.log('entering loadLayout function',1);
+ if (typeof opts.json_data.url != 'undefined' && opts.json_data.url.length > 0) {
+ // ajax option
+ dashboard.log('Getting JSON feed : ' + opts.json_data.url,1);
+ $.getJSON(opts.json_data.url, function(json) {
+ if (json == null) {
+ alert('Unable to get json. If you are using chrome: there is an issue with loading json with local files. It works on a server :-)',5);
+ return;
+ }
+ // set the layout
+ var currentLayout = (typeof dashboard.layout != 'undefined') ? dashboard.layout : getLayout(json.layout);
+ dashboard.setLayout(currentLayout);
+ dashboard.loadWidgets(json.data);
+ });
+ } else {
+ // set the layout
+ var currentLayout = (typeof dashboard.layout != 'undefined') ? dashboard.layout : getLayout(opts.json_data.layout);
+ dashboard.setLayout(currentLayout);
+ dashboard.loadWidgets(opts.json_data.data);
+ }
+ };
+
+ dashboard.addWidget = function(obj, column) {
+ dashboard.log('entering addWidget function',1);
+ // add the widget to the column
+ var wid = obj.id;
+
+ // check if the widget is already registered and available in the dom
+ if (typeof dashboard.widgets[wid] != 'undefined' && $('#' + wid).length > 0) {
+ var wi = $('#' + wid);
+ column = dashboard.widgets[wid].column;
+
+ // add it to the column
+ wi.appendTo(column);
+
+ } else {
+ // build the widget
+ dashboard.log('Applying template : ' + opts.widgetTemplate,1);
+ if ($('#' + opts.widgetTemplate).length == 0) dashboard.log('Template "' + opts.widgetTemplate + ' not found',5);
+ var widgetStr = tmpl($('#' + opts.widgetTemplate).html(), obj);
+ var wi = $(widgetStr);
+
+ // add it to the column
+ wi.appendTo(column);
+
+ if(column.find('.emptycolumn').length)
+ column.find('.emptycolumn').remove();
+
+ dashboard.widgets[wid] = widget({
+ id: wid,
+ element: wi,
+ column: obj.column,
+ url: (typeof obj.url != 'undefined' ? obj.url : null),
+ editurl: obj.editurl,
+ title: obj.title,
+ open: obj.open,
+ metadata: obj.metadata
+ });
+ }
+
+ dashboard.log('widgetAdded event thrown for widget ' + wid,2);
+ dashboard.widgets[wid].element.trigger("widgetAdded", {"widget":dashboard.widgets[wid]});
+
+ if (dashboard.initialized) {
+ dashboard.log('dashboardStateChange event thrown for widget ' + wid,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetAdded","widget":wi});
+ }
+ }
+
+ dashboard.loadWidgets = function(data) {
+ dashboard.log('entering loadWidgets function',1);
+ dashboard.element.find('.' + opts.columnClass).empty();
+
+
+ // This is for the manual feed
+ $(data).each(function() {
+ var column = this.column;
+ dashboard.addWidget(this, dashboard.element.find('.' + opts.columnPrefix + column));
+ }); // end loop for widgets
+
+ // check if there are widgets in the temp dashboard which needs to be moved
+ // this is not the correct place, but otherwise we are too late
+
+ // check if there are still widgets in the temp
+ $('#tempdashboard').find('.' + opts.widgetClass).each(function() {
+ // append it to the first column
+ var firstCol = dashboard.element.find('.' + opts.columnClass + ':first');
+ $(this).appendTo(firstCol);
+
+ // set the new column
+ dashboard.getWidget($(this).attr("id")).column = firstCol.attr("id");
+ });
+ $('#tempdashboard').remove();
+
+ // add the text to the empty columns
+ $('.' + opts.columnClass).each(function() {
+ if ($(this).children().length == 0) {
+ $(this).html('<div class="emptycolumn">' + opts.emptyColumnHtml + '</div>');
+ }
+ });
+
+ dashboard.initialized = true;
+ };
+
+ dashboard.init = function() {
+ dashboard.log('entering init function',1);
+ // load the widgets as fast as we can. After that add the binding
+ dashboard.loadLayout();
+ }
+
+ dashboard.getWidget = function(id) {
+ dashboard.log('entering getWidget function',1);
+ var wi = dashboard.widgets[id];
+ if (typeof wi != 'undefined') {
+ return wi;
+ } else {
+ return null;
+ }
+ }
+
+
+ // Merge in the caller's options with the defaults.
+ var opts = $.extend({}, $.fn.dashboard.defaults, options);
+ var addOpts = $.extend({}, $.fn.dashboard.defaults.addWidgetSettings, options.addWidgetSettings);
+ var layoutOpts = $.extend({}, $.fn.dashboard.defaults.editLayoutSettings, options.editLayoutSettings);
+
+ // Execution 'forks' here and restarts in init(). Tell the user we're busy with a loading.
+ var loading = $(opts.loadingHtml).appendTo(dashboard.element);
+
+ /**
+ * widget object
+ * Private sub-class of dashboard
+ * Constructor starts
+ */
+ function widget(widget) {
+
+ dashboard.log('entering widget constructor',1);
+ // Merge default options with the options defined for this widget.
+ widget = $.extend({}, $.fn.dashboard.widget.defaults, widget);
+
+ // public functions
+ widget.openContent = function() {
+ // hide the open link, show the close link
+ widget.element.find('.widgetOpen').hide();
+ widget.element.find('.widgetClose').show();
+
+ dashboard.log('entering openContent function',1);
+ widget.open = true;
+ if (!widget.loaded) {
+ // load the content in the widget if the state == open
+ if (this.url != '' && this.url != null && typeof this.url != 'undefined') {
+ // add the loading
+ $(opts.loadingHtml).appendTo(widget.element.find('.' + opts.widgetContentClass));
+
+ dashboard.log('widgetShow event thrown for widget ' + widget.id,2);
+ widget.element.trigger("widgetShow", {"widget":widget});
+
+ widget.element.find('.' + opts.widgetContentClass).load(this.url, function(response, status, xhr) {
+ if (status == "error") {
+ widget.element.find('.' + opts.widgetContentClass).html(opts.widgetNotFoundHtml);
+ }
+ widget.loaded = true;
+ dashboard.log('widgetLoaded event thrown for widget ' + widget.id,2);
+ widget.element.trigger("widgetLoaded", {"widget":widget});
+ });
+ } else {
+ dashboard.log('widgetShow event thrown for widget ' + widget.id,2);
+ widget.element.trigger("widgetShow", {"widget":widget});
+
+ dashboard.log('widgetLoaded event thrown',2);
+ widget.element.trigger("widgetLoaded", {"widget":widget});
+ }
+ } else {
+ dashboard.log('widgetShow event thrown for widget ' + widget.id,2);
+ widget.element.trigger("widgetShow", {"widget":widget});
+ }
+ if (dashboard.initialized) {
+ dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetOpened","widget":widget});
+ }
+ };
+ widget.refreshContent = function() {
+ dashboard.log('entering refreshContent function',1);
+ widget.loaded = false;
+ if (widget.open) {
+ widget.openContent();
+ }
+ }
+ widget.setTitle = function(newTitle){
+ dashboard.log('entering setTitle function',1);
+ widget.title=newTitle;
+ widget.element.find('.' + opts.widgetTitleClass).html(newTitle);
+ if (dashboard.initialized) {
+ dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"titleChanged","widget":widget});
+ }
+ }
+ widget.closeContent = function() {
+ dashboard.log('entering closeContent function',1);
+ widget.open = false;
+
+ dashboard.log('widgetHide event thrown for widget ' + widget.id,2);
+ widget.element.trigger("widgetHide", {"widget":widget});
+
+ // show the open link, hide the close link
+ widget.element.find('.widgetOpen').show();
+ widget.element.find('.widgetClose').hide();
+
+ dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetClosed","widget":widget});
+ };
+ widget.addMetadataValue = function(name, value) {
+ dashboard.log('entering addMetadataValue function',1);
+ if (typeof widget.metadata == 'undefined') {
+ widget.metadata = {};
+ }
+ widget.metadata[name] = value;
+ dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"metadataChanged","widget":widget});
+ };
+ widget.openMenu = function() {
+ dashboard.log('entering openMenu function',1);
+ widget.element.find('.' + opts.menuClass).show();
+ };
+ widget.closeMenu = function() {
+ dashboard.log('entering closeMenu function',1);
+ widget.element.find('.' + opts.menuClass).hide();
+ };
+ widget.remove = function() {
+ dashboard.log('entering remove function',1);
+ widget.element.remove();
+ dashboard.log('widgetDeleted event thrown for widget ' + widget.id,2);
+ widget.element.trigger('widgetDeleted', {"widget":widget});
+
+ dashboard.log('dashboardStateChange event thrown for widget ' + widget.id,2);
+ dashboard.element.trigger("dashboardStateChange",{"stateChange":"widgetRemoved","widget":widget});
+ };
+ widget.serialize = function() {
+ dashboard.log('entering serialize function',1);
+ var r = '{"title" : "' + widget.title + '", "id" : "' + widget.id + '", "column" : "' + widget.column + '","editurl" : "' + widget.editurl + '","open" : ' + widget.open + ',"url" : "' + widget.url + '"';
+
+ if (typeof widget.metadata != 'undefined') {
+ r+= ',"metadata":{'
+ var obj = widget.metadata;
+ var i=0;
+ for(var item in obj) {
+ if (i > 0) { r+= ',' };
+
+ // FIXME: support for more than string, eg numbers subobjects
+ r+= '"' + item + '":"' + obj[item] + '"';
+ i++;
+ }
+ r+= '}'
+
+ }
+
+ r += '}';
+ return r;
+ };
+ widget.openFullscreen = function() {
+ dashboard.log('entering openFullscreen function',1);
+ widget.fullscreen = true;
+
+ // create a clone
+ var clone = widget.element.clone();
+
+ // move the dashboard
+ var temp = $('<div style="display:none" id="tempdashboard_' + dashboard.id + '"></div>');
+ temp.appendTo($("body"));
+ dashboard.element.children().appendTo(temp);
+
+ // add the clone to the dashboard
+ var fs = $('<ul id="fullscreen_' + dashboard.id + '"></ul>');
+ fs.appendTo(dashboard.element);
+ clone.appendTo(fs);
+
+ };
+ widget.closeFullscreen = function() {
+ dashboard.log('entering closeFullscreen function',1);
+ widget.fullscreen = false;
+
+ // remove the fullscreen
+ $('#fullscreen_' + dashboard.id).remove();
+
+ // move the content from the tempdashboard back
+ $('#tempdashboard_' + dashboard.id).children().appendTo(dashboard.element);
+ $('#tempdashboard_' + dashboard.id).remove();
+
+ };
+ widget.openSettings = function() {
+ dashboard.log('entering openSettings function',1);
+ widget.element.find('.' + opts.widgetContentClass).load(widget.editurl);
+ };
+
+ // called when widget is initialized
+ if (widget.open) {
+ widget.openContent();
+ }
+
+ widget.initialized = true;
+
+ dashboard.log('widgetInitialized event thrown',2);
+ widget.element.trigger("widgetInitialized", {"widget":widget});
+
+ return widget;
+ };
+
+
+ // FIXME: can this be done easier??
+ function getLayout(id) {
+ dashboard.log('entering getLayout function',1);
+ var r = null;
+ var first = null;
+ if (typeof opts.layouts != 'undefined') {
+
+ $.each(opts.layouts,function(i, item) {
+ if (i == 0) { first = item; }
+ if (item.id == id) {
+ r = item;
+ }
+ });
+ }
+ if (r == null) { r = first }
+ return r;
+ }
+
+
+ $('#' + dashboard.id + ' .menutrigger').live('click', function() {
+ dashboard.log('widgetOpenMenu event thrown for widget ' + widget.id,2);
+ var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
+
+ wi.element.trigger('widgetOpenMenu', {"widget":wi});
+ return false;
+ });
+
+ // add event handlers to the menu
+ $('#' + dashboard.id + ' .' + opts.widgetFullScreenClass).live('click',function(e) {
+ // close the menu
+ dashboard.log('widgetCloseMenu event thrown for widget ' + widget.id,2);
+ var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
+ wi.element.trigger('widgetCloseMenu', {"widget":wi});
+
+ if (wi.fullscreen) {
+ dashboard.log('widgetCloseFullScreen event thrown for widget ' + wi.id,2);
+ wi.element.trigger('widgetCloseFullScreen', {"widget":wi});
+ } else {
+ dashboard.log('widgetOpenFullScreen event thrown for widget ' + wi.id,2);
+ wi.element.trigger('widgetOpenFullScreen', {"widget":wi});
+ }
+ return false;
+ });
+
+ $('#' + dashboard.id + ' .controls li').live('click',function(e) {
+ // close the menu
+ dashboard.log('widgetCloseMenu event thrown for widget ' + widget.id,2);
+
+ var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
+ wi.element.trigger('widgetCloseMenu', {"widget":wi});
+
+ // use the class on the li to determine what action to trigger
+ dashboard.log($(this).attr('class') + ' event thrown for widget ' + widget.id,2);
+
+ var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
+ wi.element.trigger($(this).attr('class'), {"widget":wi});
+ return false;
+ });
+
+ // add the menu events (by default triggers are connected in dashboard_jsonfeed)
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetCloseMenu',function(e,o) {
+ dashboard.log("Closing menu " + $(this).attr("id"),1);
+ o.widget.closeMenu();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetOpenMenu',function(e,o) {
+ dashboard.log("Opening menu " + $(this).attr("id"),1);
+ o.widget.openMenu();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetDelete',function(e,o) {
+ if (confirm(opts.deleteConfirmMessage)) {
+ dashboard.log("Removing widget " + $(this).attr("id"),1);
+ o.widget.remove();
+ }
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetRefresh',function(e,o) {
+ o.widget.refreshContent();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetSetTitle',function(event, o) {
+ o.widget.setTitle(o.title);
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetClose',function(e,o) {
+ dashboard.log("Closing widget " + $(this).attr("id"),1);
+ o.widget.closeContent();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetOpen',function(e,o) {
+ dashboard.log("Opening widget " + $(this).attr("id"),1);
+ o.widget.openContent();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetShow',function() {
+ $(this).find('.' + opts.widgetContentClass).show();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetHide',function() {
+ $(this).find('.' + opts.widgetContentClass).hide();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetAddMetadataValue',function(e,o) {
+ dashboard.log("Changing metadata for widget " + $(this).attr("id") + ", metadata name: " + o.name + ", value: " + o.value, 1);
+ o.widget.addMetadataValue(o.name, o.value);
+ });
+
+ // Define a toggle event when clicking at the header
+ $('#' + dashboard.id + ' .' + opts.widgetTitleClass).live('click',function(e) {
+ dashboard.log("Click on the header detected for widget " + $(this).attr("id"),1);
+ if (!$(this).hasClass('noclick')) {
+ var wi = dashboard.getWidget($(this).closest('.' + opts.widgetClass).attr("id"));
+ if (wi.open) {
+ dashboard.log('widgetClose event thrown for widget ' + wi,2);
+ wi.element.trigger('widgetClose', {"widget":wi});
+ } else {
+ dashboard.log('widgetOpen event thrown for widget ' + wi,2);
+ wi.element.trigger('widgetOpen', {"widget":wi});
+ }
+ }
+ return false;
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetHeaderClass).live('mouseover',function () {
+ $(this).find('.' + opts.iconsClass).removeClass("hidden");
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetHeaderClass).live('mouseout', function () {
+ $(this).find('.' + opts.iconsClass).addClass("hidden");
+ });
+
+ $('body').click(function() {
+ $('.' + opts.menuClass).hide();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetOpenFullScreen',function(e,o) {
+ o.widget.openFullscreen();
+ });
+
+ $('.' + opts.widgetClass).live('widgetCloseFullScreen',function(e,o) {
+ o.widget.closeFullscreen();
+ });
+
+ $('#' + dashboard.id + ' .' + opts.widgetClass).live('widgetEdit',function(e,o) {
+ o.widget.openSettings();
+ });
+
+ if ($('#' + addOpts.dialogId).length == 0) dashboard.log('Unable to find ' + addOpts.dialogId,5);
+ $('#' + addOpts.dialogId).dialog({
+ autoOpen: false,
+ height: 414,
+ width: 550,
+ modal: true,
+ buttons: {
+ Cancel: function() {
+ $(this).dialog('close');
+ }
+ },
+ close: function() {
+ //close
+ }
+ });
+
+ if ($('#' + layoutOpts.dialogId).length == 0) dashboard.log('Unable to find ' + layoutOpts.dialogId,5);
+ $('#' + layoutOpts.dialogId).dialog({
+ autoOpen: false,
+ height: 300,
+ width: 600,
+ modal: true
+ });
+
+ $('.' + layoutOpts.openDialogClass).live('click', function(){
+ dashboard.log('dashboardOpenLayoutDialog event thrown',2);
+ dashboard.element.trigger("dashboardOpenLayoutDialog");
+ return false;
+ });
+
+ dashboard.element.live('dashboardOpenLayoutDialog', function(){
+ dashboard.log('Opening dialog ' + layoutOpts.dialogId,1);
+ $('#' + layoutOpts.dialogId).dialog('open');
+
+ // add the layout images
+ var h = $('#' + layoutOpts.dialogId).find('.' + layoutOpts.layoutClass);
+ h.empty();
+ if (h.children().length == 0) {
+ dashboard.log('Number of layouts : ' + opts.layouts.length,1);
+ $.each(opts.layouts,function(i, item) {
+ dashboard.log('Applying template : ' + layoutOpts.layoutTemplate,1);
+ if ($('#' + layoutOpts.layoutTemplate).length == 0) dashboard.log('Template "' + layoutOpts.layoutTemplate + ' not found',5);
+ h.append(tmpl($('#' + layoutOpts.layoutTemplate).html(), item));
+ });
+ }
+
+ // set the selected class for the selected layout
+ $('.' + layoutOpts.selectLayoutClass).removeClass(layoutOpts.selectedLayoutClass);
+ $('#' + dashboard.layout.id).addClass(layoutOpts.selectedLayoutClass);
+
+ bindSelectLayout();
+ });
+
+
+ dashboard.element.live('dashboardStateChange', function(){
+ if (typeof opts.stateChangeUrl != 'undefined' && opts.stateChangeUrl != null && opts.stateChangeUrl != '') {
+ $.ajax({type: 'POST',
+ url: opts.stateChangeUrl,
+ data: { dashboard: dashboard.element.attr("id"), settings: dashboard.serialize() },
+ success: function(data){
+ if (data == "NOK" || data.indexOf('<response>NOK</response>') != -1){
+ dashboard.log('dashboardSaveFailed event thrown',2);
+ dashboard.element.trigger("dashboardSaveFailed");
+ } else {
+ dashboard.log('dashboardSuccessfulSaved event thrown',2);
+ dashboard.element.trigger("dashboardSuccessfulSaved");
+ }
+ },
+ error: function(XMLHttpRequest, textStatus, errorThrown){
+ dashboard.log('dashboardSaveFailed event thrown',2);
+ dashboard.element.trigger("dashboardSaveFailed");
+ },
+ dataType: "text"
+ });
+ }
+ });
+
+
+ dashboard.element.live('dashboardCloseLayoutDialog', function(){
+ // close the dialog
+ $('#' + layoutOpts.dialogId).dialog('close');
+ });
+
+ // FIXME: why doesn't the live construct work in this case
+ function bindSelectLayout() {
+ if ($('.' + layoutOpts.selectLayoutClass).length == 0) dashboard.log('Unable to find ' + layoutOpts.selectLayoutClass,5);
+ $('.' + layoutOpts.selectLayoutClass).bind('click', function(e){
+ var currentLayout = dashboard.layout;
+
+ dashboard.log('dashboardCloseLayoutDialog event thrown',2);
+ dashboard.element.trigger('dashboardCloseLayoutDialog');
+
+ // Now set the new layout
+ var newLayout = getLayout($(this).attr("id"));
+ dashboard.layout = newLayout;
+
+ // remove the class of the old layout
+ if (typeof opts.layoutClass != 'undefined') {
+ dashboard.element.find('.' + opts.layoutClass).removeClass(currentLayout.classname).addClass(newLayout.classname);
+
+ fixSortableColumns();
+
+ // check if there are widgets in hidden columns, move them to the first column
+ if ($('.' + opts.columnClass).length == 0) dashboard.log('Unable to find ' + opts.columnClass,5);
+ dashboard.element.find('.' + opts.columnClass).each(function() {
+ if ($(this).css("display") == "none") {
+ // move the widgets to the first column
+ $(this).children().appendTo(dashboard.element.find('.' + opts.columnClass + ':first'));
+ }
+
+ $('.emptycolumn').remove();
+ // add the text to the empty columns
+ $('.' + opts.columnClass).each(function() {
+ if ($(this).children().length == 0) {
+ $(this).html('<div class="emptycolumn">' + opts.emptyColumnHtml + '</div>');
+ }
+ });
+
+
+ });
+
+ } else {
+ // set the new layout, but first move the dashboard to a temp
+ var temp = $('<div style="display:none" id="tempdashboard"></div>');
+ temp.appendTo($("body"));
+
+ dashboard.element.children().appendTo(temp);
+
+ // reload the dashboard
+ dashboard.init();
+ }
+
+ // throw an event upon changing the layout.
+ dashboard.log('dashboardChangeLayout event thrown',2);
+ dashboard.element.trigger('dashboardLayoutChanged');
+
+ });
+ return false;
+ }
+
+ $('.' + addOpts.selectCategoryClass).live('click', function(){
+ dashboard.log('addWidgetDialogSelectCategory event thrown',2);
+ dashboard.element.trigger('addWidgetDialogSelectCategory', {"category":$(this)});
+ return false;
+ });
+
+ dashboard.element.live('addWidgetDialogSelectCategory', function(e, obj){
+ // remove the category selection
+ $('.' + addOpts.selectCategoryClass).removeClass(addOpts.selectedCategoryClass);
+
+ // empty the widgets div
+ $('#' + addOpts.dialogId).find('.' + addOpts.widgetClass).empty();
+
+ // select the category
+ $(obj.category).addClass(addOpts.selectedCategoryClass);
+
+ // get the widgets
+ url = dashboard.widgetCategories[$(obj.category).attr("id")];
+
+ dashboard.log('Getting JSON feed : ' + url,1);
+ $.getJSON(url, {"cache":true}, function(json) {
+ // load the widgets from the category
+ if (json.data == 0) dashboard.log('Empty data returned',3);
+ $.each(json.data, function(i,item){
+ dashboard.widgetsToAdd[item.id] = item;
+
+ dashboard.log('Applying template : ' + addOpts.widgetTemplate,1);
+ if ($('#' + addOpts.widgetTemplate).length == 0) dashboard.log('Template "' + addOpts.widgetTemplate + ' not found',5);
+ var html = tmpl($('#' + addOpts.widgetTemplate).html(), item);
+ $('#' + addOpts.dialogId).find('.' + addOpts.widgetClass).append(html);
+ });
+ });
+
+ dashboard.log('addWidgetDialogWidgetsLoaded event thrown',2);
+ dashboard.element.trigger('addWidgetDialogWidgetsLoaded');
+ });
+
+
+ $('.' + addOpts.addWidgetClass).live('click', function(){
+ var widget = dashboard.widgetsToAdd[$(this).attr("id").replace('addwidget','')];
+ dashboard.log('dashboardAddWidget event thrown',2);
+ dashboard.element.trigger('dashboardAddWidget', {"widget":widget});
+
+ dashboard.log('dashboardCloseWidgetDialog event thrown',2);
+ dashboard.element.trigger('dashboardCloseWidgetDialog');
+ return false;
+ });
+
+ $('.' + addOpts.openDialogClass).live('click', function(){
+ dashboard.log('dashboardOpenWidgetDialog event thrown',2);
+ dashboard.element.trigger('dashboardOpenWidgetDialog');
+ return false;
+ });
+
+ dashboard.element.live('dashboardCloseWidgetDialog', function(){
+ // close the dialog
+ $('#' + addOpts.dialogId).dialog('close');
+ });
+
+ dashboard.element.live('dashboardOpenWidgetDialog', function(){
+
+ //remove existing categories/widgets from the DOM, to prevent duplications
+ $('#' + addOpts.dialogId).find('.' + addOpts.categoryClass).empty();
+ $('#' + addOpts.dialogId).find('.' + addOpts.widgetClass).empty();
+
+ dashboard.log('Opening dialog ' + addOpts.dialogId,1);
+ $('#' + addOpts.dialogId).dialog('open');
+
+ dashboard.log('Getting JSON feed : ' + addOpts.widgetDirectoryUrl,1);
+ $.getJSON(addOpts.widgetDirectoryUrl, function(json) {
+ if (json.category == 0) dashboard.log('Empty data returned',3);
+ $.each(json.category, function(i,item){
+ // Add the categories to the dashboard
+ dashboard.widgetCategories[item.id] = item.url;
+
+ dashboard.log('Applying template : ' + addOpts.categoryTemplate,1);
+ if ($('#' + addOpts.categoryTemplate).length == 0) dashboard.log('Template "' + addOpts.categoryTemplate + ' not found',5);
+ var html = tmpl($('#' + addOpts.categoryTemplate).html(),item);
+ $('#' + addOpts.dialogId).find('.' + addOpts.categoryClass).append(html);
+ });
+ dashboard.log('addWidgetDialogCategoriesLoaded event thrown',2);
+ dashboard.element.trigger('addWidgetDialogCategoriesLoaded');
+
+ dashboard.log('addWidgetDialogSelectCategory event thrown',2);
+ dashboard.element.trigger('addWidgetDialogSelectCategory', {"category":$('#' + addOpts.dialogId).find('.' + addOpts.categoryClass + '>li:first')});
+
+ });
+
+ });
+
+ return dashboard;
+ };
+
+
+ // Public static properties of dashboard. Default settings.
+ $.fn.dashboard.defaults = {
+ debuglevel:3,
+ json_data: {},
+ loadingHtml: '<div class="loading"><img alt="Loading, please wait" src="../themes/default/loading.gif" /><p>Loading...</p></div>',
+ emptyColumnHtml: 'Drag your widgets here',
+ widgetTemplate: 'widgettemplate',
+ columnPrefix: 'column-',
+ opacity:"0.2",
+ deleteConfirmMessage: "Are you sure you want to delete this widget?",
+ widgetNotFoundHtml: "The content of this widget is not available anymore. You may remove this widget.",
+ columnClass: 'column',
+ widgetClass: 'widget',
+ menuClass: 'controls',
+ widgetContentClass: 'widgetcontent',
+ widgetTitleClass: 'widgettitle',
+ widgetHeaderClass: 'widgetheader',
+ widgetFullScreenClass: 'widgetopenfullscreen',
+ iconsClass: 'icons',
+ stateChangeUrl: '',
+
+ addWidgetSettings: {
+ openDialogClass: 'openaddwidgetdialog',
+ addWidgetClass: 'addwidget',
+ selectCategoryClass: 'selectcategory',
+ selectedCategoryClass: 'selected',
+ categoryClass: 'categories',
+ widgetClass: 'widgets',
+
+ dialogId: 'addwidgetdialog',
+
+ categoryTemplate: 'categorytemplate',
+ widgetTemplate: 'addwidgettemplate'
+ },
+ editLayoutSettings: {
+ dialogId: 'editLayout',
+ layoutClass: 'layoutselection',
+ selectLayoutClass: 'layoutchoice',
+ selectedLayoutClass: 'selected',
+ openDialogClass: 'editlayout',
+ layoutTemplate: 'selectlayouttemplate'
+ }
+
+
+ };
+
+ // Default widget settings.
+ $.fn.dashboard.widget = {
+ defaults: {
+ open: true,
+ fullscreen: false,
+ loaded: false,
+ url: '',
+ metadata: {}
+ }
+ };
+
+})(jQuery); // end of closure
+
+
+// Simple JavaScript Templating
+// John Resig - http://ejohn.org/ - MIT Licensed
+(function(){
+ var cache = {};
+
+ this.tmpl = function tmpl(str, data){
+ // Figure out if we're getting a template, or if we need to
+ // load the template - and be sure to cache the result.
+
+ var fn = !/\W/.test(str) ?
+ cache[str] = cache[str] ||
+ tmpl(document.getElementById(str).innerHTML) :
+
+ // Generate a reusable function that will serve as a template
+ // generator (and which will be cached).
+ new Function("obj",
+ "var p=[],print=function(){p.push.apply(p,arguments);};" +
+
+ // Introduce the data as local variables using with(){}
+ "with(obj){p.push('" +
+
+ // Convert the template into pure JavaScript
+ str
+ .replace(/[\r\t\n]/g, " ")
+ .split("<%").join("\t")
+ .replace(/((^|%>)[^\t]*)'/g, "$1\r")
+ .replace(/\t=(.*?)%>/g, "',$1,'")
+ .split("\t").join("');")
+ .split("%>").join("p.push('")
+ .split("\r").join("\\'")
+ + "');}return p.join('');");
+
+ // Provide some basic currying to the user
+ return data ? fn( data ) : fn;
+ };
+})();
\ No newline at end of file
=== added directory 'addons/base_dashboard/static/src'
=== added file 'addons/base_dashboard/static/src/dashboard_template.html'
--- addons/base_dashboard/static/src/dashboard_template.html 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/static/src/dashboard_template.html 2011-04-29 08:50:52 +0000
@@ -0,0 +1,85 @@
+<script type="text/html" id="categorytemplate">
+ <li id="<%= id %>" class="selectcategory"><button><%= title %> (<%= amount %>)</button></li>
+</script>
+
+
+<script type="text/html" id="widgettemplate">
+ <div class="ui-widget ui-corner-all ui-widget-content widget" id="<%= id %>" title="<%= title %>">
+ <div class="ui-widget-header ui-corner-all widgetheader">
+ <span class="widgettitle"><%= title %></span>
+ <span class="right icons hidden">
+ <span class="ui-icon ui-icon-newwin widgetopenfullscreen"></span>
+ <span class="ui-icon ui-icon-arrowthickstop-1-s menutrigger"></span>
+ <span class="hiddenmenu">
+ <ul style="top: 13px;" class="hidden controls ui-widget-header">
+ <li class="widgetClose">
+ <span class="ui-icon ui-icon-minus"></span>
+ <a class="minimization" href="#">Minimize</a>
+ </li>
+ <li class="widgetOpen">
+ <span class="ui-icon ui-icon-extlink"></span>
+ <a class="minimization" href="#">Maximize</a>
+ </li>
+ <li class="widgetDelete">
+ <span class="ui-icon ui-icon-close"></span>
+ <a class="delete" href="#">Delete</a>
+ </li>
+ <!-- This could be implemented -->
+ <!--
+ <li class="widgetEdit">
+ <span class="ui-icon ui-icon-tag"></span>
+ <a class="no_target" href="#">Edit</a>
+ </li>
+ -->
+ <li class="widgetRefresh">
+ <span class="ui-icon ui-icon-arrowrefresh-1-w"></span>
+ <a class="no_target" href="#">Refresh</a>
+ </li>
+ </ul>
+ </span>
+ </span>
+ </div>
+ <div class="widgetcontent">
+ </div>
+ </div>
+</script>
+
+<script type="text/html" id="selectlayouttemplate">
+ <li class="layoutchoice" id="<%= id %>" style="background-image: url('<%= image %>')"></li>
+</script>
+
+<script type="text/html" id="addwidgettemplate">
+
+ <li class="widgetitem">
+ <img src="<%= image %>" alt="" height="60" width="120">
+ <div class="add-button">
+ <input class="macro-button-add addwidget" id="addwidget<%= id %>" value="Add it Now" type="button"><br>
+ <input class="macro-hidden-uri" value="<%= url %>" type="hidden">
+ </div>
+ <!-- // .add-button -->
+ <h3><a href=""><%= title %></a></h3>
+
+ <p>By <%= creator %></p>
+ <p><%= description %></p>
+ </li>
+
+</script>
+
+<div class="dialog" id="addwidgetdialog" title="Widget Directory">
+ <ul class="categories">
+ </ul>
+
+ <div class="panel-body">
+ <ol id="category-all" class="widgets">
+ </ol>
+ </div>
+</div>
+
+
+<div class="dialog" id="editLayout" title="Edit layout">
+ <div class="panel-body" id="layout-dialog">
+ <p><strong>Choose dashboard layout</strong></p>
+ <ul class="layoutselection">
+ </ul>
+ </div>
+</div>
\ No newline at end of file
=== added directory 'addons/base_dashboard/static/src/js'
=== added file 'addons/base_dashboard/static/src/js/dashboard.js'
--- addons/base_dashboard/static/src/js/dashboard.js 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/static/src/js/dashboard.js 2011-04-29 08:50:52 +0000
@@ -0,0 +1,104 @@
+openerp.base_dashboard = function(openerp){
+
+QWeb.add_template('/base_dashboard/static/src/xml/base_dashboard.xml');
+
+openerp.base.form.Board = openerp.base.form.Widget.extend({
+ init: function(view, node) {
+
+ this._super(view, node);
+ this.template = "Board";
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.$element.html(QWeb.render(this.template));
+ },
+
+ render: function() {
+ var self = this;
+ jQuery('body').append(
+ jQuery('<div>', {'id': 'dashboard_template'}).load('/base_dashboard/static/src/dashboard_template.html',self.on_loaded).hide()
+ )
+ },
+
+ on_loaded: function() {
+ var children = this.node.children;
+ var board = jQuery('#dashboard').dashboard({
+ layoutClass:'layout'
+ });
+ board.init();
+ for(var ch = 0; ch < children.length; ch++) {
+ var ch_widgets = children[ch].children;
+ for(var chld = 0; chld < ch_widgets.length; chld++) {
+ var widget_type = ch_widgets[chld].tag;
+ var child_index = widget_type == 'action' ? chld : ch;
+ var widget = new (openerp.base.form.widgets.get_object(widget_type)) (this.view, ch_widgets[chld], board, child_index);
+ widget.start();
+ }
+ }
+ }
+});
+
+openerp.base.form.Action = openerp.base.form.Widget.extend({
+ init: function(view, node, board, child_index) {
+ this._super(view, node, board, child_index);
+ this.board = board;
+ this.child_index = child_index;
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ this.rpc('/base_dashboard/dashboard/load',{
+ node_attrs: this.node.attrs
+ },
+ this.on_load_action);
+ },
+
+ on_load_action: function(result) {
+ var action = result.action;
+
+ action.search_view = false;
+ action.no_sidebar = true;
+ action.search_view_id = false;
+
+ var node_attrs = this.node.attrs;
+ var get_column = ['first', 'second', 'third'];
+ var board_element = this.board.element.find('[id=column-'+get_column[this.child_index]+']');
+
+ this.board.addWidget({
+ 'id': node_attrs.name,
+ 'title': node_attrs.string,
+ }, board_element);
+
+ var content_id = node_attrs.name+'-widgetcontent';
+ this.board.getWidget(node_attrs.name).element.find('.widgetcontent').attr('id',content_id)
+
+ action_manager = new openerp.base.ActionManager(this.session, content_id);
+ action_manager.start();
+ this.board.getWidget(node_attrs.name).url = action_manager.do_action(action);
+ }
+})
+
+openerp.base.form.Vpaned = openerp.base.form.Widget.extend({
+ init: function(view, node, board, child_index) {
+
+ this._super(view, node, board, child_index);
+ this.board = board;
+ this.child_index = child_index;
+ },
+ start: function() {
+ this._super.apply(this, arguments);
+ var children = this.node.children;
+ for(var chld=0; chld<children.length; chld++) {
+ var ch_widget = children[chld].children;
+ for(var ch=0; ch<ch_widget.length; ch++) {
+ var widget_type = ch_widget[ch].tag;
+ var widget = new (openerp.base.form.widgets.get_object(widget_type)) (this.view, ch_widget[ch], this.board, this.child_index);
+ widget.start();
+ }
+ }
+ },
+})
+
+openerp.base.form.widgets.add('hpaned', 'openerp.base.form.Board');
+openerp.base.form.widgets.add('vpaned', 'openerp.base.form.Vpaned');
+openerp.base.form.widgets.add('action', 'openerp.base.form.Action');
+}
\ No newline at end of file
=== added directory 'addons/base_dashboard/static/src/xml'
=== added file 'addons/base_dashboard/static/src/xml/base_dashboard.xml'
--- addons/base_dashboard/static/src/xml/base_dashboard.xml 1970-01-01 00:00:00 +0000
+++ addons/base_dashboard/static/src/xml/base_dashboard.xml 2011-04-29 08:50:52 +0000
@@ -0,0 +1,12 @@
+<template>
+ <t t-name="Board">
+ <div id="dashboard" class="dashboard">
+ <!-- this HTML covers all layouts. The 5 different layouts are handled by setting another layout classname -->
+ <div class="layout">
+ <div id="column-first" class="column first column-first"></div>
+ <div id="column-second" class="column second column-second"></div>
+ <div id="column-third" class="column third column-third"></div>
+ </div>
+ </div>
+ </t>
+</template>
\ No newline at end of file
Follow ups