Building block & Snippet Editor guideline's

Building block & Snippet Editor The building blocks appear in the edit bar website. These pre-built html block allowing...



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>

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