[MERGE] forward port of branch 8.0 up to 262eb66
authorChristophe Simonis <chs@odoo.com>
Tue, 21 Oct 2014 12:59:56 +0000 (14:59 +0200)
committerChristophe Simonis <chs@odoo.com>
Tue, 21 Oct 2014 12:59:56 +0000 (14:59 +0200)
18 files changed:
1  2 
addons/account/res_config.py
addons/mrp/mrp.py
addons/point_of_sale/point_of_sale.py
addons/point_of_sale/report/pos_order_report.py
addons/point_of_sale/static/src/js/models.js
addons/project/report/project_report.py
addons/purchase/purchase.py
addons/sale/wizard/sale_make_invoice_advance.py
addons/web/controllers/main.py
addons/website/models/ir_qweb.py
addons/website/static/src/js/website.editor.js
addons/website/views/snippets.xml
addons/website_forum/controllers/main.py
addons/website_forum/models/forum.py
addons/website_forum/views/website_forum.xml
addons/website_sale/views/views.xml
doc/conf.py
openerp/addons/base/res/res_partner.py

@@@ -51,8 -51,8 +51,8 @@@ class account_config_settings(osv.osv_m
          'code_digits': fields.integer('# of Digits', help="No. of digits to use for account code"),
          'tax_calculation_rounding_method': fields.related('company_id',
              'tax_calculation_rounding_method', type='selection', selection=[
 -            ('round_per_line', 'Round per line'),
 -            ('round_globally', 'Round globally'),
 +            ('round_per_line', 'Round calculation of taxes per line'),
 +            ('round_globally', 'Round globally calculation of taxes '),
              ], string='Tax calculation rounding method',
              help="If you select 'Round per line' : for each tax, the tax amount will first be computed and rounded for each PO/SO/invoice line and then these rounded amounts will be summed, leading to the total amount for that tax. If you select 'Round globally': for each tax, the tax amount will be computed for each PO/SO/invoice line, then these amounts will be summed and eventually this total tax amount will be rounded. If you sell with tax included, you should choose 'Round per line' because you certainly want the sum of your tax-included line subtotals to be equal to the total amount with taxes."),
          'sale_tax': fields.many2one("account.tax.template", "Default sale tax"),
          'module_product_email_template': fields.boolean('Send products tools and information at the invoice confirmation',
              help='With this module, link your products to a template to send complete information and tools to your customer.\n'
                   'For instance when invoicing a training, the training agenda and materials will automatically be send to your customers.'),
 +        'module_account_bank_statement_import_ofx': fields.boolean('Import of Bank Statements in .OFX Format',
 +            help='Get your bank statements from you bank and import them in Odoo in .OFX format.\n'
 +                '-that installs the module account_bank_statement_import.'),
 +        'module_account_bank_statement_import_qif': fields.boolean('Import of Bank Statements in .QIF Format.',
 +            help='Get your bank statements from you bank and import them in Odoo in .QIF format.\n'
 +                '-that installs the module account_bank_statement_import_qif.'),
          'group_proforma_invoices': fields.boolean('Allow pro-forma invoices',
              implied_group='account.group_proforma_invoices',
              help="Allows you to put invoices in pro-forma state."),
                      })
              # update taxes
              ir_values = self.pool.get('ir.values')
-             taxes_id = ir_values.get_default(cr, uid, 'product.product', 'taxes_id', company_id=company_id)
-             supplier_taxes_id = ir_values.get_default(cr, uid, 'product.product', 'supplier_taxes_id', company_id=company_id)
+             taxes_id = ir_values.get_default(cr, uid, 'product.template', 'taxes_id', company_id=company_id)
+             supplier_taxes_id = ir_values.get_default(cr, uid, 'product.template', 'supplier_taxes_id', company_id=company_id)
              values.update({
                  'default_sale_tax': isinstance(taxes_id, list) and taxes_id[0] or taxes_id,
                  'default_purchase_tax': isinstance(supplier_taxes_id, list) and supplier_taxes_id[0] or supplier_taxes_id,
              raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
          ir_values = self.pool.get('ir.values')
          config = self.browse(cr, uid, ids[0], context)
-         ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'taxes_id',
+         ir_values.set_default(cr, SUPERUSER_ID, 'product.template', 'taxes_id',
              config.default_sale_tax and [config.default_sale_tax.id] or False, company_id=config.company_id.id)
-         ir_values.set_default(cr, SUPERUSER_ID, 'product.product', 'supplier_taxes_id',
+         ir_values.set_default(cr, SUPERUSER_ID, 'product.template', 'supplier_taxes_id',
              config.default_purchase_tax and [config.default_purchase_tax.id] or False, company_id=config.company_id.id)
  
      def set_chart_of_accounts(self, cr, uid, ids, context=None):
diff --combined addons/mrp/mrp.py
@@@ -159,7 -159,7 +159,7 @@@ class mrp_bom(osv.osv)
          'name': fields.char('Name'),
          'code': fields.char('Reference', size=16),
          'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the bills of material without removing it."),
 -        'type': fields.selection([('normal', 'Normal'), ('phantom', 'Set')], 'BoM Type', required=True,
 +        'type': fields.selection([('normal','Manufacture this product as a normal bill of material'),('phantom','Sell and ship this product as a set of components(phantom)')], 'BoM Type', required=True,
                  help= "Set: When processing a sales order for this product, the delivery order will contain the raw materials, instead of the finished product."),
          'position': fields.char('Internal Reference', help="Reference to a position in an external plan."),
          'product_tmpl_id': fields.many2one('product.template', 'Product', domain="[('type', '!=', 'service')]", required=True),
@@@ -406,14 -406,6 +406,14 @@@ class mrp_bom_line(osv.osv)
              'You should install the mrp_byproduct module if you want to manage extra products on BoMs !'),
      ]
  
 +    def create(self, cr, uid, values, context=None):
 +        if context is None:
 +            context = {}
 +        product_obj = self.pool.get('product.product')
 +        if 'product_id' in values and not 'product_uom' in values:
 +            values['product_uom'] = product_obj.browse(cr, uid, values.get('product_id'), context=context).uom_id.id
 +        return super(mrp_bom_line, self).create(cr, uid, values, context=context)
 +
      def onchange_uom(self, cr, uid, ids, product_id, product_uom, context=None):
          res = {'value': {}}
          if not product_uom or not product_id:
@@@ -602,14 -594,6 +602,14 @@@ class mrp_production(osv.osv)
          (_check_qty, 'Order quantity cannot be negative or zero!', ['product_qty']),
      ]
  
 +    def create(self, cr, uid, values, context=None):
 +        if context is None:
 +            context = {}
 +        product_obj = self.pool.get('product.product')
 +        if 'product_id' in values and not 'product_uom' in values:
 +            values['product_uom'] = product_obj.browse(cr, uid, values.get('product_id'), context=context).uom_id.id
 +        return super(mrp_production, self).create(cr, uid, values, context=context)
 +
      def unlink(self, cr, uid, ids, context=None):
          for production in self.browse(cr, uid, ids, context=context):
              if production.state not in ('draft', 'cancel'):
                  new_moves = stock_mov_obj.action_consume(cr, uid, [produce_product.id], (subproduct_factor * production_qty_uom),
                                                           location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context)
                  stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context)
-                 if produce_product.product_id.id == production.product_id.id and new_moves:
-                     main_production_move = new_moves[0]
+                 if produce_product.product_id.id == production.product_id.id:
+                     main_production_move = produce_product.id
  
          if production_mode in ['consume', 'consume_produce']:
              if wiz:
      
      def _make_production_produce_line(self, cr, uid, production, context=None):
          stock_move = self.pool.get('stock.move')
+         proc_obj = self.pool.get('procurement.order')
          source_location_id = production.product_id.property_stock_production.id
          destination_location_id = production.location_dest_id.id
