How to add an external jQuery plugin to the list view on Odoo? - odoo-8

I am using Odoo 10e. I want to integrate a jquery plugin into my module.
I want to integrate the jQuery plugin jquery-resizable-columns. It simple helps user to resize columns of table on the fly and I want to apply this on a specific model's list view
Which method should I extend in order to add the plugin?

I think you should extend (maybe include) some widget in the web module. If you go to the file /addons/web/static/src/js/view_list.js, you can see the widget that renders the table:
instance.web.ListView = instance.web.View.extend( /** #lends instance.web.ListView# */ {
_template: 'ListView',
display_name: _lt('List'),
defaults: {
// records can be selected one by one
'selectable': true,
// list rows can be deleted
'deletable': false,
// whether the column headers should be displayed
'header': true,
// display addition button, with that label
'addable': _lt("Create"),
// whether the list view can be sorted, note that once a view has been
// sorted it can not be reordered anymore
'sortable': true,
// whether the view rows can be reordered (via vertical drag & drop)
'reorderable': true,
'action_buttons': true,
//whether the editable property of the view has to be disabled
'disable_editable_mode': false,
},
view_type: 'tree',
events: {
'click thead th.oe_sortable[data-id]': 'sort_by_column'
},
// [...]
sort_by_column: function (e) {
e.stopPropagation();
var $column = $(e.currentTarget);
var col_name = $column.data('id');
var field = this.fields_view.fields[col_name];
// test whether the field is sortable
if (field && !field.sortable) {
return false;
}
this.dataset.sort(col_name);
if($column.hasClass("sortdown") || $column.hasClass("sortup")) {
$column.toggleClass("sortup sortdown");
} else {
$column.addClass("sortdown");
}
$column.siblings('.oe_sortable').removeClass("sortup sortdown");
this.reload_content();
},
As you can see there is an event declared as sort_by_column, so you would have to add the plugin you want in a similar way.
And if you have any doubts inheriting and modifying widgets you can go to the Odoo Documentation
And if you are using the version 10 you can check how it is built here
/addons/web/static/src/js/views/list_view.js

In .js file you have to first extend particular list view's js. After that give your custom model name in that .js file and run that.

In your case, You need.
Created a new module or modify already custom module
Create file.js and file.xml.
In the file xml you must write this
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet" href="/module_name/static/src/css/css_file.css"/>
<script type="text/javascript" src="/module_name/static/src/js/js_file.js"></script>
</xpath>
</template>
</odoo>
And after you needing extent the list_view.js of Odoo to integrate your plugin.

Related

How to configure beforeShowForm with lib.web.mvc to show non editable columns in add form

Some of my columns are not editable but I want all of the columns to display in the add form.
I was thinking that I can use the "beforeShowForm" event and call a javascript function that will dynamically change the column attribute back to editable so they will show up in the add form.
The typical approach for this is to make fields generally editable and hide them in edit dialog.
You can hide/show fields by looking for table rows which ids are being built like this:
tr_ColumnName
So in case you would have UserName column the id would be like this:
tr_UserName
Assuming you are using jQuery, you can wire-up this to your Lib.Web.Mvc configuration like this:
.Navigator(new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorOptions() { ... },
editActionOptions: new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorEditActionOptions()
{
...
BeforeShowForm : "function(form) { $('#tr_UserName', form).hide(); }"
},
addActionOptions: new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorEditActionOptions()
{
...
BeforeShowForm : "function(form) { $('#tr_UserName', form).show(); }"
}
);
I figured how to use the event beforeShowForm.
Note: I have a using statement at the top of the view, so do not need to use the full namespace
#using Lib.Web.Mvc.JQuery.JqGrid
Here is an example within the Navigator form:
.Navigator(new JqGrid.JqGridNavigatorOptions()
{ Add = true, Edit = false, Delete = false, Search = false },
null,
addActionOptions: new JqGridNavigatorEditActionOptions()
{
Url = Url.Action("Add"),
BeforeShowForm = "function () {$('#bob').jqGrid('setColProp',
'Place', {editable:true})
})

CKEDITOR - how to add permanent onclick event?

I am looking for a way to make the CKEDITOR wysiwyg content interactive. This means for example adding some onclick events to the specific elements. I can do something like this:
CKEDITOR.instances['editor1'].document.getById('someid').setAttribute('onclick','alert("blabla")');
After processing this action it works nice. But consequently if I change the mode to source-mode and then return to wysiwyg-mode, the javascript won't run. The onclick action is still visible in the source-mode, but is not rendered inside the textarea element.
However, it is interesting, that this works fine everytime:
CKEDITOR.instances['editor1'].document.getById('id1').setAttribute('style','cursor: pointer;');
And it is also not rendered inside the textarea element! How is it possible? What is the best way to work with onclick and onmouse events of CKEDITOR content elements?
I tried manually write this by the source-mode:
<html>
<head>
<title></title>
</head>
<body>
<p>
This is some <strong id="id1" onclick="alert('blabla');" style="cursor: pointer;">sample text</strong>. You are using CKEditor.</p>
</body>
</html>
And the Javascript (onclick action) does not work. Any ideas?
Thanks a lot!
My final solution:
editor.on('contentDom', function() {
var elements = editor.document.getElementsByTag('span');
for (var i = 0, c = elements.count(); i < c; i++) {
var e = new CKEDITOR.dom.element(elements.$.item(i));
if (hasSemanticAttribute(e)) {
// leve tlacitko mysi - obsluha
e.on('click', function() {
if (this.getAttribute('class') === marked) {
if (editor.document.$.getElementsByClassName(marked_unique).length > 0) {
this.removeAttribute('class');
} else {
this.setAttribute('class', marked_unique);
}
} else if (this.getAttribute('class') === marked_unique) {
this.removeAttribute('class');
} else {
this.setAttribute('class', marked);
}
});
}
}
});
Filtering (only CKEditor >=4.1)
This attribute is removed because CKEditor does not allow it. This filtering system is called Advanced Content Filter and you can read about it here:
http://ckeditor.com/blog/Upgrading-to-CKEditor-4.1
http://ckeditor.com/blog/CKEditor-4.1-Released
Advanced Content Filter guide
In short - you need to configure editor to allow onclick attributes on some elements. For example:
CKEDITOR.replace( 'editor1', {
extraAllowedContent: 'strong[onclick]'
} );
Read more here: config.extraAllowedContent.
on* attributes inside CKEditor
CKEditor encodes on* attributes when loading content so they are not breaking editing features. For example, onmouseout becomes data-cke-pa-onmouseout inside editor and then, when getting data from editor, this attributes is decoded.
There's no configuration option for this, because it wouldn't make sense.
Note: As you're setting attribute for element inside editor's editable element, you should set it to the protected format:
element.setAttribute( 'data-cke-pa-onclick', 'alert("blabla")' );
Clickable elements in CKEditor
If you want to observe click events in editor, then this is the correct solution:
editor.on( 'contentDom', function() {
var element = editor.document.getById( 'foo' );
editor.editable().attachListener( element, 'click', function( evt ) {
// ...
// Get the event target (needed for events delegation).
evt.data.getTarget();
} );
} );
Check the documentation for editor#contentDom event which is very important in such cases.

jQuery - How to call/bind jquery events for elements added by ajax?

I'm working on an implementation of the jQuery plugin Tag-it! with a product entry form for assigning attributes to products of different type (laptops, tv's, gadgets etc).
The concept is the following:
When adding a new product, first, the user selects the product category from a dropdown for the product being added and a jQuery .change() event is triggered making an ajax call to get all the attributes that are related to that category. For example, if Im adding a TV i want my ajax call to populate 3 inputs for inches, panel type, hdmi whereas, if i'm adding a laptop I want those inputs to be cpu, ram, hdd, screen etc. Tag-it! works with a list of words (in my case, attributes) and an input field for choosing the set of words.
In my case, for each type of attributes I want to populate a separate input field and assign/bind it to/apply tagit plugin (sorry, I dont know how else to explain it).
Javascript:
<script src="../js/tag-it.js" type="text/javascript" charset="utf-8"></script>
<script>
$(function(){
// Sample1: var sampleTags1 = ["red", "green", "blue"];
// Sample2: var sampleTags2 = ["lcd", "plasma", "tft"];
var sampleTags1 = [<?=createTags('name', 'tags', 1)?>];
// createTags($name, $tags, $id) is a PHP function that returnss a list of tags for a given attribute
// Question 1: how do I place this here after a new input is added to the DOM?
$('#myTags').tagit();
//Question 2: for each input added to the DOM I need also to add this block in the javascript:
$('#allowSpacesTags1').tagit({itemName: 'item1', fieldName: 'tags1',
availableTags: sampleTags1, allowSpaces: true
});
$('#removeConfirmationTags').tagit({
availableTags: sampleTags,
removeConfirmation: true
});
});
$(document).ready(function() {
$('#cat_id').change(function(){
$.post('../includes/ajax.php', {
cat_id : $(this).find("option:selected").attr('value')}, function(data) {
$("#tagholder").html(data);
});
});
});
</script>
Ajax returns the following for each call:
<ul id="allowSpacesTags'.$row['ctid'].'"></ul> // $row['ctid'] is the ID for that attribute
which represents the input field for entering the tags/attributes.
Before there's any misunderstanding, I'm not asking how to do this in PHP.
My question is about the way I can dynamically add a var like sampleTags1 and also call the tagit() for each new input that is added to the DOM by ajax. I'll try to give any required information if my question isn't clear enough.
Please look at the questions in the code comments. Thanks!
http://api.jquery.com/live/
with .live( events, handler(eventObject) )
you don't need to attach or re-attach events when content is added dynamically
EDIT
i've just notticed that live is deprecated, instead you should use
.on()
http://api.jquery.com/on/

