Building block & Snippet Editor | Odoo Require Concept.
Building block & Snippet Editor guideline's
12:12
Building block & Snippet Editor
The building blocks appear in the edit bar website. These pre-built html block
allowing the designer to easily generate content on a page (drag and drop).
Options allow snippets to add customizations part html code according to their
selector (jQuery) and javascript object.
How to create content?
Designers can add their own html block in the "snippets" (/website/views/snippets.xml).
The block must be added in one of four menus (structure, content, feature or effect).
Structure:
<div>
<div class="oe_snippet_thumbnail">
<img class="oe_snippet_thumbnail_img" src="...image src..."/>
<span class="oe_snippet_thumbnail_title">...Block Name...</span>
</div>
<div class="oe_snippet_body">
...
<!--
The block with class 'oe_snippet_body' is inserted in the page.
This class is removed when the block is dropped.
</div>!
The block can be made of any html tag and content. -->
</div>
</div>
How to create options?
Designers can add their own html block in the "snippet_options" (/website/views/snippets.xml).
Structure:
<div data-snippet-option-id='...' <!-- Required: javascript object id
(but javascript for this option object is not required) -->
data-selector="..." <!-- Required: jQuery selector. Apply options on all The
part of html who match with this jQuery selector. E.g.: If the selector is div, all div will be selected and can be highlighted and assigned an editor. -->
data-selector-siblings="..." <!-- Optional: jQuery selector. The html part
can be insert or move beside the selected html block -->
data-selector-children="..." <!-- Optional: jQuery selector. The html part
can be insert or move inside the selected html block -->
data-selector-vertical-children='...' <!-- Optional: jQuery selector. The html part can be insert or move inside the selected html block.The drop zone is displayed vertically -->
...
<li><a href="#">...</a></li> <!-- Optional: html li list. List of menu items displayed in customize menu. If the li tag have 'data-class', the class is automatically added or removed to the html content when the user select this item. -->
...
<li class="dropdown-submenu" <!-- Optional: html li list example. -->
data-required="true" <!-- Optional: if only one item can be selected
and can't be unselect. !-->
<a tabindex="-1" href="#">...</a> <!-- bootstrap
dropdown button !-->
<ul class="dropdown-menu">
<li data-value="text_only"><a>...</a></li> <!-- by default data-value is apply like a class to html lock !-->
</ul>
</li>
</div>
(but javascript for this option object is not required) -->
data-selector="..." <!-- Required: jQuery selector. Apply options on all The
part of html who match with this jQuery selector. E.g.: If the selector is div, all div will be selected and can be highlighted and assigned an editor. -->
data-selector-siblings="..." <!-- Optional: jQuery selector. The html part
can be insert or move beside the selected html block -->
data-selector-children="..." <!-- Optional: jQuery selector. The html part
can be insert or move inside the selected html block -->
data-selector-vertical-children='...' <!-- Optional: jQuery selector. The html part can be insert or move inside the selected html block.The drop zone is displayed vertically -->
...
<li><a href="#">...</a></li> <!-- Optional: html li list. List of menu items displayed in customize menu. If the li tag have 'data-class', the class is automatically added or removed to the html content when the user select this item. -->
...
<li class="dropdown-submenu" <!-- Optional: html li list example. -->
data-required="true" <!-- Optional: if only one item can be selected
and can't be unselect. !-->
<a tabindex="-1" href="#">...</a> <!-- bootstrap
dropdown button !-->
<ul class="dropdown-menu">
<li data-value="text_only"><a>...</a></li> <!-- by default data-value is apply like a class to html lock !-->
</ul>
</li>
</div>
How to create a javascript object for an options?
openerp.website.snippet.options["...option-id..."] = website.snippet.Option.extend({
// start is called when the user click into a block or when the user drop a block
// into the page (just after the init method).
// start is usually used to bind event.
//
// this.$target: block html inserted inside the page
// this.$el: html li list of this options
// this.$overlay: html editor overlay who content resize bar, customize menu...
start: function () {},
// onFocus is called when the user click inside the block inserted in page
// and when the user drop on block into the page
onFocus : function () {},
// onBlur is called when the user click outside the block inserted in page, if
// the block is focused
onBlur : function () {},
// on_clone is called when the snippet is duplicate
// @variables: $clone is allready inserted is the page
on_clone: function ($clone) {},
// on_remove is called when the snippet is removed (dom is removing after this tigger)
on_remove: function () {},
// drop_and_build_snippet is called just after that a thumbnail is drag and dropped
// into a drop zone. The content is already inserted in the page.
drop_and_build_snippet: function () {},
// select is called when a user select an item in the li list of options
// By default, if the li item have a data-value attribute, the data-vlue it's apply
// like a class to the html block (this.$target)
// @variables: next_previous = {$next, $prev}
// $next = next item selected or false
// $prev = previous item selected or false
select: function (event, next_previous) {}
// preview is called when a user is on mouse over or mouse out of an item
// variables: next_previous = {$next, $prev}
// $next = next item selected or false
// $prev = previous item selected or false
preview: function (event, next_previous) {}
// clean_for_save
// clean_for_save is called just before to save the vue
// Sometime it's important to remove or add some datas (contentEditable, added
// classes to a running animation...)
clean_for_save: function () {}
});
// 'snippet-dropped' is triggered on '#oe_snippets' whith $target as attribute when a snippet is dropped
// 'snippet-activated' is triggered on '#oe_snippets' (and on snippet) when a snippet is activated
Odoo Require Concept
Odoo web framework come up with new concept of module loading which is almost inherited from RequireJS.
Let me describe how modules are loaded, how dependencies are calculated ?
Everything else is similar in web framework but now It is more modular, each and every component is reusable by just fetching/calling it using require(Its a wrapper to load the object).
Previously modules were loaded using namespace(same name given as module name to JS namespace).
First of all note that now onwards global object openerp is replaced with odoo.
Now
onwards if you want to create any module or any widget you can simply
define it using odoo.define, lets have example of both style old style
as well as new style.
Old Style:
openerp.my_module = function(openerp) {
openerp.web.my_widget1 = openerp.web.widget.extend({
//your widget stuff here
popup = new openerp.web.FormPopup(...);
});
openerp.web.my_widget2 = openerp.web.widget.extend({
//your widget stuff here
});
});
New Style:
odoo.define('web.my_module', function(require) {
popup = require('form_popup') //Where form_popup is separately defined in another file
web = require('odoo_web');
web.my_widget2 = openerp.web.wdiget.extend({
//your widget stuff here
});
});
No
doubt in both cases we can have re-usability but in later one we can
maintain small files for small features and can use that small feature
in another file by requiring it, code is more readable and simpler.
Note
that, new style you need to define files in proper order because one
feature might depends on another and due to dependency issue you module
might not be loaded.
Lets have a look how it works in background ?
we having one main file boot.js,
boot.js file having anonymous function and it is in closure style which
is called when file is loaded in DOM, the responsibility of boot.js is to load module, this file is the file which generates the concept of require method and dependency.
It
creates global odoo object which having define method, now note that
all other files will have define function called where second parameter
will be callback function, whenever each file is loaded, each file will
call define method of odoo, now define method of odoo global object
checks for the arguments and second argument will have function in which
there will be other require calls.
Define
method checks for the require calls using Regular Expression, after
gathering all require calls it fetches those objects from services
object.
Service object is an object which is module's/object's pool.
Say for example if I define one of my widget:
odoo.define('form.digital_signature', function() {....});
Then form.digital_signature is going to register in service pool.
If
there is dependency missing then its not going to load that module, if
everything is fine, if it finds all dependent module are already loaded
in service object pool then it calls function which is second parameter
in define and also add that module/feature with name given as a first
argument in service pool, if one tries to register service with same
name twice then it will raise error that service with same name is
already registered.
There are some core methods in boot.js, which you should go through:
define -> Finds require call, generates dependency list, creates wrapper of require
process_jobs -> loads module and add that module in module/object service and factories pool
init -> initializes webclient.
So with this we can simply create small features and use it by calling it another file using require('feature_name').
All your generated module will generally return reference of your object like example given below:
odoo.define('web.ajax', function (require) {
"use strict";
var time = require('web.time');
var Dialog = require('web.dialog');
time.date_to_utc...
var my_dialog = new Dialog(....)
});
where web.dialog is:
odoo.define('web.Dialog', function (require) {
"use strict";
var Dialog = Widget.extend({
//your dialog stuff
});
return Dialog;
});
So here web.dialog returns reference of Dialog and we can then use new Dialog after calling var Dialog require('web.dialog');
Hope this will help, feel free to raise your query by comments.
0 comments