+         procs = proc_obj.search(cr, uid, [('production_id', '=', production.id)], context=context)
+         procurement_id = procs and procs[0] or False
          data = {
              'name': production.name,
              'date': production.date_planned,
              'location_id': source_location_id,
              'location_dest_id': destination_location_id,
              'move_dest_id': production.move_prod_id.id,
+             'procurement_id': procurement_id,
              'company_id': production.company_id.id,
              'production_id': production.id,
              'origin': production.name,
@@@ -25,7 -25,6 +25,7 @@@ import tim
  from openerp import tools
  from openerp.osv import fields, osv
  from openerp.tools.translate import _
 +from openerp.exceptions import Warning
  
  import openerp.addons.decimal_precision as dp
  import openerp.addons.product.product
@@@ -73,7 -72,6 +73,7 @@@ class pos_config(osv.osv)
          'iface_scan_via_proxy' : fields.boolean('Scan via Proxy', help="Enable barcode scanning with a remotely connected barcode scanner"),
          'iface_invoicing': fields.boolean('Invoicing',help='Enables invoice generation from the Point of Sale'),
          'iface_big_scrollbars': fields.boolean('Large Scrollbars',help='For imprecise industrial touchscreens'),
 +        'iface_fullscreen':     fields.boolean('Fullscreen', help='Display the Point of Sale in full screen mode'),
          'receipt_header': fields.text('Receipt Header',help="A short text that will be inserted as a header in the printed receipt"),
          'receipt_footer': fields.text('Receipt Footer',help="A short text that will be inserted as a footer in the printed receipt"),
          'proxy_ip':       fields.char('IP Address', help='The hostname or ip address of the hardware proxy, Will be autodetected if left empty', size=45),
                  return False
          return True
  
+     def _check_company_payment(self, cr, uid, ids, context=None):
+         for config in self.browse(cr, uid, ids, context=context):
+             journal_ids = [j.id for j in config.journal_ids]
+             if self.pool['account.journal'].search(cr, uid, [
+                     ('id', 'in', journal_ids),
+                     ('company_id', '!=', config.company_id.id)
+                 ], count=True, context=context):
+                 return False
+         return True
      _constraints = [
          (_check_cash_control, "You cannot have two cash controls in one Point Of Sale !", ['journal_ids']),
          (_check_company_location, "The company of the stock location is different than the one of point of sale", ['company_id', 'stock_location_id']),
          (_check_company_journal, "The company of the sale journal is different than the one of point of sale", ['company_id', 'journal_id']),
+         (_check_company_payment, "The company of a payment method is different than the one of point of sale", ['company_id', 'journal_ids']),
      ]
  
      def name_get(self, cr, uid, ids, context=None):
@@@ -591,7 -600,11 +602,7 @@@ class pos_order(osv.osv)
              if order['amount_return']:
                  cash_journal = session.cash_journal_id
                  if not cash_journal:
 -                    cash_journal_ids = filter(lambda st: st.journal_id.type=='cash', session.statement_ids)
 -                    if not len(cash_journal_ids):
 -                        raise osv.except_osv( _('error!'),
 -                            _("No cash statement found for this session. Unable to record returned cash."))
 -                    cash_journal = cash_journal_ids[0].journal_id
 +                    raise Warning(_('No cash statement found with cash control enabled for this session. Unable to record returned cash.'))
                  self.add_payment(cr, uid, order_id, {
                      'amount': -order['amount_return'],
                      'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'),
@@@ -58,7 -58,7 +58,7 @@@ class pos_order_report(osv.osv)
                      sum(l.qty * u.factor) as product_qty,
                      sum(l.qty * l.price_unit) as price_total,
                      sum((l.qty * l.price_unit) * (l.discount / 100)) as total_discount,
-                     (sum(l.qty*l.price_unit)/sum(l.qty * u.factor))::decimal(16,2) as average_price,
+                     (sum(l.qty*l.price_unit)/sum(l.qty * u.factor))::decimal as average_price,
                      sum(cast(to_char(date_trunc('day',s.date_order) - date_trunc('day',s.create_date),'DD') as int)) as delay_validation,
                      s.partner_id as partner_id,
                      s.state as state,
@@@ -70,8 -70,8 +70,8 @@@
                      pt.categ_id as product_categ_id
                  from pos_order_line as l
                      left join pos_order s on (s.id=l.order_id)
 -                    left join product_product p on (p.id=l.product_id)
 -                    left join product_template pt on (pt.id=p.product_tmpl_id)
 +                    left join product_product p on (l.product_id=p.id)
 +                    left join product_template pt on (p.product_tmpl_id=pt.id)
                      left join product_uom u on (u.id=pt.uom_id)
                  group by
                      s.date_order, s.partner_id,s.state, pt.categ_id,
@@@ -294,12 -294,14 +294,12 @@@ function openerp_pos_models(instance, m
              label: 'fonts',
              loaded: function(self){
                  var fonts_loaded = new $.Deferred();
 -
                  // Waiting for fonts to be loaded to prevent receipt printing
                  // from printing empty receipt while loading Inconsolata
                  // ( The font used for the receipt ) 
                  waitForWebfonts(['Lato','Inconsolata'], function(){
                      fonts_loaded.resolve();
                  });
 -
                  // The JS used to detect font loading is not 100% robust, so
                  // do not wait more than 5sec
                  setTimeout(function(){
                          c.height = height
                      var ctx = c.getContext('2d');
                          ctx.drawImage(self.company_logo,0,0, width, height);
-                     
                      self.company_logo_base64 = c.toDataURL();
                      logo_loaded.resolve();
                  };
                  self.company_logo.onerror = function(){
                      logo_loaded.reject();
                  };
+                     self.company_logo.crossOrigin = "anonymous";
                  self.company_logo.src = '/web/binary/company_logo' +'?_'+Math.random();
  
                  return logo_loaded;
          // wrapper around the _save_to_server that updates the synch status widget
          _flush_orders: function(orders, options) {
              var self = this;
 -
              this.set('synch',{ state: 'connecting', pending: orders.length});
  
              return self._save_to_server(orders, options).done(function (server_ids) {
                  return server_ids;
              }).fail(function (error, event){
                  if(error.code === 200 ){    // Business Logic Error, not a connection problem
 +                    //if warning do not need to dispaly traceback!!
 +                    if(error.data.exception_type == 'warning'){
 +                        delete error.data.debug;
 +                    }
                      self.pos_widget.screen_selector.show_popup('error-traceback',{
                          message: error.data.message,
                          comment: error.data.debug
              this.screen_data = {};  // see ScreenSelector
              this.receipt_type = 'receipt';  // 'receipt' || 'invoice'
              this.temporary = attributes.temporary || false;
 +            this.to_invoice = false;
              return this;
          },
          is_empty: function(){
                  return sum + paymentLine.get_amount();
              }), 0);
          },
 -        getChange: function() {
 -            return this.getPaidTotal() - this.getTotalTaxIncluded();
 +        getChange: function(paymentline) {
 +            if (!paymentline) {
 +                var change = this.getPaidTotal() - this.getTotalTaxIncluded();
 +            } else {
 +                var change = -this.getTotalTaxIncluded(); 
 +                var lines  = this.get('paymentLines').models;
 +                for (var i = 0; i < lines.length; i++) {
 +                    change += lines[i].get_amount();
 +                    if (lines[i] === paymentline) {
 +                        break;
 +                    }
 +                }
 +            }
 +            return round_pr(Math.max(0,change), this.pos.currency.rounding);
 +        },
 +        getDueLeft: function(paymentline) {
 +            if (!paymentline) {
 +                var due = this.getTotalTaxIncluded() - this.getPaidTotal();
 +            } else {
 +                var due = this.getTotalTaxIncluded();
 +                var lines = this.get('paymentLines').models;
 +                for (var i = 0; i < lines.length; i++) {
 +                    if (lines[i] === paymentline) {
 +                        break;
 +                    } else {
 +                        due -= lines[i].get_amount();
 +                    }
 +                }
 +            }
 +            return round_pr(Math.max(0,due), this.pos.currency.rounding);
 +        },
 +        isPaid: function(){
 +            return this.getDueLeft() === 0;
          },
 -        getDueLeft: function() {
 -            return this.getTotalTaxIncluded() - this.getPaidTotal();
 +        isPaidWithCash: function(){
 +            return !!this.get('paymentLines').find( function(pl){
 +                return pl.cashregister.journal.type === 'cash';
 +            });
 +        },
 +        finalize: function(){
 +            this.destroy();
          },
          // sets the type of receipt 'receipt'(default) or 'invoice'
          set_receipt_type: function(type){
                  }
              }
          },
 +        set_to_invoice: function(to_invoice) {
 +            this.to_invoice = to_invoice;
 +        },
 +        is_to_invoice: function(){
 +            return this.to_invoice;
 +        },
 +        // remove all the paymentlines with zero money in it
 +        clean_empty_paymentlines: function() {
 +            var lines = this.get('paymentLines').models;
 +            var empty = [];
 +            for ( var i = 0; i < lines.length; i++) {
 +                if (!lines[i].get_amount()) {
 +                    empty.push(lines[i]);
 +                }
 +            }
 +            for ( var i = 0; i < empty.length; i++) {
 +                this.removePaymentline(empty[i]);
 +            }
 +        },
          //see set_screen_data
          get_screen_data: function(key){
              return this.screen_data[key];
@@@ -30,6 -30,7 +30,6 @@@ class report_project_task_user(osv.osv)
      _columns = {
          'name': fields.char('Task Summary', readonly=True),
          'user_id': fields.many2one('res.users', 'Assigned To', readonly=True),
 -        'reviewer_id': fields.many2one('res.users', 'Reviewer', readonly=True),
          'date_start': fields.datetime('Assignation Date', readonly=True),
          'no_of_days': fields.integer('# of Days', size=128, readonly=True),
          'date_end': fields.datetime('Ending Date', readonly=True),
@@@ -70,6 -71,7 +70,6 @@@
                      t.date_deadline as date_deadline,
                      abs((extract('epoch' from (t.write_date-t.date_start)))/(3600*24))  as no_of_days,
                      t.user_id,
 -                    t.reviewer_id,
                      progress as progress,
                      t.project_id,
                      t.effective_hours as hours_effective,
@@@ -85,7 -87,7 +85,7 @@@
                      planned_hours as hours_planned,
                      (extract('epoch' from (t.write_date-t.create_date)))/(3600*24)  as closing_days,
                      (extract('epoch' from (t.date_start-t.create_date)))/(3600*24)  as opening_days,
-                     abs((extract('epoch' from (t.date_deadline-t.write_date)))/(3600*24))  as delay_endings_days
+                     (extract('epoch' from (t.date_deadline-now())))/(3600*24)  as delay_endings_days
                FROM project_task t
                  WHERE t.active = 'true'
                  GROUP BY
                      date_deadline,
                      date_last_stage_update,
                      t.user_id,
 -                    t.reviewer_id,
                      t.project_id,
                      t.priority,
                      name,
@@@ -253,7 -253,7 +253,7 @@@ class purchase_order(osv.osv)
                                      help="It indicates that an invoice has been validated"),
          'invoiced_rate': fields.function(_invoiced_rate, string='Invoiced', type='float'),
          'invoice_method': fields.selection([('manual','Based on Purchase Order lines'),('order','Based on generated draft invoice'),('picking','Based on incoming shipments')], 'Invoicing Control', required=True,
 -            readonly=True, states={'draft':[('readonly',False)], 'sent':[('readonly',False)]},
 +            readonly=True, states={'draft':[('readonly',False)], 'sent':[('readonly',False)],'bid':[('readonly',False)]},
              help="Based on Purchase Order lines: place individual lines in 'Invoice Control / On Purchase Order lines' from where you can selectively create an invoice.\n" \
                  "Based on generated invoice: create a draft invoice you can validate later.\n" \
                  "Based on incoming shipments: let you create an invoice when receipts are validated."
          product_uom = self.pool.get('product.uom')
          price_unit = order_line.price_unit
          if order_line.product_uom.id != order_line.product_id.uom_id.id:
-             price_unit *= order_line.product_uom.factor
+             price_unit *= order_line.product_uom.factor / order_line.product_id.uom_id.factor
          if order.currency_id.id != order.company_id.currency_id.id:
              #we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency
              price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False, context=context)
@@@ -31,13 -31,17 +31,13 @@@ class sale_advance_payment_inv(osv.osv_
              [('all', 'Invoice the whole sales order'), ('percentage','Percentage'), ('fixed','Fixed price (deposit)'),
                  ('lines', 'Some order lines')],
              'What do you want to invoice?', required=True,
 -            help="""Use Invoice the whole sale order to create the final invoice.
 -                Use Percentage to invoice a percentage of the total amount.
 -                Use Fixed Price to invoice a specific amound in advance.
 -                Use Some Order Lines to invoice a selection of the sales order lines."""),
 +            help="""Use Invoice the whole sale order to create the final invoice.\nUse Percentage to invoice a percentage of the total amount.\nUse Fixed Price to invoice a specific amount in advance.\nUse Some Order Lines to invoice a selection of the sales order lines."""),
          'qtty': fields.float('Quantity', digits=(16, 2), required=True),
          'product_id': fields.many2one('product.product', 'Advance Product',
              domain=[('type', '=', 'service')],
 -            help="""Select a product of type service which is called 'Advance Product'.
 -                You may have to create it and set it as a default value on this field."""),
 +            help="Select a product of type service which is called 'Advance Product'.\nYou may have to create it and set it as a default value on this field."),
          'amount': fields.float('Advance Amount', digits_compute= dp.get_precision('Account'),
 -            help="The amount to be invoiced in advance."),
 +            help="The amount to be invoiced in advance. \nTaxes are not taken into account for advance invoices."),
      }
  
      def _get_advance_product(self, cr, uid, context=None):
@@@ -54,6 -58,9 +54,9 @@@
          'product_id': _get_advance_product,
      }
  
+     def _translate_advance(self, cr, uid, percentage=False, context=None):
+         return _("Advance of %s %%") if percentage else _("Advance of %s %s")
      def onchange_method(self, cr, uid, ids, advance_payment_method, product_id, context=None):
          if advance_payment_method == 'percentage':
              return {'value': {'amount':0, 'product_id':False }}
              if wizard.advance_payment_method == 'percentage':
                  inv_amount = sale.amount_total * wizard.amount / 100
                  if not res.get('name'):
-                     res['name'] = _("Advance of %s %%") % (wizard.amount)
+                     res['name'] = self._translate_advance(cr, uid, percentage=True, context=dict(context, lang=sale.partner_id.lang)) % (wizard.amount)
              else:
                  inv_amount = wizard.amount
                  if not res.get('name'):
                      #TODO: should find a way to call formatLang() from rml_parse
                      symbol = sale.pricelist_id.currency_id.symbol
                      if sale.pricelist_id.currency_id.position == 'after':
-                         res['name'] = _("Advance of %s %s") % (inv_amount, symbol)
+                         symbol_order = (inv_amount, symbol)
                      else:
-                         res['name'] = _("Advance of %s %s") % (symbol, inv_amount)
+                         symbol_order = (symbol, inv_amount)
+                     res['name'] = self._translate_advance(cr, uid, context=dict(context, lang=sale.partner_id.lang)) % symbol_order
  
              # determine taxes
              if res.get('invoice_line_tax_id'):
          sale_obj.write(cr, uid, sale_id, {'invoice_ids': [(4, inv_id)]}, context=context)
          return inv_id
  
      def create_invoices(self, cr, uid, ids, context=None):
          """ create invoices for the active sales orders """
          sale_obj = self.pool.get('sale.order')
@@@ -550,34 -550,6 +550,34 @@@ class WebClient(http.Controller)
      def jslist(self, mods=None):
          return manifest_list('js', mods=mods)
  
 +    @http.route('/web/webclient/locale/<string:lang>', type='http', auth="none")
 +    def load_locale(self, lang):
 +        magic_file_finding = [lang.replace("_",'-').lower(), lang.split('_')[0]]
 +        addons_path = http.addons_manifest['web']['addons_path']
 +        #load datejs locale
 +        datejs_locale = ""
 +        try:
 +            with open(os.path.join(addons_path, 'web', 'static', 'lib', 'datejs', 'globalization', lang.replace('_', '-') + '.js'), 'r') as f:
 +                datejs_locale = f.read()
 +        except IOError:
 +            pass
 +
 +        #load momentjs locale
 +        momentjs_locale_file = False
 +        momentjs_locale = ""
 +        for code in magic_file_finding:
 +            try:
 +                with open(os.path.join(addons_path, 'web', 'static', 'lib', 'moment', 'locale', code + '.js'), 'r') as f:
 +                    momentjs_locale = f.read()
 +                #we found a locale matching so we can exit
 +                break
 +            except IOError:
 +                continue
 +
 +        #return the content of the locale
 +        headers = [('Content-Type', 'application/javascript'), ('Cache-Control', 'max-age=%s' % (36000))]
 +        return request.make_response(datejs_locale + "\n"+ momentjs_locale, headers)
 +
      @http.route('/web/webclient/qweb', type='http', auth="none")
      def qweb(self, mods=None, db=None):
          files = [f[0] for f in manifest_glob('qweb', addons=mods, db=db)]
@@@ -748,17 -720,14 +748,17 @@@ class Database(http.Controller)
              return {'error': _('Could not drop database !'), 'title': _('Drop Database')}
  
      @http.route('/web/database/backup', type='http', auth="none")
 -    def backup(self, backup_db, backup_pwd, token):
 +    def backup(self, backup_db, backup_pwd, token, **kwargs):
          try:
 +            format = kwargs.get('format')
 +            ext = "zip" if format == 'zip' else "dump"
              db_dump = base64.b64decode(
 -                request.session.proxy("db").dump(backup_pwd, backup_db))
 -            filename = "%(db)s_%(timestamp)s.dump" % {
 +                request.session.proxy("db").dump(backup_pwd, backup_db, format))
 +            filename = "%(db)s_%(timestamp)s.%(ext)s" % {
                  'db': backup_db,
                  'timestamp': datetime.datetime.utcnow().strftime(
 -                    "%Y-%m-%d_%H-%M-%SZ")
 +                    "%Y-%m-%d_%H-%M-%SZ"),
 +                'ext': ext
              }
              return request.make_response(db_dump,
                 [('Content-Type', 'application/octet-stream; charset=binary'),
@@@ -1210,7 -1179,7 +1210,7 @@@ class Binary(http.Controller)
          '/web/binary/company_logo',
          '/logo',
          '/logo.png',
-     ], type='http', auth="none")
+     ], type='http', auth="none", cors="*")
      def company_logo(self, dbname=None, **kw):
          imgname = 'logo.png'
          placeholder = functools.partial(get_module_resource, 'web', 'static', 'src', 'img')
@@@ -1576,6 -1545,7 +1576,6 @@@ class Reports(http.Controller)
      @serialize_exception
      def index(self, action, token):
          action = simplejson.loads(action)
 -
          report_srv = request.session.proxy("report")
          context = dict(request.context)
          context.update(action["context"])
              else:
                  file_name = action['report_name']
          file_name = '%s.%s' % (file_name, report_struct['format'])
 -
 +        headers=[
 +             ('Content-Disposition', content_disposition(file_name)),
 +             ('Content-Type', report_mimetype),
 +             ('Content-Length', len(report))]
 +        if action.get('pdf_viewer'):
 +            del headers[0]
          return request.make_response(report,
 -             headers=[
 -                 ('Content-Disposition', content_disposition(file_name)),
 -                 ('Content-Type', report_mimetype),
 -                 ('Content-Length', len(report))],
 +             headers=headers,
               cookies={'fileToken': token})
  
  class Apps(http.Controller):
@@@ -45,14 -45,6 +45,14 @@@ class QWeb(orm.AbstractModel)
          'a': 'href',
      }
  
 +    re_remove_spaces = re.compile('\s+')
 +    PRESERVE_WHITESPACE = [
 +        'pre',
 +        'textarea',
 +        'script',
 +        'style',
 +    ]
 +
      def add_template(self, qcontext, name, node):
          # preprocessing for multilang static urls
          if request.website:
              'website.qweb.field.' + field_type,
              self.pool['website.qweb.field'])
  
 +    def render_text(self, text, element, qwebcontext):
 +        compress = request and not request.debug and request.website and request.website.compress_html
 +        if compress and element.tag not in self.PRESERVE_WHITESPACE:
 +            text = self.re_remove_spaces.sub(' ', text.lstrip())
 +        return super(QWeb, self).render_text(text, element, qwebcontext)
 +
 +    def render_tail(self, tail, element, qwebcontext):
 +        compress = request and not request.debug and request.website and request.website.compress_html
 +        if compress and element.getparent().tag not in self.PRESERVE_WHITESPACE:
 +            # No need to recurse because those tags children are not html5 parser friendly
 +            tail = self.re_remove_spaces.sub(' ', tail.rstrip())
 +        return super(QWeb, self).render_tail(tail, element, qwebcontext)
 +
  class Field(orm.AbstractModel):
      _name = 'website.qweb.field'
      _inherit = 'ir.qweb.field'
@@@ -438,6 -417,9 +438,9 @@@ class Contact(orm.AbstractModel)
      _name = 'website.qweb.field.contact'
      _inherit = ['ir.qweb.field.contact', 'website.qweb.field.many2one']
  