Custom pager in Telerik MVC Grid

Can i customize appearance of a Grid's pager? I wanna select a page size from list (like Redmine, see 'Per page' block) not from dropdown.
It's standart Telerik's pager:
It's Redmine's pager:
Thanks.
PS for instance Devexpress' Grid has this ability
You could replace the DOM element that is responsible for page size. You need to do it when grid is loaded.
View
#Html.Telerik().Grid(Model)
.Name("Grid")
.ClientEvents(events => events.OnLoad("Grid_onLoad"))
JavaScript
function Grid_onLoad(e)
{
var html = { place your favorite template engine here }
$('#YourGridId').find('.t-page-size').html(html);
// bind 'click' event to your new control
}
Now the problem is that you need to bind own event to the change of the page size and tell new page size for the Telerik grid.
You can provide additional parameters to the controller action that provides data to your controller. There is an example in the documentation how to add additional data to your request.
<script type="text/javascript">
function Grid_onDataBinding(e) {
// pass additional values by setting the "data" field of the event argument
e.data = {
pageSize: // TODO: provide selected page size from your new control
};
}
</script>
In the server side controller action should automatically map your pageSize to an action parameter.
I hope this helps, let me know if you need more information.

How to customize Ext JS tree nodes properly?

Ext JS 4. I have a tree.Panel where I want to display custom HTML in each node, generated from that node’s model data. I can do this by setting the node’s text when loading the store, but it is not the model’s job to do markup. So I created a custom Column that renders my HTML.
My problem is: unless I derive from Ext.tree.Column, it doesn’t show up properly (no outline, plus/minus icons etc.). If I do, everything is fine, but Ext.tree.Column is marked as private to Ext JS.
Is there some officially supported API to do what I want?
I have written a blog post about how to customize ExtJS 4 tree panel, I hope it will help:
http://hardtouse.com/blog/?p=24
The idea is to use renderer combined with A LOT OF css magic:
columns : [{
xtype : 'treecolumn',
dataIndex : 'name',
renderer : function(value, record){
return Ext.String.format('<div class="tree-font">{0}</div>', value);
}]
Thanks for your answer above. Here is another example showing a few more options for formatting:
columns: [{
xtype: 'treecolumn',
dataIndex: 'text',
flex: 1,
renderer: function (value, metaData, record, rowIndex, colIndex, store, view) {
// see http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.tree.Column-cfg-renderer
var tooltipString = "Hello";
metaData.tdAttr = 'data-qtip="' + tooltipString + '"';
return Ext.String.format('{0} <span style="color:red;">{1}</span>', value, record.data.personname);
}
}]
You might also want to add
hideHeaders : true,
to your tree panel config to remove the "grid" header that appears as a result of using a treecolumn.
Murray

Resources