+     def from_html(self, cr, uid, model, column, element, context=None):
+         return None
  class QwebView(orm.AbstractModel):
      _name = 'website.qweb.field.qweb'
      _inherit = ['ir.qweb.field.qweb']
              }
          });
  
 +        CKEDITOR.plugins.add('customColor', {
 +            requires: 'panelbutton,floatpanel',
 +            init: function (editor) {
 +                function create_button (buttonID, label) {
 +                    var btnID = buttonID;
 +                    editor.ui.add(buttonID, CKEDITOR.UI_PANELBUTTON, {
 +                        label: label,
 +                        title: label,
 +                        modes: { wysiwyg: true },
 +                        editorFocus: true,
 +                        context: 'font',
 +                        panel: {
 +                            css: [  '/web/css/web.assets_common/' + (new Date().getTime()),
 +                                    '/web/css/website.assets_frontend/' + (new Date().getTime()),
 +                                    '/web/css/website.assets_editor/' + (new Date().getTime())],
 +                            attributes: { 'role': 'listbox', 'aria-label': label },
 +                        },
 +                        enable: function () {
 +                            this.setState(CKEDITOR.TRISTATE_OFF);
 +                        },
 +                        disable: function () {
 +                            this.setState(CKEDITOR.TRISTATE_DISABLED);
 +                        },
 +                        onBlock: function (panel, block) {
 +                            var self = this;
 +                            var html = openerp.qweb.render('website.colorpicker');
 +                            block.autoSize = true;
 +                            block.element.setHtml( html );
 +                            $(block.element.$).on('click', 'button', function () {
 +                                self.clicked(this);
 +                            });
 +                            if (btnID === "TextColor") {
 +                                $(".only-text", block.element.$).css("display", "block");
 +                                $(".only-bg", block.element.$).css("display", "none");
 +                            }
 +                            var $body = $(block.element.$).parents("body");
 +                            setTimeout(function () {
 +                                $body.css('background-color', '#fff');
 +                            }, 0);
 +                        },
 +                        getClasses: function () {
 +                            var self = this;
 +                            var classes = [];
 +                            var id = this._.id;
 +                            var block = this._.panel._.panel._.blocks[id];
 +                            var $root = $(block.element.$);
 +                            $root.find("button").map(function () {
 +                                var color = self.getClass(this);
 +                                if(color) classes.push( color );
 +                            });
 +                            return classes;
 +                        },
 +                        getClass: function (button) {
 +                            var color = btnID === "BGColor" ? $(button).attr("class") : $(button).attr("class").replace(/^bg-/i, 'text-');
 +                            return color.length && color;
 +                        },
 +                        clicked: function (button) {
 +                            var className = this.getClass(button);
 +                            var ancestor = editor.getSelection().getCommonAncestor();
 +
 +                            editor.focus();
 +                            this._.panel.hide();
 +                            editor.fire('saveSnapshot');
 +
 +                            // remove style
 +                            var classes = [];
 +                            var $ancestor = $(ancestor.$);
 +                            var $fonts = $(ancestor.$).find('font');
 +                            if (!ancestor.$.tagName) {
 +                                $ancestor = $ancestor.parent();
 +                            }
 +                            if ($ancestor.is('font')) {
 +                                $fonts = $fonts.add($ancestor[0]);
 +                            }
 +
 +                            $fonts.filter("."+this.getClasses().join(",.")).map(function () {
 +                                var className = $(this).attr("class");
 +                                if (classes.indexOf(className) === -1) {
 +                                    classes.push(className);
 +                                }
 +                            });
 +                            for (var k in classes) {
 +                                editor.removeStyle( new CKEDITOR.style({
 +                                    element: 'font',
 +                                    attributes: { 'class': classes[k] },
 +                                }) );
 +                            }
 +
 +                            // add new style
 +                            if (className) {
 +                                editor.applyStyle( new CKEDITOR.style({
 +                                    element: 'font',
 +                                    attributes: { 'class': className },
 +                                }) );
 +                            }
 +                            editor.fire('saveSnapshot');
 +                        }
 +
 +                    });
 +                }
 +                create_button("BGColor", "Background Color");
 +                create_button("TextColor", "Text Color");
 +            }
 +        });
 +
          CKEDITOR.plugins.add('oeref', {
              requires: 'widget',
  
                  fillEmptyBlocks: false,
                  filebrowserImageUploadUrl: "/website/attach",
                  // Support for sharedSpaces in 4.x
 -                extraPlugins: 'sharedspace,customdialogs,tablebutton,oeref',
 +                extraPlugins: 'customColor,sharedspace,customdialogs,tablebutton,oeref',
                  // Place toolbar in controlled location
                  sharedSpaces: { top: 'oe_rte_toolbar' },
                  toolbar: [{
                      {name: "Heading 5", element: 'h5'},
                      {name: "Heading 6", element: 'h6'},
                      {name: "Formatted", element: 'pre'},
 -                    {name: "Address", element: 'address'}
 +                    {name: "Address", element: 'address'},
                  ],
              };
          },
                  this.changed($(e.target));
              },
              'click button.filepicker': function () {
-                 this.$('input[type=file]').click();
+                 var filepicker = this.$('input[type=file]');
+                 if (!_.isEmpty(filepicker)){
+                     filepicker[0].click();
+                 }
              },
              'click .js_disable_optimization': function () {
                  this.$('input[name="disable_optimization"]').val('1');
-                 this.$('button.filepicker').click();
+                 var filepicker = this.$('button.filepicker');
+                 if (!_.isEmpty(filepicker)){
+                     filepicker[0].click();
+                 }
              },
              'change input[type=file]': 'file_selection',
              'submit form': 'form_submit',
              }
              var callback = _.uniqueId('func_');
              this.$('input[name=func]').val(callback);
 -            window[callback] = function (url, error) {
 +            window[callback] = function (attachments, error) {
                  delete window[callback];
 -                self.file_selected(url, error);
 +                self.file_selected(attachments[0]['website_url'], error);
              };
          },
          file_selection: function () {
  
  <div id="snippet_structure" class="tab-pane active">
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_banner.png"/>
 -            <span class="oe_snippet_thumbnail_title">Banner</span>
 -        </div>
 -        <div id="myCarousel" class="oe_snippet_body carousel slide mb32" style="height: 320px;">
 +    <div name="Banner" class="o_block_banner">
 +        <div id="myCarousel" class="carousel slide mb32" data-interval="10000" style="height: 320px;">
              <!-- Indicators -->
              <ol class="carousel-indicators hidden">
                  <li data-target="#myCarousel" data-slide-to="0" class="active"></li>
@@@ -30,9 -34,9 +30,9 @@@
                                          <a href="/page/website.contactus" class="btn btn-success btn-large">Contact us</a>
                                      </p>
                              </div>
-                             <span class="carousel-img col-md-6 hidden-sm hidden-xs">
+                             <div class="carousel-img col-md-6 hidden-sm hidden-xs">
                                  <img class="img-responsive" src="/website/static/src/img/banner/banner_picture.png" alt="Banner Odoo Image"/>
-                             </span> 
+                             </div>
                          </div>
                      </div>
                  </div>
          </div>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_text_image.png"/>
 -            <span class="oe_snippet_thumbnail_title">Text-Image</span>
 -        </div>
 -        <section class="oe_snippet_body">
 +    <div name="Text-Image" class="o_block_text_image">
 +        <section>
              <div class="container">
                  <div class="row">
                      <div class="col-md-6 mt16">
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_image_text.png"/>
 -            <span class="oe_snippet_thumbnail_title">Image-Text</span>
 -        </div>
 -        <section class="oe_snippet_body">
 +    <div name="Image-Text" class="o_block_image_text">
 +        <section>
              <div class="container">
                  <div class="row">
                      <div class="col-md-6 mt16">
          </section>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_jumbotron.png"/>
 -            <span class="oe_snippet_thumbnail_title">Big Message</span>
 -        </div>
 -        <section class="oe_snippet_body jumbotron mt16 mb16">
 +    <div name="Big Message" class="o_block_jumbotron">
 +        <section class="jumbotron mt16 mb16">
              <div class="container">
                  <h1>Sell Online. Easily.</h1>
                  <p>
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_text_block.png"/>
 -            <span class="oe_snippet_thumbnail_title">Text Block</span>
 -        </div>
 -        <section class="oe_snippet_body mt16 mb16">
 +    <div name="Text Block" class="o_block_text_block">
 +        <section class="mt16 mb16">
              <div class="container">
                  <div class="row">
                      <div class="col-md-12 text-center mt16 mb32">
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_title.png"/>
 -            <span class="oe_snippet_thumbnail_title">Title</span>
 -        </div>
 -        <section class="oe_snippet_body">
 +    <div name="Title" class="o_block_title">
 +        <section>
              <div class="container">
                  <div class="row">
                      <div class="col-md-12">
          </section>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_features.png"/>
 -            <span class="oe_snippet_thumbnail_title">Features</span>
 -        </div>
 -        <section class="oe_snippet_body mb16">
 +    <div name="Features" class="o_block_features">
 +        <section class="mb16">
              <div class="container">
                  <div class="row mt16 mb16">
                      <div class="col-md-4 text-center">
          </section>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_big_picture.png"/>
 -            <span class="oe_snippet_thumbnail_title">Big Picture</span>
 -        </div>
 -        <section class="oe_snippet_body oe_dark mt16 mb16">
 +    <div name="Big Picture" class="o_block_big_picture">
 +        <section class="oe_dark mt16 mb16">
              <div class="container">
                  <div class="row">
                      <div class="col-md-12 text-center mt32 mb32">
          </section>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_three_columns.png"/>
 -            <span class="oe_snippet_thumbnail_title">Three Columns</span>
 -        </div>
 -        <section class="oe_snippet_body mt16 mb16">
 +    <div name="Three Columns" class="o_block_three_columns">
 +        <section class="mt16 mb16">
              <div class="container">
                  <div class="row">
                      <div class="col-md-4">
  
  <div id="snippet_content" class="tab-pane">
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_well.png"/>
 -            <span class="oe_snippet_thumbnail_title">Well</span>
 -        </div>
 -        <div class="oe_snippet_body well">
 +    <div name="Well" class="o_block_well">
 +        <div class="well">
              Explain the benefits you offer. Don't write about products or
              services here, write about solutions.
          </div>
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_quote.png"/>
 -            <span class="oe_snippet_thumbnail_title">Quote</span>
 -        </div>
 -        <blockquote class="oe_snippet_body">
 +    <div name="Quote" class="o_block_quote">
 +        <blockquote>
              <p>
                  Write a quote here from one of your customers. Quotes are a
                  great way to build confidence in your products or services.
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_panel.png"/>
 -            <span class="oe_snippet_thumbnail_title">Panel</span>
 -        </div>
 -        <div class="oe_snippet_body panel panel-default">
 +    <div name="Panel" class="o_block_panel">
 +        <div class="panel panel-default">
              <div class="panel-heading">
                  <h3 class="panel-title">Feature Title</h3>
              </div>
          </div>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_separator.png"/>
 -            <span class="oe_snippet_thumbnail_title">Separator</span>
 -        </div>
 -        <hr class="oe_snippet_body"/>
 +    <div name="Separator" class="o_block_separator">
 +        <hr/>
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_button.png"/>
 -            <span class="oe_snippet_thumbnail_title">Share</span>
 -        </div>
 -        <div class="oe_snippet_body oe_share">
 +    <div name="Share" class="o_block_button">
 +        <div class="oe_share">
              <h3>
                  Share 
                  <a target="_Blank" class="oe_share_facebook" href="https://www.facebook.com/sharer/sharer.php?u={url}"><i class="fa fa-facebook-square"></i></a>
          </div>
      </div>
  
 +    <div name="Table" class="o_block_table">
 +        <section class="oe_snippet_body mt16 mb16">
 +            <div class="container">
 +                <div class="row">
 +                    <div class="col-md-8">
 +                        <table cellspacing="0" class="table_desc">
 +                            <tbody>
 +                                <tr><th class="table_heading" colspan="2">Description</th></tr>
 +                                <tr>
 +                                    <td></td>
 +                                    <td>(Press Tab to add a new row)</td>
 +                                </tr>
 +                            </tbody>
 +                        </table>
 +                    </div>
 +                    <div class="col-md-4">
 +                        <img class="img img-rounded img-responsive" src="/website/static/src/img/library/ipad.png"/>
 +                        <h4 class="mt16">Description</h4>
 +                        <p>
 +                            To add a related product list, reduce 
 +                            the size of these three columns using 
 +                            the right icon of each block.
 +                        </p>
 +                    </div>
 +                </div>
 +            </div>
 +        </section>
 +    </div>
  </div>
  
  <div id="snippet_feature" class="tab-pane">
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_image_gallery.png"/>
 -            <span class="oe_snippet_thumbnail_title">Image Gallery</span>
 -        </div>
 -        <section class="oe_snippet_body">
 +    <div name="Image Gallery" class="o_block_image_gallery">
 +        <section class="o_gallery o_nomode o_spc-none">
              <div class="container">
                  <div class="row">
 -                    <div class="col-md-12 text-center mt16 mb32">
 -                        <h2>Our Customer References</h2>
 -                        <h4 class="text-muted">More than 500 successful projects</h4>
 -                    </div>
                      <div class="col-md-6">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/desert.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/desert.jpg"/>
                      </div>
                      <div class="col-md-3">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/china_thumb.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/china_thumb.jpg"/>
                      </div>
                      <div class="col-md-3">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/deers_thumb.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/deers_thumb.jpg"/>
                      </div>
                      <div class="col-md-3">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/desert_thumb.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/desert_thumb.jpg"/>
                      </div>
                      <div class="col-md-3">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/china_thumb.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/china_thumb.jpg"/>
                      </div>
                      <div class="col-md-3">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/deers_thumb.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/deers_thumb.jpg"/>
                      </div>
                      <div class="col-md-6">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/landscape.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/landscape.jpg"/>
                      </div>
                      <div class="col-md-3">
 -                        <img class="img img-thumbnail img-responsive mb16" src="/website/static/src/img/china_thumb.jpg"/>
 +                        <img class="img img-thumbnail img-responsive mb8 mt8" src="/website/static/src/img/china_thumb.jpg"/>
                      </div>
                  </div>
              </div>
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_comparison.png"/>
 -            <span class="oe_snippet_thumbnail_title">Comparisons</span>
 -        </div>
 -        <section class="oe_snippet_body">
 +    <div name="Comparisons" class="o_block_comparison">
 +        <section>
              <div class="container">
                <div class="row">
                  <div class="col-md-12 text-center mt16 mb32">
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_button.png"/>
 -            <span class="oe_snippet_thumbnail_title">Button</span>
 -        </div>
 -        <section class="oe_snippet_body jumbotron">
 +    <div name="Button" class="o_block_button">
 +        <section class="jumbotron">
              <div class="container">
                  <div class="row">
                      <div class="col-md-9 text-muted">
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_faq.png"/>
 -            <span class="oe_snippet_thumbnail_title">FAQ</span>
 -        </div>
 -        <section class="oe_snippet_body">
 +    <div name="FAQ" class="o_block_faq">
 +        <section>
              <div class="container">
                  <h2 class="page-header">
                      Point of Sale Questions <small>v7</small>
      </div>
  
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_references.png"/>
 -            <span class="oe_snippet_thumbnail_title">References</span>
 -        </div>
 -        <section class="oe_snippet_body mb32 mt16">
 +    <div name="References" class="o_block_references">
 +        <section class="mb32 mt16">
              <div class="container">
                  <div class="row">
                      <div class="col-md-12">
          </section>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_quotes_slider.png"/>
 -            <span class="oe_snippet_thumbnail_title">Quotes Slider</span>
 -        </div>
 -        <div id="myQuoteCarousel" class="oe_snippet_body carousel quotecarousel slide mb0">
 +    <div name="Quotes Slider" class="o_block_quotes_slider">
 +        <div id="myQuoteCarousel" class="carousel quotecarousel slide mb0" data-interval="10000">
              <!-- Indicators -->
              <ol class="carousel-indicators mb0">
                  <li data-target="#myQuoteCarousel" data-slide-to="0" class="active"></li>
          </div>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_features.png"/>
 -            <span class="oe_snippet_thumbnail_title">Feature Grid</span>
 -        </div>
 -        <section class="oe_snippet_body mb16">
 +    <div name="Feature Grid" class="o_block_features">
 +        <section class="mb16">
              <div class="container">
                  <div class="row">
                      <div class="col-md-5 text-center">
  
  <div id="snippet_effect" class="tab-pane">
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_parallax.png"/>
 -            <span class="oe_snippet_thumbnail_title">Parallax</span>
 -        </div>
 -        <section class="oe_snippet_body parallax"
 +    <div name="Parallax" class="o_block_parallax">
 +        <section class="parallax"
                  style="background-image: url('/website/static/src/img/banner/mountains.jpg')"
                  data-scroll-background-ratio="0.3">
                  <div><div class="oe_structure"/></div>
          </section>
      </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_quotes_slider.png"/>
 -            <span class="oe_snippet_thumbnail_title">Parallax Slider</span>
 -        </div>
 -        <section class="oe_snippet_body parallax"
 +    <div name="Parallax Slider" class="o_block_quotes_slider">
 +        <section class="parallax"
                   style="background-image: url('/website/static/src/img/parallax/quote.png')"
                  data-scroll-background-ratio="0.3">
              <div><div><div class="oe_structure">
 -                    <div id="myQuoteCarousel" class="carousel quotecarousel slide mb0">
 +                    <div id="myQuoteCarousel" class="carousel quotecarousel slide mb0" data-interval="10000">
                          <!-- Indicators -->
                          <ol class="carousel-indicators mb0">
                              <li data-target="#myQuoteCarousel" data-slide-to="0" class="active"></li>
  
  <template id="snippet_options">
  
 -    <div data-snippet-option-id='blog-style'
 -        data-selector="section:not(.carousel):not(.parallax)">
 +    <div data-js='blog-style'
 +        data-selector="section:not(.carousel):not(.parallax):not(.o_gallery)">
          <li class="dropdown-submenu">
              <a tabindex="-1" href="#">Style</a>
              <ul class="dropdown-menu">
 -                <li data-value="para_large"><a>Bigger Text</a></li>
 -                <li data-value="readable"><a>Narrow</a></li>
 +                <li data-toggle_class="para_large"><a>Bigger Text</a></li>
 +                <li data-toggle_class="readable"><a>Narrow</a></li>
              </ul>
          </li>
      </div>
  
 -    <div data-snippet-option-id='background'
 -        data-selector="section, .carousel, .parallax">
 -        <li class="dropdown-submenu" data-required="true">
 +    <div data-js='background'
 +        data-selector="section, :not(.o_gallery > .container) > .carousel, .parallax">
 +        <li class="dropdown-submenu" data-background="">
              <a tabindex="-1" href="#">Background</a>
              <ul class="dropdown-menu">
 -                <li class="dropdown-submenu">
 -                    <a tabindex="-2" href="#">Uniform Color</a>
 -                    <ul class="dropdown-menu">
 -                        <li data-value='oe_dark'><a>Darken</a></li>
 -                        <li data-value='oe_green'><a>Green</a></li>
 -                        <li data-value='oe_red'><a>Red</a></li>
 -                        <li data-value='oe_blue_light'><a>Turquoise</a></li>
 -                        <li data-value='oe_blue'><a>Dark Blue</a></li>
 -                        <li data-value='oe_orange'><a>Orange</a></li>
 -                        <li data-value='oe_purple'><a>Purple</a></li>
 -                        <li data-value='oe_black'><a>Black</a></li>
 -                    </ul>
 -                </li>
 -                <li class="dropdown-submenu">
 -                    <a tabindex="-2" href="#">People</a>
 -                    <ul class="dropdown-menu">
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/parallax/parallax_bg.jpg"><a>Sunflower</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/business_guy.jpg"><a>Business Guy</a></li>
 -                    </ul>
 -                </li>
 -                <li class="dropdown-submenu">
 -                    <a tabindex="-2" href="#">Landscape</a>
 -                    <ul class="dropdown-menu">
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/flower_field.jpg"><a>Flowers Field</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/landscape.jpg"><a>Landscape</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/mountains.jpg"><a>Mountains</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/greenfields.jpg"><a>Greenfields</a></li>
 -                    </ul>
 -                </li>
 -                <li class="dropdown-submenu">
 -                    <a tabindex="-2" href="#">Various</a>
 -                    <ul class="dropdown-menu">
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/aqua.jpg"><a>Aqua</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/baby_blue.jpg"><a>Baby Blue</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/black.jpg"><a>Black</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/color_splash.jpg"><a>Color Splash</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/mango.jpg"><a>Mango</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/orange_red.jpg"><a>Orange Red</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/flower.jpg"><a>Purple</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/velour.jpg"><a>Velour</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/wood.jpg"><a>Wood</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/banner/yellow_green.jpg"><a>Yellow Green</a></li>
 -                        <li data-value="oe_img_bg" data-src="/website/static/src/img/parallax/quote.png"><a>Quote</a></li>
 -                    </ul>
 -                </li>
 -                <li data-value=""><a>None</a></li>
 +                <li data-background="/website/static/src/img/parallax/parallax_bg.jpg"><a>Sunflower</a></li>
 +                <li data-background="/website/static/src/img/banner/business_guy.jpg"><a>Business Guy</a></li>
 +                <li data-background="/website/static/src/img/banner/flower_field.jpg"><a>Flowers Field</a></li>
 +                <li data-background="/website/static/src/img/banner/landscape.jpg"><a>Landscape</a></li>
 +                <li data-background="/website/static/src/img/banner/mountains.jpg"><a>Mountains</a></li>
 +                <li data-background="/website/static/src/img/banner/greenfields.jpg"><a>Greenfields</a></li>
 +                <li data-background="/website/static/src/img/banner/aqua.jpg"><a>Aqua</a></li>
 +                <li data-background="/website/static/src/img/banner/baby_blue.jpg"><a>Baby Blue</a></li>
 +                <li data-background="/website/static/src/img/banner/black.jpg"><a>Black</a></li>
 +                <li data-background="/website/static/src/img/banner/color_splash.jpg"><a>Color Splash</a></li>
 +                <li data-background="/website/static/src/img/banner/mango.jpg"><a>Mango</a></li>
 +                <li data-background="/website/static/src/img/banner/orange_red.jpg"><a>Orange Red</a></li>
 +                <li data-background="/website/static/src/img/banner/flower.jpg"><a>Purple</a></li>
 +                <li data-background="/website/static/src/img/banner/velour.jpg"><a>Velour</a></li>
 +                <li data-background="/website/static/src/img/banner/wood.jpg"><a>Wood</a></li>
 +                <li data-background="/website/static/src/img/banner/yellow_green.jpg"><a>Yellow Green</a></li>
 +                <li data-background="/website/static/src/img/parallax/quote.png"><a>Quote</a></li>
 +                <li data-background=""><a>None</a></li>
                  <li><a style="background: none; padding: 5px; border-top: 1px solid #ddd;"></a></li>
 -                <li class="oe_custom_bg" data-value="oe_img_bg"><a><b>Choose an image...</b></a></li>
 +                <li data-choose_image="choose_image" data-background=""><a><b>Choose an image...</b></a></li>
              </ul>
          </li>
      </div>
 +     
 +    <div data-js='gallery' data-selector=".o_gallery">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Mode</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-mode="nomode"   > <a>None</a></li>
 +                <li data-mode="masonry"  > <a>Masonry</a> </li>
 +                <li data-mode="grid"     > <a>Grid</a> </li>
 +                <li data-mode="slideshow"> <a>Slideshow</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Slideshow speed</a>
 +            <ul class="dropdown-menu">
 +                 <li data-interval="1000"> <a>1s</a> </li>
 +                 <li data-interval="2000"> <a>2s</a> </li>
 +                 <li data-interval="3000"> <a>3s</a> </li>
 +                 <li data-interval="5000"> <a>5s</a> </li>
 +                 <li data-interval="10000"> <a>10s</a></li>
 +                 <li data-interval="0"   > <a>Disable autoplay</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Columns</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-columns="1"  > <a>1</a> </li>
 +                <li data-columns="2"  > <a>2</a> </li>
 +                <li data-columns="3"  > <a>3</a> </li>
 +                <li data-columns="4"  > <a>4</a> </li>
 +                <li data-columns="6"  > <a>6</a> </li>
 +                <li data-columns="12" > <a>12</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Images spacing</a>
  
 -    <div data-snippet-option-id='carousel'
 -        data-selector=".carousel">
 -        <li class="divider"></li>
 -        <li>
 -            <a href="#" class="button js_add">Add Slide</a>
 +            <ul class="dropdown-menu">
 +                <li data-select_class="o_spc-none"  > <a>None</a>   </li>
 +                <li data-select_class="o_spc-small" > <a>Small</a>  </li>
 +                <li data-select_class="o_spc-medium"> <a>Medium</a> </li>
 +                <li data-select_class="o_spc-big"   > <a>Big</a>    </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Album</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-albumimages="images_add"> <a>Add images</a></li>
 +               <li data-albumimages="images_rm"><a>Remove all images</a></li>
 +           </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Styling</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-styling="img-rounded"   ><a>Rounded corners</a></li>
 +               <li data-styling="img-thumbnail" ><a>Thumbnails</a></li>
 +               <li data-styling="img-circle"    ><a>Circle</a></li>
 +               <li data-styling="shadow"        ><a>Shadows</a></li>
 +               <li data-styling="fa-spin"       ><a>Spinning</a></li>
 +           </ul>
 +        </li>
 +    </div>
 +
 +    <div data-js='colorpicker'
 +        data-selector="section, :not(.o_gallery > .container) > .carousel, .parallax">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-1" href="#">Color</a>
 +            <ul class="dropdown-menu">
 +                <li></li>
 +            </ul>
          </li>
 -        <li>
 -            <a href="#" class="button js_remove">Remove Slide</a>
 +    </div>
 +     
 +    <div data-js='gallery' data-selector=".gallery">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Mode</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-mode="nomode"   > <a>None</a></li>
 +                <li data-mode="masonry"  > <a>Masonry</a> </li>
 +                <li data-mode="grid"     > <a>Grid</a> </li>
 +                <li data-mode="slideshow"> <a>Slideshow</a> </li>
 +            </ul>
          </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Slideshow speed</a>
 +            <ul class="dropdown-menu">
 +                 <li data-interval="1000"> <a>1s</a> </li>
 +                 <li data-interval="2000"> <a>2s</a> </li>
 +                 <li data-interval="3000"> <a>3s</a> </li>
 +                 <li data-interval="5000"> <a>5s</a> </li>
 +                 <li data-interval="10000"> <a>10s</a></li>
 +                 <li data-interval="0"   > <a>Disable autoplay</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Columns</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-columns="1"  > <a>1</a> </li>
 +                <li data-columns="2"  > <a>2</a> </li>
 +                <li data-columns="3"  > <a>3</a> </li>
 +                <li data-columns="4"  > <a>4</a> </li>
 +                <li data-columns="6"  > <a>6</a> </li>
 +                <li data-columns="12" > <a>12</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Images spacing</a>
 +
 +            <ul class="dropdown-menu">
 +                <li data-select_class="spc-none"  > <a>None</a>   </li>
 +                <li data-select_class="spc-small" > <a>Small</a>  </li>
 +                <li data-select_class="spc-medium"> <a>Medium</a> </li>
 +                <li data-select_class="spc-big"   > <a>Big</a>    </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Album</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-albumimages="images_add"> <a>Add images</a></li>
 +               <li data-albumimages="images_rm"><a>Remove all images</a></li>
 +           </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Styling</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-styling="img-rounded"   ><a>Rounded corners</a></li>
 +               <li data-styling="img-thumbnail" ><a>Thumbnails</a></li>
 +               <li data-styling="img-circle"    ><a>Circle</a></li>
 +               <li data-styling="shadow"        ><a>Shadows</a></li>
 +               <li data-styling="fa-spin"       ><a>Spinning</a></li>
 +           </ul>
 +        </li>
 +    </div>
 +
 +    <div data-js='carousel'
 +        data-selector=":not(.o_gallery > .container) > .carousel">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Slideshow speed</a>
 +            <ul class="dropdown-menu">
 +                 <li data-interval="1000"> <a>1s</a> </li>
 +                 <li data-interval="2000"> <a>2s</a> </li>
 +                 <li data-interval="3000"> <a>3s</a> </li>
 +                 <li data-interval="5000"> <a>5s</a> </li>
 +                 <li data-interval="10000"> <a>10s</a></li>
 +                 <li data-interval="0"   > <a>Disable autoplay</a> </li>
 +            </ul>
 +        </li>
 +        <li class="divider"></li>
 +        <li data-add_slide="true"> <a href="#">Add Slide</a> </li>
 +        <li data-remove_slide="true"> <a href="#" >Remove Slide</a></li>
      </div>
  
 -    <div data-snippet-option-id='margin-y'
 -        data-selector="section, .row > [class*='col-md-'], .carousel, .parallax, hr">
 +    <div data-js='margin-y'
 +        data-selector="section, .row > [class*='col-md-'], :not(.o_gallery > .container) > .carousel, .parallax, hr">
      </div>
  
 -    <div data-snippet-option-id='resize'
 -        data-selector="section, .carousel, .parallax"
 -        data-selector-children=".oe_structure, [data-oe-type=html]">
 +    <div data-js='resize'
 +        data-selector="section, :not(.o_gallery > .container) > .carousel, .parallax"
 +        data-drop-in=".oe_structure, [data-oe-type=html]">
      </div>
  
 -    <div data-snippet-option-id='margin-x'
 +    <div data-js='margin-x'
          data-selector=".row > [class*='col-md-']"
 -        data-selector-vertical-children='.row'>
 +        data-drop-near=".row > [class*='col-md-']">
      </div>
  
 -    <div data-snippet-option-id='content'
 +    <div data-js='content'
          data-selector="blockquote, .well, .panel, .oe_share, .o_image_floating"
 -        data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel, .oe_share"
 -        data-selector-children=".content">
 +        data-drop-near="p, h1, h2, h3, blockquote, .well, .panel, .oe_share"
 +        data-drop-in=".content">
      </div>
  
 -    <div data-snippet-option-id='separator'
 +    <div data-js='separator'
          data-selector="hr"
 -        data-selector-children=".oe_structure, [data-oe-type=html]">
 +        data-drop-in=".oe_structure, [data-oe-type=html]">
      </div>
  
      <div data-snippet-option-id='image_floating_margin'
          </li>
      </div>
  
 -    <div data-snippet-option-id='parallax'
 +    <div data-js='parallax'
          data-selector=".parallax">
          <li class="dropdown-submenu">
              <a tabindex="-1" href="#">Scroll Speed</a>
              <ul class="dropdown-menu" name="parallax-scroll">
 -                <li data-value="0"><a>Static</a></li>
 -                <li data-value="0.3"><a>Very Slow</a></li>
 -                <li data-value="0.6"><a>Slow</a></li>
 -                <li data-value="1"><a>Fixed</a></li>
 -                <li data-value="1.4"><a>Fast</a></li>
 -                <li data-value="1.7"><a>Very Fast</a></li>
 +                <li data-scroll="0"><a>Static</a></li>
 +                <li data-scroll="0.3"><a>Very Slow</a></li>
 +                <li data-scroll="0.6"><a>Slow</a></li>
 +                <li data-scroll="1"><a>Fixed</a></li>
 +                <li data-scroll="1.4"><a>Fast</a></li>
 +                <li data-scroll="1.7"><a>Very Fast</a></li>
              </ul>
          </li>
      </div>
  
 -    <div data-snippet-option-id='media'
 +    <div data-js='media'
          data-selector="img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa, .glyphicon">
 -        <li><a href="#" class="edition">Change...</a></li>
 +        <li data-edition="edition"><a>Change...</a></li>
      </div>
  
 -    <div data-snippet-option-id='transform'
 +    <div data-js='transform'
          data-selector="img:not(.cke_iframe), .media_iframe_video, span.fa, i.fa">
          <li class="dropdown-submenu">
              <a tabindex="-1" href="#">Style</a>
              <ul class="dropdown-menu" name="parallax-scroll">
 -                <li data-value="img-rounded"><a>Rounded corners</a></li>
 -                <li data-value="img-thumbnail"><a>Box</a></li>
 -                <li data-value="img-circle"><a>Circle</a></li>
 -                <li data-value="shadow"><a>Shadow</a></li>
 -                <li data-value="fa-spin"><a>Spin</a></li>
 +                <li data-select_class="img-rounded"><a>Rounded corners</a></li>
 +                <li data-select_class="img-thumbnail"><a>Box</a></li>
 +                <li data-select_class="img-circle"><a>Circle</a></li>
 +                <li data-select_class="shadow"><a>Shadow</a></li>
 +                <li data-select_class="fa-spin"><a>Spin</a></li>
              </ul>
          </li>
 -        <li><a href="#" class="style">Transform</a></li>
 -        <li><a href="#" class="clear-style">Reset Transformation</a></li>
 +        <li data-style=""><a>Transform</a></li>
 +        <li data-clear_style=""><a>Reset Transformation</a></li>
      </div>
  
  </template>
@@@ -5,8 -5,6 +5,8 @@@ import werkzeug.url
  import werkzeug.wrappers
  import re
  import simplejson
 +import lxml
 +from urllib2 import urlopen
  
  from openerp import tools
  from openerp import SUPERUSER_ID
@@@ -42,7 -40,6 +42,7 @@@ class WebsiteForum(http.Controller)
                    'notifications': self._get_notifications(),
                    'header': kwargs.get('header', dict()),
                    'searches': kwargs.get('searches', dict()),
 +                  'no_introduction_message': request.httprequest.cookies.get('no_introduction_message', False),
                    }
          if forum:
              values['forum'] = forum
@@@ -79,7 -76,7 +79,7 @@@
                   '''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions''',
                   '''/forum/<model("forum.forum"):forum>/tag/<model("forum.tag", "[('forum_id','=',forum[0])]"):tag>/questions/page/<int:page>''',
                   ], type='http', auth="public", website=True)
 -    def questions(self, forum, tag=None, page=1, filters='all', sorting='date', search='', **post):
 +    def questions(self, forum, tag=None, page=1, filters='all', sorting=None, search='', post_type=None, **post):
          cr, uid, context = request.cr, request.uid, request.context
          Post = request.registry['forum.post']
          user = request.registry['res.users'].browse(cr, uid, uid, context=context)
              domain += [('child_ids', '=', False)]
          elif filters == 'followed':
              domain += [('message_follower_ids', '=', user.partner_id.id)]
 -        else:
 -            filters = 'all'
 -
 -        if sorting == 'answered':
 -            order = 'child_count desc'
 -        elif sorting == 'vote':
 -            order = 'vote_count desc'
 -        elif sorting == 'date':
 -            order = 'write_date desc'
 -        else:
 -            sorting = 'creation'
 -            order = 'create_date desc'
 +
 +        if post_type:
 +            domain += [('type', '=', post_type)]
 +        if not sorting:
 +            sorting = forum.default_order
  
          question_count = Post.search(cr, uid, domain, count=True, context=context)
          if tag:
          else:
              url = "/forum/%s" % slug(forum)
  
 -        url_args = {}
 +        url_args = {
 +            'sorting': sorting
 +        }
          if search:
              url_args['search'] = search
          if filters:
              url_args['filters'] = filters
 -        if sorting:
 -            url_args['sorting'] = sorting
          pager = request.website.pager(url=url, total=question_count, page=page,
                                        step=self._post_per_page, scope=self._post_per_page,
                                        url_args=url_args)
  
 -        obj_ids = Post.search(cr, uid, domain, limit=self._post_per_page, offset=pager['offset'], order=order, context=context)
 +        obj_ids = Post.search(cr, uid, domain, limit=self._post_per_page, offset=pager['offset'], order=sorting, context=context)
          question_ids = Post.browse(cr, uid, obj_ids, context=context)
  
          values = self._prepare_forum_values(forum=forum, searches=post)
              'filters': filters,
              'sorting': sorting,
              'search': search,
 +            'post_type': post_type,
          })
          return request.website.render("website_forum.forum_index", values)
  
      # Questions
      # --------------------------------------------------
  
 -    @http.route(['/forum/<model("forum.forum"):forum>/ask'], type='http', auth="public", website=True)
 -    def question_ask(self, forum, **post):
 -        if not request.session.uid:
 -            return login_redirect()
 -        values = self._prepare_forum_values(forum=forum, searches={},  header={'ask_hide': True})
 -        return request.website.render("website_forum.ask_question", values)
 -
 -    @http.route('/forum/<model("forum.forum"):forum>/question/new', type='http', auth="user", methods=['POST'], website=True)
 -    def question_create(self, forum, **post):
 -        cr, uid, context = request.cr, request.uid, request.context
 -        Tag = request.registry['forum.tag']
 -        question_tag_ids = []
 -        if post.get('question_tags').strip('[]'):
 -            tags = post.get('question_tags').strip('[]').replace('"', '').split(",")
 -            for tag in tags:
 -                tag_ids = Tag.search(cr, uid, [('name', '=', tag)], context=context)
 -                if tag_ids:
 -                    question_tag_ids.append((4, tag_ids[0]))
 -                else:
 -                    question_tag_ids.append((0, 0, {'name': tag, 'forum_id': forum.id}))
 -
 -        new_question_id = request.registry['forum.post'].create(
 -            request.cr, request.uid, {
 -                'forum_id': forum.id,
 -                'name': post.get('question_name'),
 -                'content': post.get('content'),
 -                'tag_ids': question_tag_ids,
 -            }, context=context)
 -        return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), new_question_id))
 +    @http.route('/forum/get_url_title', type='json', auth="user", methods=['POST'], website=True)
 +    def get_url_title(self, **kwargs):
 +        arch = lxml.html.parse(urlopen(kwargs.get('url')))
 +        return arch.find(".//title").text
  
      @http.route(['''/forum/<model("forum.forum"):forum>/question/<model("forum.post", "[('forum_id','=',forum[0]),('parent_id','=',False)]"):question>'''], type='http', auth="public", website=True)
      def question(self, forum, question, **post):
              'forum': forum,
              'reasons': reasons,
          })
 -        return request.website.render("website_forum.close_question", values)
 +        return request.website.render("website_forum.close_post", values)
  
      @http.route('/forum/<model("forum.forum"):forum>/question/<model("forum.post"):question>/edit_answer', type='http', auth="user", website=True)
      def question_edit_answer(self, forum, question, **kwargs):
      # Post
      # --------------------------------------------------
  
 -    @http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/new', type='http', auth="public", methods=['POST'], website=True)
 -    def post_new(self, forum, post, **kwargs):
 +    @http.route(['/forum/<model("forum.forum"):forum>/<post_type>'], type='http', auth="public", website=True)
 +    def forum_post(self, forum, post_type, **post):
          if not request.session.uid:
              return login_redirect()
          cr, uid, context = request.cr, request.uid, request.context
          user = request.registry['res.users'].browse(cr, SUPERUSER_ID, uid, context=context)
          if not user.email or not tools.single_email_re.match(user.email):
              return werkzeug.utils.redirect("/forum/%s/user/%s/edit?email_required=1" % (slug(forum), uid))
 -        request.registry['forum.post'].create(
 -            request.cr, request.uid, {
 +        values = self._prepare_forum_values(forum=forum, searches={},  header={'ask_hide': True})
 +        return request.website.render("website_forum.%s" % post_type, values)
 +
 +    @http.route(['/forum/<model("forum.forum"):forum>/<post_type>/new',
 +                 '/forum/<model("forum.forum"):forum>/<model("forum.post"):post_parent>/reply']
 +                , type='http', auth="public", methods=['POST'], website=True)
 +    def post_create(self, forum, post_parent='', post_type='', **post):
 +        cr, uid, context = request.cr, request.uid, request.context
 +        if not request.session.uid:
 +            return login_redirect()
 +
 +        post_tag_ids = []
 +        Tag = request.registry['forum.tag']
 +        if post.get('post_tags', False) and post.get('post_tags').strip('[]'):
 +            tags = post.get('post_tags').strip('[]').replace('"', '').split(",")
 +            for tag in tags:
 +                tag_ids = Tag.search(cr, uid, [('name', '=', tag)], context=context)
 +                if tag_ids:
 +                    post_tag_ids.append((4, tag_ids[0]))
 +                else:
 +                    post_tag_ids.append((0, 0, {'name': tag, 'forum_id': forum.id}))
 +
 +        new_question_id = request.registry['forum.post'].create(cr, uid, {
                  'forum_id': forum.id,
 -                'parent_id': post.id,
 -                'content': kwargs.get('content'),
 -            }, context=request.context)
 -        return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(post)))
 +                'name': post.get('post_name', ''),
 +                'content': post.get('content', False),
 +                'content_link': post.get('content_link', False),
 +                'parent_id': post_parent and post_parent.id or False,
 +                'tag_ids': post_tag_ids,
 +                'type': post_parent and post_parent.type or post_type,
 +            }, context=context)
 +        return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), post_parent and slug(post_parent) or new_question_id))
  
      @http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/comment', type='http', auth="public", methods=['POST'], website=True)
      def post_comment(self, forum, post, **kwargs):
          cr, uid, context = request.cr, request.uid, request.context
          if kwargs.get('comment') and post.forum_id.id == forum.id:
              # TDE FIXME: check that post_id is the question or one of its answers
-             request.registry['forum.post'].message_post(
-                 cr, uid, post.id,
+             request.registry['forum.post']._post_comment(
+                 cr, uid, post,
                  body=kwargs.get('comment'),
-                 type='comment',
-                 subtype='mt_comment',
-                 context=dict(context, mail_create_nosubcribe=True))
+                 context=context)
          return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), slug(question)))
  
      @http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/toggle_correct', type='json', auth="public", website=True)
      @http.route('/forum/<model("forum.forum"):forum>/post/<model("forum.post"):post>/save', type='http', auth="user", methods=['POST'], website=True)
      def post_save(self, forum, post, **kwargs):
          cr, uid, context = request.cr, request.uid, request.context
 -        question_tags = []
 -        if kwargs.get('question_tag') and kwargs.get('question_tag').strip('[]'):
 +        post_tags = []
 +        if kwargs.get('post_tag') and kwargs.get('post_tag').strip('[]'):
              Tag = request.registry['forum.tag']
 -            tags = kwargs.get('question_tag').strip('[]').replace('"', '').split(",")
 +            tags = kwargs.get('post_tag').strip('[]').replace('"', '').split(",")
              for tag in tags:
                  tag_ids = Tag.search(cr, uid, [('name', '=', tag)], context=context)
                  if tag_ids:
 -                    question_tags += tag_ids
 +                    post_tags += tag_ids
                  else:
                      new_tag = Tag.create(cr, uid, {'name': tag, 'forum_id': forum.id}, context=context)
 -                    question_tags.append(new_tag)
 +                    post_tags.append(new_tag)
          vals = {
 -            'tag_ids': [(6, 0, question_tags)],
 -            'name': kwargs.get('question_name'),
 +            'tag_ids': [(6, 0, post_tags)],
 +            'name': kwargs.get('post_name'),
              'content': kwargs.get('content'),
          }
          request.registry['forum.post'].write(cr, uid, [post.id], vals, context=context)
@@@ -10,8 -10,9 +10,9 @@@ from openerp.osv import osv, field
  from openerp.tools import html2plaintext
  from openerp.tools.translate import _
  
+ from werkzeug.exceptions import Forbidden
  
- class KarmaError(ValueError):
+ class KarmaError(Forbidden):
      """ Karma-related error, used for forum and posts. """
      pass
  
@@@ -23,55 -24,41 +24,55 @@@ class Forum(osv.Model)
      _inherit = ['mail.thread', 'website.seo.metadata']
  
      _columns = {
 -        'name': fields.char('Name', required=True, translate=True),
 +        'name': fields.char('Forum Name', required=True, translate=True),
          'faq': fields.html('Guidelines'),
          'description': fields.html('Description'),
 +        'introduction_message': fields.html('Introduction Message'),
 +        'relevancy_option_first': fields.float('First Relevancy Parameter'),
 +        'relevancy_option_second': fields.float('Second Relevancy Parameter'),
 +        'default_order': fields.selection([
 +            ('create_date desc','Newest'),
 +            ('write_date desc','Last Updated'),
 +            ('vote_count desc','Most Voted'),
 +            ('relevancy desc','Relevancy'),
 +            ('child_count desc','Answered'),
 +            ], 'Default Order', required=True),
 +        'default_allow': fields.selection([('post_link','Link'),('ask_question','Question'),('post_discussion','Discussion')], 'Default Post', required=True),
 +        'allow_link': fields.boolean('Links', help="When clicking on the post, it redirects to an external link"),
 +        'allow_question': fields.boolean('Questions', help="Users can answer only once per question. Contributors can edit answers and mark the right ones."),
 +        'allow_discussion': fields.boolean('Discussions'),
          # karma generation
 -        'karma_gen_question_new': fields.integer('Karma earned for new questions'),
 -        'karma_gen_question_upvote': fields.integer('Karma earned for upvoting a question'),
 -        'karma_gen_question_downvote': fields.integer('Karma earned for downvoting a question'),
 -        'karma_gen_answer_upvote': fields.integer('Karma earned for upvoting an answer'),
 -        'karma_gen_answer_downvote': fields.integer('Karma earned for downvoting an answer'),
 -        'karma_gen_answer_accept': fields.integer('Karma earned for accepting an anwer'),
 -        'karma_gen_answer_accepted': fields.integer('Karma earned for having an answer accepted'),
 -        'karma_gen_answer_flagged': fields.integer('Karma earned for having an answer flagged'),
 +        'karma_gen_question_new': fields.integer('Post a Questions'),
 +        'karma_gen_question_upvote': fields.integer('Upvote a Question'),
 +        'karma_gen_question_downvote': fields.integer('Downvote a Question'),
 +        'karma_gen_answer_upvote': fields.integer('Upvote an Answer'),
 +        'karma_gen_answer_downvote': fields.integer('Downvote an answer'),
 +        'karma_gen_answer_accept': fields.integer('Accept an Answer'),
 +        'karma_gen_answer_accepted': fields.integer('Have Your Answer Accepted'),
 +        'karma_gen_answer_flagged': fields.integer('Have Your Answer Flagged'),
          # karma-based actions
 -        'karma_ask': fields.integer('Karma to ask a new question'),
 -        'karma_answer': fields.integer('Karma to answer a question'),
 -        'karma_edit_own': fields.integer('Karma to edit its own posts'),
 -        'karma_edit_all': fields.integer('Karma to edit all posts'),
 -        'karma_close_own': fields.integer('Karma to close its own posts'),
 -        'karma_close_all': fields.integer('Karma to close all posts'),
 -        'karma_unlink_own': fields.integer('Karma to delete its own posts'),
 -        'karma_unlink_all': fields.integer('Karma to delete all posts'),
 -        'karma_upvote': fields.integer('Karma to upvote'),
 -        'karma_downvote': fields.integer('Karma to downvote'),
 -        'karma_answer_accept_own': fields.integer('Karma to accept an answer on its own questions'),
 -        'karma_answer_accept_all': fields.integer('Karma to accept an answers to all questions'),
 -        'karma_editor_link_files': fields.integer('Karma for linking files (Editor)'),
 -        'karma_editor_clickable_link': fields.integer('Karma for clickable links (Editor)'),
 -        'karma_comment_own': fields.integer('Karma to comment its own posts'),
 -        'karma_comment_all': fields.integer('Karma to comment all posts'),
 -        'karma_comment_convert_own': fields.integer('Karma to convert its own answers to comments and vice versa'),
 -        'karma_comment_convert_all': fields.integer('Karma to convert all answers to answers and vice versa'),
 -        'karma_comment_unlink_own': fields.integer('Karma to unlink its own comments'),
 -        'karma_comment_unlink_all': fields.integer('Karma to unlinnk all comments'),
 -        'karma_retag': fields.integer('Karma to change question tags'),
 -        'karma_flag': fields.integer('Karma to flag a post as offensive'),
 +        'karma_ask': fields.integer('Ask a new question'),
 +        'karma_answer': fields.integer('Answer a question'),
 +        'karma_edit_own': fields.integer('Edit its own posts'),
 +        'karma_edit_all': fields.integer('Edit all posts'),
 +        'karma_close_own': fields.integer('Close its own posts'),
 +        'karma_close_all': fields.integer('Close all posts'),
 +        'karma_unlink_own': fields.integer('Delete its own posts'),
 +        'karma_unlink_all': fields.integer('Delete all posts'),
 +        'karma_upvote': fields.integer('Upvote'),
 +        'karma_downvote': fields.integer('Downvote'),
 +        'karma_answer_accept_own': fields.integer('Accept an answer on its own questions'),
 +        'karma_answer_accept_all': fields.integer('Accept an answers to all questions'),
 +        'karma_editor_link_files': fields.integer('Linking files (Editor)'),
 +        'karma_editor_clickable_link': fields.integer('Add clickable links (Editor)'),
 +        'karma_comment_own': fields.integer('Comment its own posts'),
 +        'karma_comment_all': fields.integer('Comment all posts'),
 +        'karma_comment_convert_own': fields.integer('Convert its own answers to comments and vice versa'),
 +        'karma_comment_convert_all': fields.integer('Convert all answers to answers and vice versa'),
 +        'karma_comment_unlink_own': fields.integer('Unlink its own comments'),
 +        'karma_comment_unlink_all': fields.integer('Unlink all comments'),
 +        'karma_retag': fields.integer('Change question tags'),
 +        'karma_flag': fields.integer('Flag a post as offensive'),
      }
  
      def _get_default_faq(self, cr, uid, context=None):
          return False
  
      _defaults = {
 +        'default_order': 'write_date desc',
 +        'allow_question': True,
 +        'default_allow': 'ask_question',
 +        'allow_link': False,
 +        'allow_discussion': False,
          'description': 'This community is for professionals and enthusiasts of our products and services.',
          'faq': _get_default_faq,
 +        'introduction_message': """<h1 class="mt0">Welcome!</h1>
 +                  <p> This community is for professionals and enthusiasts of our products and services.
 +                      Share and discuss the best content and new marketing ideas,
 +                      build your professional profile and become a better marketer together.
 +                  </p>""",
 +        'relevancy_option_first': 0.8,
 +        'relevancy_option_second': 1.8,
          'karma_gen_question_new': 2,
          'karma_gen_question_upvote': 5,
          'karma_gen_question_downvote': -2,
@@@ -140,14 -115,6 +141,14 @@@ class Post(osv.Model)
      _inherit = ['mail.thread', 'website.seo.metadata']
      _order = "is_correct DESC, vote_count DESC, write_date DESC"
  
 +    def _get_post_relevancy(self, cr, uid, ids, field_name, arg, context):
 +        res = dict.fromkeys(ids, 0)
 +        for post in self.browse(cr, uid, ids, context=context):
 +            days = (datetime.today() - datetime.strptime(post.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT)).days
 +            relavency = abs(post.vote_count - 1) ** post.forum_id.relevancy_option_first / ( days + 2) ** post.forum_id.relevancy_option_second
 +            res[post.id] = relavency if (post.vote_count - 1) >= 0 else -relavency
 +        return res
 +
      def _get_user_vote(self, cr, uid, ids, field_name, arg, context):
          res = dict.fromkeys(ids, 0)
          vote_ids = self.pool['forum.post.vote'].search(cr, uid, [('post_id', 'in', ids), ('user_id', '=', uid)], context=context)
          'name': fields.char('Title'),
          'forum_id': fields.many2one('forum.forum', 'Forum', required=True),
          'content': fields.html('Content'),
 +        'content_link': fields.char('URL', help="URL of Link Articles"),
          'tag_ids': fields.many2many('forum.tag', 'forum_tag_rel', 'forum_id', 'forum_tag_id', 'Tags'),
          'state': fields.selection([('active', 'Active'), ('close', 'Close'), ('offensive', 'Offensive')], 'Status'),
          'views': fields.integer('Number of Views'),
          'active': fields.boolean('Active'),
 +        'type': fields.selection([('question', 'Question'), ('link', 'Article'), ('discussion', 'Discussion')], 'Type'),
 +        'relevancy': fields.function(
 +            _get_post_relevancy, string="Relevancy", type='float',
 +            store={
 +                'forum.post': (lambda self, cr, uid, ids, c={}: ids, ['vote_ids'], 10),
 +                'forum.post.vote': (_get_post_from_vote, [], 10),
 +            }),
          'is_correct': fields.boolean('Valid Answer', help='Correct Answer or Answer on this question accepted.'),
          'website_message_ids': fields.one2many(
              'mail.message', 'res_id',
          'state': 'active',
          'views': 0,
          'active': True,
 +        'type': 'question',
          'vote_ids': list(),
          'favourite_ids': list(),
          'child_ids': list(),
              context = {}
          create_context = dict(context, mail_create_nolog=True)
          post_id = super(Post, self).create(cr, uid, vals, context=create_context)
-         post = self.browse(cr, SUPERUSER_ID, post_id, context=context)  # SUPERUSER_ID to avoid read access rights issues when creating
+         post = self.browse(cr, uid, post_id, context=context)
 +        # deleted or closed questions
 +        if post.parent_id and (post.parent_id.state == 'close' or post.parent_id.active == False):
 +            osv.except_osv(_('Error !'), _('Posting answer on [Deleted] or [Closed] question is prohibited'))
          # karma-based access
-         if post.parent_id and not post.can_ask:
+         if not post.parent_id and not post.can_ask:
              raise KarmaError('Not enough karma to create a new question')
-         elif not post.parent_id and not post.can_answer:
+         elif post.parent_id and not post.can_answer:
              raise KarmaError('Not enough karma to answer to a question')
          # messaging and chatter
          base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
          res_id = post.parent_id and "%s#answer-%s" % (post.parent_id.id, post.id) or post.id
          return "/forum/%s/question/%s" % (post.forum_id.id, res_id)
  
+     def _post_comment(self, cr, uid, post, body, context=None):
+         context = dict(context or {}, mail_create_nosubcribe=True)
+         if not post.can_comment:
+             raise KarmaError('Not enough karma to comment')
+         return self.message_post(cr, uid, post.id,
+                                  body=body,
+                                  type='comment',
+                                  subtype='mt_comment',
+                                  context=context)
  
  class PostReason(osv.Model):
      _name = "forum.post.reason"
@@@ -2,28 -2,6 +2,28 @@@
  <openerp>
      <data>
  
 +<!-- Editor custom -->
 +<template id="assets_editor" inherit_id="website.assets_editor" name="Forum Editor Assets" groups="base.group_user">
 +    <xpath expr="." position="inside">
 +        <link rel='stylesheet' href="/website_forum/static/src/css/website_forum.css"/>
 +        <script type="text/javascript" src="/website_forum/static/src/js/website.tour.forum.js"/>
 +        <script type="text/javascript" src="/website_forum/static/src/js/website_forum.editor.js"/>
 +    </xpath>
 +</template>
 +
 +<template id="assets_forum" name="Forum Assets">
 +    <link rel='stylesheet' href="/web/static/lib/jquery.textext/jquery.textext.css"/>
 +    <link rel='stylesheet' href='/website_forum/static/src/css/website_forum.css'/>
 +
 +    <script type="text/javascript" src="/website_forum/static/src/js/website_forum.js"/>
 +    <script type="text/javascript" src="/web/static/lib/jquery.textext/jquery.textext.js"/>
 +    <script type="text/javascript" src="/web/static/lib/ckeditor/ckeditor.js"/>
 +    <script type="text/javascript">
 +        CKEDITOR.config.toolbar = [['Bold','Italic','Underline','Strike'],['NumberedList','BulletedList', 'Blockquote']
 +        ,['Outdent','Indent','Link','Unlink','Image'],] ;
 +    </script>
 +</template>
 +
  <!-- Layout add nav and footer -->
  <template id="header_footer_custom" inherit_id="website.footer_default"
      name="Footer Questions Link">
      </form>
  </template>
  
 -<template id="assets_frontend" inherit_id="website.assets_frontend" name="website_forum assets">
 -    <xpath expr="." position="inside">
 -        <link rel='stylesheet' href="/web/static/lib/jquery.textext/jquery.textext.css"/>
 -        <link rel='stylesheet' href='/website_forum/static/src/css/website_forum.css'/>
 -        <script type="text/javascript" src="/website_forum/static/src/js/website_forum.js"/>
 -        <script type="text/javascript" src="/web/static/lib/jquery.textext/jquery.textext.js"/>
 -    </xpath>
 -</template>
 -
 -<template id="assets_editor" inherit_id="website.assets_editor" name="Forum Editor" groups="base.group_user">
 -    <xpath expr="." position="inside">
 -        <script type="text/javascript" src="/website_forum/static/src/js/website.tour.forum.js"/>
 -        <script type="text/javascript" src="/website_forum/static/src/js/website_forum.editor.js"/>
 -    </xpath>
 -</template>
 -
  <!-- Page Index -->
  <template id="header" name="Forum Index">
      <t t-call="website.layout">
          <t t-set="head">
 -            <script type="text/javascript" src="/web/static/lib/ckeditor/ckeditor.js"/>
 -            <script type="text/javascript">
 -                CKEDITOR.config.toolbar = [['Bold','Italic','Underline','Strike'],['NumberedList','BulletedList', 'Blockquote']
 -                ,['Outdent','Indent','Link','Unlink','Image'],] ;
 -            </script>
 +            <t t-call-assets="website_forum.assets_forum"/>
          </t>
 +        <div t-if="is_public_user and not no_introduction_message" class="alert alert-success alert-dismissable">
 +            <div class="container">
 +                <div t-field="forum.introduction_message"/>
 +                <a class='btn btn-primary' t-attf-href="/web?redirect=#{ request.httprequest.url }">Register</a>
 +                <button type="button" class="btn btn-link js_close_intro" data-dismiss="alert" aria-hidden="true">Hide Intro</button>
 +            </div>
 +        </div>
          <div class="container mt16 website_forum">
              <div class="navbar navbar-default">
                  <div class="navbar-header">
                  </div>
                  <div class="collapse navbar-collapse" id="oe-help-navbar-collapse">
                      <ul class="nav navbar-nav">
 -                        <li t-att-class="filters in ('all', 'unanswered','followed','question','tag') and 'active' or '' ">
 -                            <a t-attf-href="/forum/#{ slug(forum) }">Questions</a>
 +                        <li t-att-class="sorting == 'relevancy desc' and 'active' or '' ">
 +                            <a t-attf-href="/forum/#{ slug(forum) }?{{ keep_query( 'search', 'post_type', 'filters', sorting='relevancy desc') }}">Trending</a>
 +                        </li>
 +                        <li t-att-class="sorting == 'create_date desc' and 'active' or '' ">
 +                            <a t-attf-href="/forum/#{ slug(forum) }?{{ keep_query( 'search', 'post_type', 'filters', sorting='create_date desc') }}">Newest</a>
                          </li>
                          <li t-att-class="searches.get('users') and 'active' or '' ">
                              <a t-attf-href="/forum/#{ slug(forum) }/users">People</a>
                          </li>
                      </ul>
                      <form class="navbar-form navbar-right" role="search" t-attf-action="/forum/#{ slug(forum) }" method="get">
 -                        <div class="form-group">
 -                            <input type="search" class="form-control"
 -                                name="search" placeholder="Search a question..."
 -                                t-att-value="search or ''"/>
 -                            <button type="submit" class="btn btn-default">Search</button>
 +                        <div class="input-group">
 +                            <input type="search" class="form-control" name="search" t-att-value="search or ''"/>
 +                            <span class="input-group-btn">
 +                                <button type="submit" class="btn btn-default">Search</button>
 +                            </span>
                          </div>
                      </form>
                  </div>
                      <t t-raw="0"/>
                  </div>
                  <div class="col-sm-3" id="right-column">
-                     <div t-if="not header.get('ask_hide')" class="btn-group btn-block mb16">
 -                    <a t-if="not header.get('ask_hide')"
 -                       t-attf-class="btn btn-primary btn-lg btn-block mb16 #{user.karma &gt;= forum.karma_ask and '' or 'karma_required'}"
 -                       t-attf-href="/forum/#{slug(forum)}/ask"
 -                       t-attf-data-karma="#{forum.karma_ask}">Ask a Question</a>
++                    <div t-if="not header.get('ask_hide')" t-attf-class="btn-group btn-block mb16 #{user.karma &gt;= forum.karma_ask and '' or 'karma_required'}" t-attf-data-karma="#{forum.karma_ask}">
 +                        <a type="button" class="btn btn-primary btn-lg col-sm-10" t-attf-href="/forum/#{slug(forum)}/#{forum.default_allow}">
 +                            <t t-if="forum.default_allow == 'ask_question'">Ask a Question</t>
 +                            <t t-if="forum.default_allow == 'post_link'">Submit a Post</t>
 +                            <t t-if="forum.default_allow == 'post_discussion'">New Discussion</t>
 +                        </a>
 +                        <button type="button" class="btn btn-primary btn-lg col-sm-2 dropdown-toggle" data-toggle="dropdown">
 +                            <span class="caret"></span>
 +                            <span class="sr-only">Select Post</span>
 +                        </button>
 +                        <ul class="dropdown-menu" role="menu">
 +                            <li t-if="forum.allow_link"><a t-attf-href="/forum/#{slug(forum)}/post_link">Submit a Post</a></li>
 +                            <li t-if="forum.allow_question"><a t-attf-href="/forum/#{slug(forum)}/ask_question">Ask a Question</a></li>
 +                            <li t-if="forum.allow_discussion"><a t-attf-href="/forum/#{slug(forum)}/post_discussion">Launch a Discussion</a></li>
 +                        </ul>
 +                    </div>
                      <div class="panel panel-default">
                          <div class="panel-heading">
                              <h3 class="panel-title">Keep Informed</h3>
                      </div>
                      <div class="panel panel-default" id="about_forum">
                          <div class="panel-heading">
 -                            <h3 class="panel-title">About This Forum</h3>
 +                            <h3 class="panel-title">About This Community</h3>
                          </div>
                          <div class="panel-body">
                              <t t-raw="forum.description"/>
  <template id="display_post">
      <div class="question row">
          <div class="col-md-2 hidden-xs text-center">
 -            <div t-attf-class="box #{question.is_correct and 'oe_green' or 'oe_grey'} #{(question.child_count == 0) and 'text-muted' or ''}">
 -                <span t-esc="question.child_count"/>
 -                <div t-if="question.child_count&gt;1" class="subtitle">Answers</div>
 -                <div t-if="question.child_count&lt;=1" class="subtitle">Answer</div>
 -            </div>
 +            <t t-call="website_forum.vote">
 +                <t t-set="post" t-value="question"/>
 +            </t>
          </div>
          <div class="col-md-10 clearfix">
              <div class="question-name">
 -                <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
 -                    <span t-if="not question.active"><b> [Deleted]</b></span>
 -                    <span t-if="question.state == 'close'"><b> [Closed]</b></span>
 +                <t t-if="question.type == 'link'">
 +                    <a t-att-href="question.content_link" t-raw="question.name"/>
 +                </t>
 +                <t t-if="question.type in ('question', 'discussion')">
 +                    <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
 +                </t>
 +                <span t-if="not question.active"><b> [Deleted]</b></span>
 +                <span t-if="question.state == 'close'"><b> [Closed]</b></span>
              </div>
              <t t-foreach="question.tag_ids" t-as="question_tag">
                  <a t-attf-href="/forum/#{ slug(forum) }/tag/#{slug(question_tag)}/questions">
 -                    <span t-attf-class="pull-right badge #{tag and tag.name == question_tag.name and 'badge-active' ''}" t-field="question_tag.name"
 +                    <span t-attf-class="pull-right label #{tag and tag.name == question_tag.name and 'label-primary' or 'label-default'}" t-field="question_tag.name"
                          style="margin-right: 4px;"/>
                  </a>
              </t>
 -            <div class="text-muted">
 -                by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.create_uid.id }"
 -                    t-field="question.create_uid" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
 -                    style="display: inline-block;"/>
 -                on <span t-field="question.write_date" t-field-options='{"format":"short"}'/>
 -                <span class="visible-xs">
 -                    <b t-esc="question.child_count or 0"/>
 -                    <t t-if="question.child_count&gt;1">answers</t>
 -                    <t t-if="question.child_count==1">answers</t>
 -                </span>
 -                with <b t-field="question.views"/> views
 -                <span t-if="question.vote_count&gt;0"> and
 -                    <b t-esc="question.vote_count or 0"/>
 -                    <t t-if="question.vote_count&gt;1">votes</t>
 -                    <t t-if="question.vote_count==1">vote</t>
 -                </span>
 -            </div>
 +            <small class="text-muted">
 +                By <span t-field="question.create_uid" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}' style="display: inline-block;"/>
 +                â€¢ <span t-field="question.write_date" t-field-options='{"format":"short"}'/>
 +                â€¢ <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">
 +                    <t t-esc="question.child_count"/>
 +                    <t t-if="question.child_count&gt;1">comments</t>
 +                    <t t-if="question.child_count&lt;=1">comment</t>
 +                </a>
 +            </small>
          </div>
      </div>
  </template>
  <!-- Specific Forum Layout -->
  <template id="forum_index" name="Forum">
      <t t-call="website_forum.header">
 -        <h1 class="page-header mt0">
 -            <t t-esc="question_count"/> <span>Questions</span>
 +        <h2 class="page-header mt0">
 +            <t t-esc="question_count"/>
 +                <span t-if="post_type == 'all'">Posts</span>
 +                <span t-if="post_type == 'question'">Questions</span>
 +                <span t-if="post_type == 'link'">Posts</span>
 +                <span t-if="post_type == 'discussion'">Discussions</span>
              <t t-esc="search"/>
              <small class="dropdown" t-if="filters in ('all', 'unanswered','followed', 'tag')">
                <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                    <t t-if="filters == 'unanswered'">Unanswered</t>
                    <t t-if="filters == 'followed'">Followed</t>
                    <t t-if="tag"><span t-field="tag.name"/></t>
 -                  <t t-if="sorting == 'date'"> by activity date</t>
 -                  <t t-if="sorting == 'creation'"> by creation date</t>
 -                  <t t-if="sorting == 'answered'"> by most answered</t>
 -                  <t t-if="sorting == 'vote'"> by most voted</t>
 +                  <t t-if="sorting == 'relevancy desc'"> by relevancy</t>
 +                  <t t-if="sorting == 'write_date desc'"> by activity date</t>
 +                  <t t-if="sorting == 'create_date desc'"> by newest</t>
 +                  <t t-if="sorting == 'child_count desc'"> by most answered</t>
 +                  <t t-if="sorting == 'vote_count desc'"> by most voted</t>
                    <b class="caret"/>
                </a>
                <ul class="dropdown-menu">
                        <a href=""><t t-esc="tag.name"/></a>
                    </li>
                    <li class="dropdown-header">Sort by</li>
 -                  <li t-att-class="sorting == 'date' and 'active' or '' ">
 -                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='date')">Last activity date</a>
 +                  <li t-att-class="sorting == 'relevancy desc' and 'active' or '' ">
 +                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='relevancy desc')">Relevancy</a>
                    </li>
 -                  <li t-att-class="sorting == 'creation' and 'active' or '' ">
 -                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='creation')">Newest</a>
 +                  <li t-att-class="sorting == 'write_date desc' and 'active' or '' ">
 +                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='write_date desc')">Last activity date</a>
                    </li>
 -                  <li t-att-class="sorting == 'answered' and 'active' or '' ">
 -                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='answered')">Most answered</a>
 +                  <li t-att-class="sorting == 'create_date desc' and 'active' or '' ">
 +                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='create_date desc')">Newest</a>
                    </li>
 -                  <li t-att-class="sorting == 'vote' and 'active' or '' ">
 -                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='vote')">Most voted</a>
 +                  <li t-att-class="sorting == 'child_count desc' and 'active' or '' ">
 +                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='child_count desc')">Most answered</a>
 +                  </li>
 +                  <li t-att-class="sorting == 'vote_count desc' and 'active' or '' ">
 +                      <a t-att-href="url_for('') + '?' + keep_query( 'search', 'filters', sorting='vote_count desc')">Most voted</a>
                    </li>
                </ul>
              </small>
 -        </h1>
 +        </h2>
          <div t-foreach="question_ids" t-as="question" class="mb16">
              <t t-call="website_forum.display_post"/>
          </div>
      </t>
  </template>
  
 +<!-- Edition: Post Article -->
 +<template id="post_link">
 +    <t t-call="website_forum.header">
 +        <h1 class="mt0">Submit a Link</h1>
 +        <p class="mb32">
 +            Share an awesome link. Your post will appear in the 'Newest' top-menu.
 +            If the community vote on your post, it will get traction by being promoted
 +            in the homepage.
 +        </p><p>
 +            We keep a high level of quality in showcased posts, only 20% of the submited
 +            posts will be featured.
 +        </p>
 +        <form t-attf-action="/forum/#{ slug(forum) }/link/new" method="post" role="form" class="tag_text form-horizontal">
 +            <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
 +            <div class="form-group">
 +                <label class="col-sm-2 control-label" for="content_link">URL to Share</label>
 +                <div class="col-sm-8">
 +                    <input type="text" name="post_name" required="True" t-attf-value="#{post_name}"
 +                        class="form-control mb16 link_url" placeholder="e.g. https://www.odoo.com"/>
 +                </div>
 +            </div>
 +            <div class="form-group">
 +                <label class="col-sm-2 control-label" for="post_name">Post Title</label>
 +                <div class="col-sm-8">
 +                    <input type="text" name="content" readonly="True" required="True" t-attf-value="#{content}"
 +                        class="form-control"/>
 +                </div>
 +            </div>
 +            <div class="form-group">
 +                <label class="col-sm-2 control-label" for="post_tags">Tags</label>
 +                <div class="col-sm-8">
 +                    <input type="text" name="post_tags" readonly="True" class="form-control load_tags"/>
 +                </div>
 +            </div>
 +            <div class="form-group">
 +                <div class="col-sm-offset-2 col-sm-8">
 +                    <button class="btn btn-primary" disabled="True" id="btn_post_your_article">Post Your Article</button>
 +                </div>
 +            </div>
 +        </form>
 +    </t>
 +</template>
 +
 +<!-- Edition: Post your Discussion Topic -->
 +<template id="post_discussion">
 +    <t t-call="website_forum.header">
 +        <h1 class="mt0">Post Your Discussion Topic</h1>
 +        <p>
 +            <b>Share</b> Start Something Awesome
 +        </p>
 +        <form t-attf-action="/forum/#{ slug(forum) }/discussion/new" method="post" role="form" class="tag_text">
 +            <input type="text" name="post_name" required="True" t-attf-value="#{post_name}"
 +                class="form-control mb16" placeholder="Your Discussion Title..."/>
 +            <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
 +            <textarea name="content" id="content" required="True" class="form-control load_editor">
 +                <t t-esc="question_content"/>
 +            </textarea>
 +            <br/>
 +            <input type="text" name="post_tags" placeholder="Tags" class="form-control load_tags"/>
 +            <br/>
 +            <button class="btn btn-primary" id="btn_ask_your_question">Post Your Topic</button>
 +        </form>
 +    </t>
 +</template>
 +
  <!-- Edition: ask your question -->
  <template id="ask_question">
      <t t-call="website_forum.header">
 -        <h1 class="mt0">Ask your Question</h1>
 +        <h1 class="mt0">Ask Your Question</h1>
 +        <p>
 +            To improve your chance getting an answer:
 +        </p>
          <ul>
 -            <li> please, try to make your question interesting to others </li>
 -            <li> provide enough details and, if possible, give an example </li>
 -            <li> be clear and concise, avoid unnecessary introductions (Hi, ... Thanks...) </li>
 +            <li>Set a clear, explicit and concise question title
 +                (check
 +                <a href="#" data-placement="top" data-toggle="popover" data-content="Inventory Date Problem, Task remaining hours, Can you help solve solve my tax computation problem in Canada?" title="Click to get bad question samples">bad examples</a>
 +                and
 +                <a href="#" data-placement="bottom" data-toggle="popover" data-content="How to create a physical inventory at an anterior date?, How is the 'remaining hours' field computed on tasks?, How to configure TPS and TVQ's canadian taxes?" title="Click to get good question titles">good examples</a>
 +                ),
 +            </li>
 +            <li>Avoid unnecessary introductions (Hi,... Please... Thanks...),</li>
 +            <li>Provide enough details and, if possible, give an example.</li>
          </ul>
 +        <script type="text/javascript">
 +            $(function () {
 +                $("[data-toggle='popover']").popover();
 +            });
 +        </script>
          <form t-attf-action="/forum/#{ slug(forum) }/question/new" method="post" role="form" class="tag_text">
 -            <input type="text" name="question_name" required="True" t-attf-value="#{question_name}"
 -                class="form-control" placeholder="Enter your Question"/>
 -            <h5 class="mt20">Please enter a descriptive question (should finish with a '?')</h5>
 +            <input type="text" name="post_name" required="True" t-attf-value="#{post_name}"
 +                class="form-control mb16" placeholder="Your Question Title..."/>
              <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
 -            <textarea name="content" required="True" class="form-control load_editor">
 +            <textarea name="content" required="True" id="content" class="form-control load_editor">
                  <t t-esc="question_content"/>
              </textarea>
              <br/>
 -            <input type="text" name="question_tags" placeholder="Tags" class="form-control load_tags"/>
 +            <input type="text" name="post_tags" placeholder="Tags" class="form-control load_tags"/>
              <br/>
-             <button class="btn btn-primary" id="btn_ask_your_question">Post Your Question</button>
+             <button t-attf-class="btn btn-primary #{(user.karma &lt;= forum.karma_ask) and 'karma_required' or ''}"
+                 id="btn_ask_your_question" t-att-data-karma="forum.karma_ask">Post Your Question</button>
          </form>
 -        <script type="text/javascript">
 -            CKEDITOR.replace("content");
 -        </script>
      </t>
  </template>
  
  <!-- Edition: edit a post -->
  <template id="edit_post">
      <t t-call="website_forum.header">
 -        <h3 t-if="not is_answer">Edit question</h3>
 -        <h3 t-if="is_answer">Edit answer</h3>
 +        <h3 t-if="not is_answer">Edit <span t-field="post.type"/></h3>
 +        <h3 t-if="is_answer">Edit reply</h3>
          <form t-attf-action="/forum/#{slug(forum)}/post/#{slug(post)}/save" method="post" role="form" class="tag_text">
              <div t-if="not is_answer">
 -                <input type="text" name="question_name" id="question_name" required="True"
 -                    t-attf-value="#{post.name}" class="form-control" placeholder="Edit your Question"/>
 -                <h5 class="mt20">Please enter a descriptive question (should finish by a '?')</h5>
 +                <input type="text" name="post_name" required="True"
 +                    t-attf-value="#{post.name}" class="form-control mb8" placeholder="Edit your Post"/>
 +                <h5 t-if="post.type == 'question'" class="mt20">Please enter a descriptive question (should finish by a '?')</h5>
              </div>
              <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
 -            <textarea name="content" required="True" class="form-control load_editor">
 +            <textarea name="content" id="content" required="True" class="form-control load_editor">
                  <t t-esc="post.content"/>
              </textarea>
              <div t-if="not is_answer">
                  <br/>
 -                <input type="text" name="question_tag" class="form-control col-md-9 load_tags" placeholder="Tags" t-attf-value="#{tags}"/>
 +                <input type="text" name="post_tag" class="form-control col-md-9 load_tags" placeholder="Tags" t-attf-value="#{tags}"/>
                  <br/>
              </div>
              <button class="btn btn-primary btn-lg">Save</button>
          </form>
      </t>
  </template>
  
 -<!-- Moderation: close a question -->
 -<template id="close_question">
 +<!-- Moderation: close a post -->
 +<template id="close_post">
      <t t-call="website_forum.header">
 -        <h1 class="mt0">Close question</h1>
 +        <h1 class="mt0">Close Post</h1>
          <p class="text-muted">
 -            If you close this question, it will be hidden for most users. Only
 -            users having a high karma can see closed questions to moderate
 +            If you close this post, it will be hidden for most users. Only
 +            users having a high karma can see closed posts to moderate
              them.
          </p>
          <form t-attf-action="/forum/#{ slug(forum) }/question/#{slug(question)}/close" method="post" role="form" class="form-horizontal mt32 mb64">
              <input name="post_id" t-att-value="question.id" type="hidden"/>
              <div class="form-group">
 -                <label class="col-md-3 control-label" for="reason">Question:</label>
 +                <label class="col-md-3 control-label" for="reason">Post:</label>
                  <div class="col-md-8 mt8">
                      <span t-field="question.name"/>
                  </div>
              </div>
              <div class="form-group">
                  <div class="col-md-offset-3 col-md-8">
 -                    <button class="btn btn-primary">Close question</button>
 +                    <button class="btn btn-primary">Close post</button>
                      <span class="text-muted">or</span>
 -                    <a class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">back to question</a>
 +                    <a class="btn btn-link" t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }">back to post</a>
                  </div>
              </div>
          </form>
      </t>
  </template>
  
 +<!-- Edition: post a reply -->
 +<template id="post_reply">
 +    <div class="css_editable_mode_hidden">
 +        <form t-attf-id="reply#{ object._name.replace('.','') + '-' + str(object.id) }" class="collapse oe_comment_grey"
 +            t-attf-action="/forum/#{ slug(forum) }/#{slug(object)}/reply" method="post" role="form">
 +            <h3 class="mt10">Your Reply</h3>
 +            <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
 +            <textarea name="content" t-attf-id="content-#{str(object.id)}" class="form-control load_editor" required="True"/>
 +            <button class="btn btn-primary" id="btn_ask_your_question">Post Your Reply</button>
 +        </form>
 +    </div>
 +</template>
 +
  <!-- Edition: post an answer -->
  <template id="post_answer">
 -    <h3 class="mt10">Your answer</h3>
 -    <p>
 +    <h3 class="mt10">Your Reply</h3>
 +    <p t-if="question.type == 'question'">
          <b>Please try to give a substantial answer.</b> If you wanted to comment on the question or answer, just
          <b>use the commenting tool.</b> Please remember that you can always <b>revise your answers</b>
          - no need to answer the same question twice. Also, please <b>don't forget to vote</b>
          - it really helps to select the best questions and answers!
      </p>
 -    <form t-attf-action="/forum/#{ slug(forum) }/post/#{slug(question)}/new" method="post" role="form">
 +    <form t-attf-action="/forum/#{ slug(forum) }/#{slug(question)}/reply" method="post" role="form">
          <input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
 -        <textarea name="content" class="form-control load_editor" required="True"/>
 +        <textarea name="content" t-attf-id="content-#{str(question.id)}" class="form-control load_editor" required="True"/>
-         <button class="btn btn-primary mt16" id="btn_ask_your_question">Post Your Reply</button>
+         <button t-attf-class="btn btn-primary mt16 #{not question.can_answer and 'karma_required' or ''}"
 -                id="btn_ask_your_question" t-att-data-karma="question.karma_answer">Post Your Answer</button>
++                id="btn_ask_your_question" t-att-data-karma="question.karma_answer">Post Your Reply</button>
      </form>
 -    <script type="text/javascript">
 -        CKEDITOR.replace("content");
 -    </script>
  </template>
  
  <template id="vote">
  <!-- Specific Post Layout -->
  <template id="post_description_full" name="Question Navigation">
      <t t-call="website_forum.header">
 -        <div t-attf-class="row question #{not question.active and 'alert alert-danger' or ''}">
 +        <div t-attf-class="row question">
              <div class="col-md-2 hidden-xs text-center">
                  <t t-call="website_forum.vote">
                      <t t-set="post" t-value="question"/>
                          t-attf-class="favourite_question no-decoration fa fa-2x fa-star #{question.user_favourite and 'forum_favourite_question' or ''}"/>
                  </div>
              </div>
 -            <div class="col-md-10">
 +            <div t-attf-class="col-md-10 #{not question.active and 'alert alert-danger' or ''}">
                  <h1 class="mt0">
 -                    <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
 +                    <t t-if="question.type == 'link'">
 +                        <a t-att-href="question.content_link" t-raw="question.name"/>
 +                    </t>
 +                    <t t-if="question.type in ('question', 'discussion')">
 +                        <a t-attf-href="/forum/#{ slug(forum) }/question/#{ slug(question) }" t-field="question.name"/>
 +                    </t>
                      <span t-if="not question.active"><b> [Deleted]</b></span>
                      <span t-if="question.state == 'close'"><b> [Closed]</b></span>
                  </h1>
                  <div class="alert alert-info text-center" t-if="question.state == 'close'">
                      <p class="mt16">
 -                        <b>The question has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
 +                        <b>The <i t-field="question.type"/> has been closed<t t-if="question.closed_reason_id"> for reason: <i t-esc="question.closed_reason_id.name"/></t></b>
                      </p>
                      <t t-if="question.closed_uid">
                          <b>by <a t-attf-href="/forum/#{ slug(forum) }/user/#{ question.closed_uid.id }"
                          </t>
                      </div>
                  </div>
 -                <t t-raw="question.content"/>
 +                <div t-if="question.type != 'link'"><t t-raw="question.content"/></div>
                  <div class="mt16 clearfix">
                      <div class="pull-right">
                          <div class="text-right">
                              <t t-foreach="question.tag_ids" t-as="tag">
 -                                <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="badge" t-field="tag.name"/>
 +                                <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ tag.id }/questions" class="label lebel-default" t-field="tag.name"/>
                              </t>
                          </div>
                          <ul class="list-inline" id="options">
 -                            <li>
 +                            <li t-if="question.type == 'question'">
-                                 <a style="cursor: pointer" data-toggle="collapse"
+                                 <a style="cursor: pointer" t-att-data-toggle="question.can_comment and 'collapse' or ''"
                                      t-attf-class="fa fa-comment-o #{not question.can_comment and 'karma_required text-muted' or ''}"
                                      t-attf-data-karma="#{not question.can_comment and question.karma_comment or 0}"
                                      t-attf-data-target="#comment#{ question._name.replace('.','') + '-' + str(question.id) }">
              </div>
          </div>
          <hr/>
 +        <div t-foreach="question.child_ids" t-as="post_answer" class="mt16 mb32">
 +            <t t-call="website_forum.post_answers">
 +                <t t-set="answer" t-value="post_answer"/>
 +            </t>
 +        </div>
 +        <div t-if="question.type != 'question' or question.type == 'question' and not question.uid_has_answered and question.state != 'close' and question.active != False">
 +            <t t-call="website_forum.post_answer"/>
 +        </div>
 +        <div t-if="question.type == 'question' and question.uid_has_answered" class="mb16">
 +            <a class="btn btn-primary" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">Edit Your Previous Answer</a>
 +            <span class="text-muted">(only one answer per question is allowed)</span>
 +        </div>
 +    </t>
 +</template>
  
 -        <div t-foreach="question.child_ids" t-as="answer" class="mt16 mb32">
 -            <a t-attf-id="answer-#{str(answer.id)}"/>
 -            <div t-attf-class="forum_answer row" t-attf-id="answer_#{answer.id}" >
 -                <div class="col-md-2 hidden-xs text-center">
 +<template id="post_answers">
 +    <a t-attf-id="answer-#{str(answer.id)}"/>
 +    <div t-attf-class="forum_answer row" t-attf-id="answer_#{answer.id}" >
 +        <div class="col-md-2 hidden-xs text-center">
 +            <t t-call="website_forum.vote">
 +                <t t-set="post" t-value="answer"/>
 +            </t>
 +            <div t-if="question.type == 'question'" class="text-muted mt8">
 +                <a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'} #{not answer.can_accept and 'karma_required' or ''}"
 +                    t-attf-data-karma="#{answer.karma_accept}"
 +                    t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
 +            </div>
 +        </div>
 +        <div class="col-md-10 clearfix">
 +            <t t-raw="answer.content"/>
 +            <div class="mt16">
 +                <ul class="list-inline pull-right">
 +                    <li t-if="question.type == 'question'">
 +                        <a t-attf-class="fa fa-comment-o #{not answer.can_comment and 'karma_required text-muted' or ''}"
 +                            t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
-                             style="cursor: pointer" data-toggle="collapse"
++                            style="cursor: pointer" t-att-data-toggle="answer.can_comment and 'collapse' or ''"
 +                            t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment
 +                        </a>
 +                    </li>
 +                    <li t-if="question.type != 'question' and not answer.parent_id or answer.parent_id and not answer.parent_id.parent_id">
 +                        <a t-attf-class="fa fa-comment-o #{not answer.can_comment and 'karma_required text-muted' or ''}"
 +                            t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
 +                            style="cursor: pointer" data-toggle="collapse"
 +                            t-attf-data-target="#reply#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Reply
 +                        </a>
 +                    </li>
 +                    <li>
 +                        <t t-call="website_forum.link_button">
 +                            <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
 +                            <t t-set="label" t-value="'Edit'"/>
 +                            <t t-set="classes" t-value="'fa fa-edit'"/>
 +                            <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
 +                        </t>
 +                    </li>
 +                    <li>
 +                        <t t-call="website_forum.link_button">
 +                            <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
 +                            <t t-set="label" t-value="'Delete'"/>
 +                            <t t-set="classes" t-value="'fa-trash-o'"/>
 +                            <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
 +                        </t>
 +                    </li>
 +                    <li t-if="question.type == 'question'">
 +                        <t t-call="website_forum.link_button">
 +                            <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
 +                            <t t-set="label" t-value="'Convert as a comment'"/>
 +                            <t t-set="classes" t-value="'fa-magic'"/>
 +                            <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
 +                        </t>
 +                    </li>
 +                </ul>
 +                <img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{answer.create_uid.id}/avatar"/>
 +                <div>
 +                    <a t-attf-href="/forum/#{ slug(forum) }/user/#{ answer.create_uid.id }"
 +                        t-field="answer.create_uid"
 +                        t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
 +                        style="display: inline-block;"/>
 +                    <div t-field="answer.create_uid" t-field-options='{"widget": "contact", "badges": true, "fields": ["karma"]}'/>
 +                    <span class="text-muted">Answered on <span t-field="answer.create_date" t-field-options='{"format":"short"}'/></span>
 +                </div>
 +                <div class="visible-xs text-center">
                      <t t-call="website_forum.vote">
                          <t t-set="post" t-value="answer"/>
                      </t>
                              t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
                      </div>
                  </div>
 -                <div class="col-md-10 clearfix">
 -                    <t t-raw="answer.content"/>
 -                    <div class="mt16">
 -                        <ul class="list-inline pull-right">
 -                            <li>
 -                                <a t-attf-class="fa fa-comment-o #{not answer.can_comment and 'karma_required text-muted' or ''}"
 -                                    t-attf-data-karma="#{not answer.can_comment and answer.karma_comment or 0}"
 -                                    style="cursor: pointer" t-att-data-toggle="answer.can_comment and 'collapse' or ''"
 -                                    t-attf-data-target="#comment#{ answer._name.replace('.','') + '-' + str(answer.id) }"> Comment
 -                                </a>
 -                            </li>
 -                            <li>
 -                                <t t-call="website_forum.link_button">
 -                                    <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/edit'"/>
 -                                    <t t-set="label" t-value="'Edit'"/>
 -                                    <t t-set="classes" t-value="'fa fa-edit'"/>
 -                                    <t t-set="karma" t-value="not answer.can_edit and answer.karma_edit or 0"/>
 -                                </t>
 -                            </li>
 -                            <li>
 -                                <t t-call="website_forum.link_button">
 -                                    <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/delete'"/>
 -                                    <t t-set="label" t-value="'Delete'"/>
 -                                    <t t-set="classes" t-value="'fa-trash-o'"/>
 -                                    <t t-set="karma" t-value="not answer.can_unlink and answer.karma_unlink or 0"/>
 -                                </t>
 -                            </li>
 -                            <li>
 -                                <t t-call="website_forum.link_button">
 -                                    <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(answer) + '/convert_to_comment'"/>
 -                                    <t t-set="label" t-value="'Convert as a comment'"/>
 -                                    <t t-set="classes" t-value="'fa-magic'"/>
 -                                    <t t-set="karma" t-value="not answer.can_comment_convert and answer.karma_comment_convert or 0"/>
 -                                </t>
 -                            </li>
 -                        </ul>
 -                        <img class="pull-left img img-circle img-avatar" t-attf-src="/forum/user/#{answer.create_uid.id}/avatar"/>
 -                        <div>
 -                            <a t-attf-href="/forum/#{ slug(forum) }/user/#{ answer.create_uid.id }"
 -                                t-field="answer.create_uid"
 -                                t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
 -                                style="display: inline-block;"/>
 -                            <div t-field="answer.create_uid" t-field-options='{"widget": "contact", "badges": true, "fields": ["karma"]}'/>
 -                            <span class="text-muted">Answered on <span t-field="answer.create_date" t-field-options='{"format":"short"}'/></span>
 -                        </div>
 -                        <div class="visible-xs text-center">
 -                            <t t-call="website_forum.vote">
 -                                <t t-set="post" t-value="answer"/>
 -                            </t>
 -                            <div class="text-muted mt8">
 -                                <a t-attf-class="accept_answer fa fa-2x fa-check-circle no-decoration #{answer.is_correct and 'oe_answer_true' or 'oe_answer_false'} #{not answer.can_accept and 'karma_required' or ''}"
 -                                    t-attf-data-karma="#{answer.karma_accept}"
 -                                    t-attf-data-href="/forum/#{slug(question.forum_id)}/post/#{slug(answer)}/toggle_correct"/>
 -                            </div>
 -                        </div>
 -                    </div>
 -                    <t t-call="website_forum.post_comment">
 -                        <t t-set="object" t-value="answer"/>
 -                    </t>
 -                </div>
 +            </div>
 +            <t t-if="answer.type == 'question'" t-call="website_forum.post_comment">
 +                <t t-set="object" t-value="answer"/>
 +            </t>
 +            <div t-if="answer.type != 'question' and question.state != 'close' and question.active != False">
 +                <t t-call="website_forum.post_reply">
 +                    <t t-set="object" t-value="answer"/>
 +                </t>
 +            </div>
 +            <div t-foreach="answer.child_ids" t-as="child_answer" class="mt16 mb16">
 +                <t t-call="website_forum.post_answers">
 +                    <t t-set="answer" t-value="child_answer"/>
 +                </t>
              </div>
          </div>
 -        <div t-if="not question.uid_has_answered">
 -            <t t-call="website_forum.post_answer"/>
 -        </div>
 -        <div t-if="question.uid_has_answered" class="mb16">
 -            <a class="btn btn-primary" t-attf-href="/forum/#{slug(forum)}/question/#{slug(question)}/edit_answer">Edit Your Previous Answer</a>
 -            <span class="text-muted">(only one answer per question is allowed)</span>
 -        </div>
 -    </t>
 +    </div>
  </template>
  
  <!-- Utility template: Post a Comment -->
  
                      <span t-field="message.body"/>
                      <t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_convert_own or object.forum_id.karma_comment_convert_all"/>
 -                    <t t-call="website_forum.link_button">
 -                        <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
 -                        <t t-set="label" t-value="'Convert as an answer'"/>
 -                        <t t-set="karma" t-value="user.karma&lt;required_karma and required_karma or 0"/>
 -                        <t t-set="classes" t-value="'fa-magic pull-right'"/>
 +                    <t t-if="(object.parent_id and object.parent_id.state != 'close' and object.parent_id.active != False) or (not object.parent_id and object.state != 'close' and object.active != False)">
 +                        <t t-set="allow_post_comment" t-value="True" />
 +                    </t>
 +                    <t t-if="allow_post_comment">
 +                        <t t-call="website_forum.link_button" >
 +                            <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
 +                            <t t-set="label" t-value="'Convert as an answer'"/>
 +                            <t t-set="karma" t-value="user.karma&lt;required_karma and required_karma or 0"/>
 +                            <t t-set="classes" t-value="'fa-magic pull-right'"/>
 +                        </t>
                      </t>
                      <a t-attf-href="/forum/#{slug(forum)}/partner/#{message.author_id.id}"
                          t-field="message.author_id" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
          </p>
          <div class="row">
              <div class="col-sm-3 mt16" t-foreach="tags" t-as="tag">
 -                <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ slug(tag) }/questions?{{ keep_query( filters='tag') }}" class="badge">
 +                <a t-attf-href="/forum/#{ slug(forum) }/tag/#{ slug(tag) }/questions?{{ keep_query( filters='tag') }}" class="label label-default">
                      <span t-field="tag.name"/>
                  </a>
                  <span>
              </field>
          </field>
      </record>
+     <record id="attribute_tree_view" model="ir.ui.view">
+         <field name="name">product.attribute.tree.type</field>
+         <field name="model">product.attribute</field>
+         <field name="inherit_id" ref="product.attribute_tree_view"></field>
+         <field name="arch" type="xml">
+             <field name="name" position="after">
+                 <field name="type"/>
+             </field>
+         </field>
+     </record>
  
      <!-- Product Public Categories -->
      <record id="product_public_category_form_view" model="ir.ui.view">
@@@ -87,7 -97,7 +97,7 @@@
          </field>
      </record>
      <record id="product_public_category_action" model="ir.actions.act_window">
 -        <field name="name">Public Product Categories</field>
 +        <field name="name">Public Categories</field>
          <field name="type">ir.actions.act_window</field>
          <field name="res_model">product.public.category</field>
          <field name="view_type">form</field>
            </p>
          </field>
      </record>
 -    <menuitem action="product_public_category_action" id="menu_product_public_category" parent="product.prod_config_main" sequence="10" />
 +    <menuitem action="product_public_category_action" id="menu_product_public_category" parent="product.prod_config_main" sequence="2" />
      <!-- END -->
  
   </data>
diff --combined doc/conf.py
@@@ -20,6 -20,7 +20,7 @@@ needs_sphinx = '1.1
  # Add any Sphinx extension module names here, as strings. They can be extensions
  # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
  extensions = [
+     'sphinx.ext.ifconfig',
      'sphinx.ext.todo',
      'sphinx.ext.autodoc',
      'sphinx.ext.intersphinx',
@@@ -52,9 -53,9 +53,9 @@@ copyright = u'2014, OpenERP s.a.
  # built documents.
  #
  # The short X.Y version.
 -version = '8.0'
 +version = 'master'
  # The full version, including alpha/beta/rc tags.
 -release = '8.0b1'
 +release = 'master'
  
  # There are two options for replacing |today|: either, you set today to some
  # non-false value, then it is used:
@@@ -165,6 -166,9 +166,9 @@@ html_sidebars = 
  # base URL from which the finished HTML is served.
  #html_use_opensearch = ''
  
+ # default must be set otherwise ifconfig blows up
+ todo_include_todos = False
  intersphinx_mapping = {
      'python': ('https://docs.python.org/2/', None),
      'werkzeug': ('http://werkzeug.pocoo.org/docs/', None),
@@@ -233,8 -233,9 +233,9 @@@ class res_partner(osv.Model, format_add
          'date': fields.date('Date', select=1),
          'title': fields.many2one('res.partner.title', 'Title'),
          'parent_id': fields.many2one('res.partner', 'Related Company', select=True),
+         'parent_name': fields.related('parent_id', 'name', type='char', readonly=True, string='Parent name'),
          'child_ids': fields.one2many('res.partner', 'parent_id', 'Contacts', domain=[('active','=',True)]), # force "active_test" domain to bypass _search() override
 -        'ref': fields.char('Contact Reference', select=1),
 +        'ref': fields.char('Internal Reference', select=1),
          'lang': fields.selection(_lang_get, 'Language',
              help="If the selected language is loaded in the system, all documents related to this contact will be printed in this language. If not, it will be English."),
          'tz': fields.selection(_tz_get,  'Timezone', size=64,
          'credit_limit': fields.float(string='Credit Limit'),
          'ean13': fields.char('EAN13', size=13),
          'active': fields.boolean('Active'),
 -        'customer': fields.boolean('Customer', help="Check this box if this contact is a customer."),
 -        'supplier': fields.boolean('Supplier', help="Check this box if this contact is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."),
 +        'customer': fields.boolean('Is a Customer', help="Check this box if this contact is a customer."),
 +        'supplier': fields.boolean('Is a Supplier', help="Check this box if this contact is a supplier. If it's not checked, purchase people will not see it when encoding a purchase order."),
          'employee': fields.boolean('Employee', help="Check this box if this contact is an Employee."),
          'function': fields.char('Job Position'),
          'type': fields.selection([('default', 'Default'), ('invoice', 'Invoice'),
          for record in self.browse(cr, uid, ids, context=context):
              name = record.name
              if record.parent_id and not record.is_company:
-                 name =  "%s, %s" % (record.parent_id.name, name)
+                 name = "%s, %s" % (record.parent_name, name)
              if context.get('show_address_only'):
                  name = self._display_address(cr, uid, record, without_company=True, context=context)
              if context.get('show_address'):
              'state_name': address.state_id.name or '',
              'country_code': address.country_id.code or '',
              'country_name': address.country_id.name or '',
-             'company_name': address.parent_id.name or '',
+             'company_name': address.parent_name or '',
          }
          for field in self._address_fields(cr, uid, context=context):
              args[field] = getattr(address, field) or ''