[MERGE]with lp:~openerp-dev/openobject-addons/trunk-website-al.

bzr revid: dka@tinyerp.com-20140115144940-srkv28a758ov0xx8
This commit is contained in:
Darshan Kalola (OpenERP) 2014-01-15 20:19:40 +05:30
commit 90248025a4
38 changed files with 2028 additions and 1161 deletions

View File

@ -35,10 +35,6 @@ to an appropriate local partner, based on the distance and the weight that was a
""",
'author': 'OpenERP SA',
'depends': ['base_geolocalize', 'crm', 'account', 'portal'],
'demo': [
# 'res_partner_demo.xml',
'crm_lead_demo.xml'
],
'data': [
'security/ir.model.access.csv',
'res_partner_view.xml',
@ -50,7 +46,10 @@ to an appropriate local partner, based on the distance and the weight that was a
'portal_data.xml',
'report/crm_lead_report_view.xml',
'report/crm_partner_report_view.xml',
],
'demo': [
'res_partner_demo.xml',
'crm_lead_demo.xml'
],
'js': [
'static/src/js/next.js',

View File

@ -176,7 +176,7 @@ class email_template(osv.osv):
'mail_server_id': fields.many2one('ir.mail_server', 'Outgoing Mail Server', readonly=False,
help="Optional preferred server for outgoing mails. If not set, the highest "
"priority one will be used."),
'body_html': fields.text('Body', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
'body_html': fields.html('Body', translate=True, help="Rich-text/HTML version of the message (placeholders may be used here)"),
'report_name': fields.char('Report Filename', translate=True,
help="Name to use for the generated report file (may contain placeholders)\n"
"The extension can be omitted and will then come from the report type."),

View File

@ -78,6 +78,9 @@ Example: 10% for retailers, promotion of 5 EUR on this product, etc."""),
'module_sale_stock': fields.boolean("Trigger delivery orders automatically from sales orders",
help='Allows you to Make Quotation, Sale Order using different Order policy and Manage Related Stock.\n'
'-This installs the module sale_stock.'),
'group_sale_delivery_address': fields.boolean("Allow a different address for delivery and invoicing ",
implied_group='sale.group_delivery_invoice_address',
help="Allows you to specify different delivery and invoice addresses on a sales order."),
}
def default_get(self, cr, uid, fields, context=None):

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_sales_config" model="ir.ui.view">
<field name="name">sale settings</field>
<field name="model">sale.config.settings</field>
@ -41,6 +40,10 @@
<field name="module_warning" class="oe_inline"/>
<label for="module_warning"/>
</div>
<div>
<field name="group_sale_delivery_address" class="oe_inline"/>
<label for="group_sale_delivery_address"/>
</div>
</div>
<group name="Sale" position="before">
<group>
@ -58,7 +61,7 @@
</group>
</group>
<group name="Sale" position="before">
<group>
<group name="Product Features">
<label for="id" string="Product Features"/>
<div>
<div>

View File

@ -28,9 +28,6 @@ class sale_configuration(osv.osv_memory):
_inherit = 'sale.config.settings'
_columns = {
'group_sale_delivery_address': fields.boolean("Allow a different address for delivery and invoicing ",
implied_group='sale.group_delivery_invoice_address',
help="Allows you to specify different delivery and invoice addresses on a sales order."),
'group_invoice_deli_orders': fields.boolean('Generate invoices after and based on delivery orders',
implied_group='sale_stock.group_invoice_deli_orders',
help="To allow your salesman to make invoices for Delivery Orders using the menu 'Deliveries to Invoice'."),

View File

@ -8,12 +8,6 @@
<field name="inherit_id" ref="sale.view_sales_config"/>
<field name="arch" type="xml">
<data>
<xpath expr="//div[@name='Customer Features']" position="inside">
<div>
<field name="group_sale_delivery_address" class="oe_inline"/>
<label for="group_sale_delivery_address"/>
</div>
</xpath>
<xpath expr="//div[@name='group_invoice_so_lines']" position="replace">
<div>
<field name="group_invoice_so_lines" on_change="onchange_invoice_methods(group_invoice_so_lines, group_invoice_deli_orders)" class="oe_inline"/>

View File

@ -135,11 +135,16 @@ class Website(openerp.addons.web.controllers.main.Home):
view_model, view_theme_id = imd.get_object_reference(
request.cr, request.uid, 'website', 'theme')
user = request.registry['res.users'].browse(request.cr, request.uid, request.uid, request.context)
group_ids = [g.id for g in user.groups_id]
view = request.registry.get("ir.ui.view")
views = view._views_get(request.cr, request.uid, xml_id, request.context)
done = {}
result = []
for v in views:
if v.groups_id and [g for g in v.groups_id if g.id not in group_ids]:
continue
if v.inherit_option_id and v.inherit_option_id.id != view_theme_id or not optional:
if v.inherit_option_id.id not in done:
result.append({

View File

@ -1,3 +1,4 @@
sass:
sass -t expanded --compass --unix-newlines --watch website.sass:website.css&
sass -t expanded --compass --unix-newlines --watch editor.sass:editor.css&
sass -t expanded --compass --unix-newlines --watch snippets.sass:snippets.css&

View File

@ -93,20 +93,6 @@
display: none;
}
.oe_carousel_options {
cursor: pointer;
position: absolute;
white-space: nowrap;
z-index: 1;
display: none;
}
.oe_carousel_options > * {
display: inline-block !important;
vertical-align: middle !important;
position: relative !important;
top: 2px;
}
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
background-image: url("/website/static/src/img/edit_here.png") !important;
}
@ -248,387 +234,6 @@ ul.oe_menu_editor .disclose {
z-index: 1000;
}
/* ---- SNIPPET EDITOR ---- {{{ */
#oe_snippets {
position: fixed;
left: 0px;
right: 0px;
background: #282828;
-webkit-box-shadow: 0px 10px 10px -10px black inset;
-moz-box-shadow: 0px 10px 10px -10px black inset;
box-shadow: 0px 10px 10px -10px black inset;
z-index: 1010;
overflow: hidden;
}
#oe_snippets:hover {
height: auto;
}
#oe_snippets .scroll {
white-space: nowrap;
overflow-y: none;
}
#oe_snippets .nav {
display: inline-block;
border-bottom: none !important;
vertical-align: middle;
min-width: 120px;
z-index: 1;
}
#oe_snippets .nav > li {
display: block;
float: none;
}
#oe_snippets .nav > li.active {
background: black !important;
}
#oe_snippets .nav > li > a {
padding: 2px 10px !important;
width: 100%;
display: block;
border: 0;
}
#oe_snippets .pill-content {
border: 0;
}
#oe_snippets .tab-content {
display: inline-block;
white-space: nowrap;
background: black;
}
#oe_snippets .tab-content > div {
background: black;
}
#oe_snippets .tab-content > div label {
width: 44px;
color: white;
padding-left: 10px;
}
#oe_snippets .tab-content > div label div {
width: 100px;
text-align: center;
-webkit-transform: translate(-39px, 44px);
-moz-transform: translate(-39px, 44px);
-ms-transform: translate(-39px, 44px);
-o-transform: translate(-39px, 44px);
transform: translate(-39px, 44px);
-webkit-transform-origin: 50% 50% 50%;
-moz-transform-origin: 50% 50% 50%;
-ms-transform-origin: 50% 50% 50%;
-o-transform-origin: 50% 50% 50%;
transform-origin: 50% 50% 50%;
}
.oe_snippet {
float: left;
vertical-align: top;
width: 93px;
margin-left: 1px;
margin-top: 0px;
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
cursor: move;
pointer-events: none;
}
.oe_snippet .oe_snippet_thumbnail {
pointer-events: auto;
text-align: center;
height: 100%;
background: transparent;
color: white;
position: relative;
}
.oe_snippet .oe_snippet_thumbnail:hover .oe_snippet_thumbnail_img {
-webkit-transform: scale(0.95, 0.95);
-moz-transform: scale(0.95, 0.95);
-ms-transform: scale(0.95, 0.95);
-o-transform: scale(0.95, 0.95);
transform: scale(0.95, 0.95);
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title {
font-size: 12px;
display: block;
text-shadow: 0 0 2px black;
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img {
height: 74px;
-webkit-transition: all 150ms linear;
-moz-transition: all 150ms linear;
-o-transition: all 150ms linear;
transition: all 150ms linear;
-webkit-box-shadow: inset 0px 0px 0px 3px #333333;
-moz-box-shadow: inset 0px 0px 0px 3px #333333;
box-shadow: inset 0px 0px 0px 3px #333333;
-webkit-transform: scale(1, 1);
-moz-transform: scale(1, 1);
-ms-transform: scale(1, 1);
-o-transform: scale(1, 1);
transform: scale(1, 1);
}
.oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div {
line-height: 18px;
}
.oe_snippet > :not(.oe_snippet_thumbnail) {
display: none !important;
}
#oe_snippets .oe_snippet_thumbnail {
background: #747474, -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, rgba(0, 0, 0, 0.25)), color-stop(100%, rgba(0, 0, 0, 0.4)));
background: #747474, -webkit-radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
background: #747474, -moz-radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
background: #747474, -o-radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
background: #747474, radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
}
/* ---- SNIPPETS DROP ZONES ---- {{{ */
.oe_drop_zone.oe_insert {
display: block;
height: 48px;
margin: 0px;
margin-top: -4px;
margin-bottom: -44px;
-webkit-transition: margin 250ms linear;
-moz-transition: margin 250ms linear;
-o-transition: margin 250ms linear;
transition: margin 250ms linear;
width: 100%;
position: absolute;
z-index: 1000;
}
.oe_drop_zone.oe_insert:not(.oe_vertical):before {
content: "";
display: block;
border-top: dashed 2px rgba(209, 178, 255, 0.72);
position: relative;
top: 0px;
}
.oe_drop_zone.oe_insert.oe_hover:before {
border-top: dashed 2px rgba(116, 255, 161, 0.72);
}
.oe_drop_zone.oe_insert.oe_vertical {
width: 48px;
float: left;
position: relative;
margin: 0px -24px !important;
}
.oe_drop_zone.oe_insert.oe_overlay {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
background: rgba(153, 0, 255, 0.5);
}
.oe_drop_zone, .oe_drop_zone_style {
border: none;
background: rgba(153, 0, 255, 0.3);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
-o-border-radius: 4px;
border-radius: 4px;
}
.oe_drop_zone.oe_hover, .oe_drop_zone_style.oe_hover {
background: rgba(0, 255, 133, 0.3);
z-index: 1001;
}
.oe_drop_zone_style {
color: white;
height: 48px;
margin-bottom: 32px;
padding-top: 12px;
}
/* ---- SNIPPET MANIPULATOR ---- {{{ */
.resize_editor_busy {
background-color: rgba(0, 0, 0, 0.3);
}
.oe_overlay {
display: none;
position: absolute;
background: transparent;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
-webkit-transition: opacity 100ms linear;
-moz-transition: opacity 100ms linear;
-o-transition: opacity 100ms linear;
transition: opacity 100ms linear;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
pointer-events: none;
}
.oe_overlay.oe_active {
display: block;
border-style: dashed;
border-width: 1px;
-webkit-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
-moz-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
border-color: rgba(0, 0, 0, 0.5);
}
.oe_overlay .oe_handle {
display: block !important;
pointer-events: auto;
position: absolute;
top: 50%;
left: 50%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 12px;
height: 12px;
margin: -2px;
}
.oe_overlay .oe_handle:before {
position: relative;
top: 50%;
left: 50%;
display: block;
background: white;
border: solid 1px rgba(0, 0, 0, 0.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
width: 18px;
height: 18px;
margin: -9px;
padding-left: 1px;
font-size: 14px;
line-height: 14px;
font-family: FontAwesome;
color: rgba(0, 0, 0, 0.5);
-webkit-transition: background 100ms linear;
-moz-transition: background 100ms linear;
-o-transition: background 100ms linear;
transition: background 100ms linear;
}
.oe_overlay .oe_handle:hover:before {
background: rgba(0, 0, 0, 0.5);
color: white;
-webkit-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
-moz-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
}
.oe_overlay .oe_handle.e {
left: auto;
top: 2px;
height: 100%;
right: -4px;
cursor: w-resize;
}
.oe_overlay .oe_handle.e:before {
content: "\F061";
}
.oe_overlay .oe_handle.s, .oe_overlay .oe_handle.size {
top: auto;
left: 2px;
width: 100%;
bottom: -4px;
cursor: n-resize;
}
.oe_overlay .oe_handle.s:before, .oe_overlay .oe_handle.size:before {
content: "\F063";
}
.oe_overlay .oe_handle.size {
border-style: dashed;
border-width: 0 0 1px 0;
border-color: rgba(0, 0, 0, 0.5);
}
.oe_overlay .oe_handle.size:before {
content: "Resize";
width: 64px;
text-align: center;
margin-left: -32px;
margin-top: -4px;
}
.oe_overlay .oe_handle.w {
top: 2px;
height: 100%;
left: -4px;
cursor: e-resize;
}
.oe_overlay .oe_handle.w:before {
content: "\F060";
}
.oe_overlay .oe_handle.n {
left: 2px;
width: 100%;
top: -4px;
cursor: s-resize;
}
.oe_overlay .oe_handle.n:before {
content: "\F062";
}
.oe_overlay .icon.btn {
display: inline-block;
}
.oe_overlay .oe_overlay_options {
position: absolute;
width: 100%;
text-align: center;
top: -11px;
z-index: 1002;
}
.oe_overlay .oe_overlay_options .btn, .oe_overlay .oe_overlay_options a {
pointer-events: auto;
cursor: pointer;
}
.oe_overlay .oe_overlay_options .dropdown {
display: inline-block;
}
.oe_overlay .oe_overlay_options .dropdown-menu {
text-align: left;
min-width: 180px;
}
.oe_overlay .oe_overlay_options .dropdown-menu select, .oe_overlay .oe_overlay_options .dropdown-menu input {
display: block;
}
.oe_handle {
pointer-events: auto;
position: absolute;
top: 50%;
left: 50%;
display: block;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 8px;
height: 8px;
margin: -4px;
}
.s-resize-important, .s-resize-important * {
cursor: s-resize !important;
}
.n-resize-important, .n-resize-important * {
cursor: n-resize !important;
}
.e-resize-important, .e-resize-important * {
cursor: e-resize !important;
}
.w-resize-important, .w-resize-important * {
cursor: w-resize !important;
}
.move-important, .move-important * {
cursor: move !important;
}
/* ---- MOBILE PREVIEW ---- {{{ */
.oe_mobile_preview.modal .modal-content {
height: 660px;

View File

@ -76,18 +76,6 @@
.cke_editable .css_editable_mode_hidden
display: none
.oe_carousel_options
cursor: pointer
position: absolute
white-space: nowrap
z-index: 1
display: none
> *
display: inline-block !important
vertical-align: middle !important
position: relative !important
top: +2px
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
background-image: url('/website/static/src/img/edit_here.png') !important
@ -216,281 +204,6 @@ ul.oe_menu_editor
// }}}
/* ---- SNIPPET EDITOR ---- {{{ */
#oe_snippets
position: fixed
left: 0px
right: 0px
// top property is set programmatically
background: rgb(40,40,40)
+box-shadow(0px 10px 10px -10px black inset)
z-index: 1010
overflow: hidden
&:hover
height: auto
.scroll
white-space: nowrap
overflow-y: none
.nav
display: inline-block
border-bottom: none !important
vertical-align: middle
min-width: 120px
> li
display: block
float: none
&.active
background: black !important
> a
padding: 2px 10px !important
width: 100%
display: block
border: 0
z-index: 1
.pill-content
border: 0
.tab-content
display: inline-block
white-space: nowrap
background: black
> div
background: rgb(0,0,0)
label
width: 44px
color: #fff
padding-left: 10px
div
width: 100px
text-align: center
@include transform( translate(-39px, 44px) , rotate(-90deg) )
@include transform-origin(50% 50%)
.oe_snippet
float: left
vertical-align: top
width: 93px
margin-left: 1px
margin-top: 0px
position: relative
overflow: hidden
+user-select(none)
cursor: move
pointer-events: none
.oe_snippet_thumbnail
pointer-events: auto
text-align: center
height: 100%
background: transparent
color: white
position: relative
&:hover
.oe_snippet_thumbnail_img
@include transform( scale(.95,.95))
.oe_snippet_thumbnail_title
font-size: 12px
display: block
+text-shadow(0 0 2px rgb(0,0,0))
.oe_snippet_thumbnail_img
height: 74px
@include transition(all 150ms linear)
+box-shadow(inset 0px 0px 0px 3px #333333)
@include transform( scale(1,1))
span, div
line-height: 18px
& > :not(.oe_snippet_thumbnail)
display: none !important
#oe_snippets .oe_snippet_thumbnail
@include background(#747474, radial-gradient(rgba(0,0,0,0.25),rgba(0,0,0,0.4)))
// }}}}
/* ---- SNIPPETS DROP ZONES ---- {{{ */
.oe_drop_zone.oe_insert
display: block
height: 48px
margin: 0px
margin-top: -4px
margin-bottom: -44px
@include transition(margin 250ms linear)
width: 100%
position: absolute
z-index: 1000
&:not(.oe_vertical):before
content: ""
display: block
border-top: dashed 2px rgba(209, 178, 255, 0.72)
position: relative
top: 0px
&.oe_hover:before
border-top: dashed 2px rgba(116, 255, 161, 0.72)
&.oe_vertical
width: 48px
float: left
position: relative
margin: 0px -24px !important
&.oe_overlay
+border-radius(3px)
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
//background-size: 100px 100px
background: rgba(153, 0, 255,.5)
.oe_drop_zone, .oe_drop_zone_style
border: none
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
//background-size: 100px 100px
background: rgba(153, 0, 255, .3)
+border-radius(4px)
&.oe_hover
background: rgba(0, 255, 133, .3)
z-index: 1001
.oe_drop_zone_style
color: white
height: 48px
margin-bottom: 32px
padding-top: 12px
// }}}
/* ---- SNIPPET MANIPULATOR ---- {{{ */
.resize_editor_busy
background-color: rgba(0,0,0,0.3)
.oe_overlay
display: none
position: absolute
background: transparent
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.02) ,rgba(255,255,255,.02) 35px, rgba(0,0,0,.02) 35px, rgba(0,0,0,.02) 75px))
+border-radius(3px)
@include transition(opacity 100ms linear)
+box-sizing(border-box)
pointer-events: none
&.oe_active
display: block
border-style: dashed
border-width: 1px
+box-shadow(0px 0px 0px 1px rgba(255,255,255,0.3), 0px 0px 0px 1px rgba(255,255,255,0.3) inset)
border-color: rgba(0, 0, 0, 0.5)
.oe_handle
display: block !important
pointer-events: auto
position: absolute
top: 50%
left: 50%
+box-sizing(border-box)
width: 12px
height: 12px
margin: -2px
&:before
position: relative
top: 50%
left: 50%
display: block
background: rgba(255, 255, 255, 1)
border: solid 1px rgba(0, 0, 0, .2)
+border-radius(5px)
width: 18px
height: 18px
margin: -9px
padding-left: 1px
font-size: 14px
line-height: 14px
font-family: FontAwesome
color: rgba(0,0,0,.5)
@include transition(background 100ms linear)
&:hover:before
background: rgba(0, 0, 0, .5)
color: #fff
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
.oe_handle.e
left: auto
top: 2px
height: 100%
right: -4px
cursor: w-resize
&:before
content: "\F061"
.oe_handle.s, .oe_handle.size
top: auto
left: 2px
width: 100%
bottom: -4px
cursor: n-resize
&:before
content: "\F063"
.oe_handle.size
border-style: dashed
border-width: 0 0 1px 0
border-color: rgba(0, 0, 0, 0.5)
&:before
content: "Resize"
width: 64px
text-align: center
margin-left: -32px
margin-top: -4px
.oe_handle.w
top: 2px
height: 100%
left: -4px
cursor: e-resize
&:before
content: "\F060"
.oe_handle.n
left: 2px
width: 100%
top: -4px
cursor: s-resize
&:before
content: "\F062"
.icon.btn
display: inline-block
.oe_overlay_options
position: absolute
width: 100%
text-align: center
top: -11px
z-index: 1002
.btn, a
pointer-events: auto
cursor: pointer
.dropdown
display: inline-block
.dropdown-menu
text-align: left
min-width: 180px
.dropdown-menu select,.dropdown-menu input
display: block
.oe_handle
pointer-events: auto
position: absolute
top: 50%
left: 50%
display: block
+box-sizing(border-box)
width: 8px
height: 8px
margin: -4px
.s-resize-important, .s-resize-important *
cursor: s-resize !important
.n-resize-important, .n-resize-important *
cursor: n-resize !important
.e-resize-important, .e-resize-important *
cursor: e-resize !important
.w-resize-important, .w-resize-important *
cursor: w-resize !important
.move-important, .move-important *
cursor: move !important
// }}}
/* ---- MOBILE PREVIEW ---- {{{ */
$mobile_preview_background: #000000

View File

@ -1,220 +1,588 @@
/* ---- SNIPPET EDITOR ---- {{{ */
#oe_snippets {
position: fixed;
left: 0px;
right: 0px;
background: #282828;
-webkit-box-shadow: 0px 10px 10px -10px black inset;
-moz-box-shadow: 0px 10px 10px -10px black inset;
box-shadow: 0px 10px 10px -10px black inset;
z-index: 1010;
overflow: hidden;
}
#oe_snippets:hover {
height: auto;
}
#oe_snippets .scroll {
white-space: nowrap;
overflow-y: none;
}
#oe_snippets .nav {
display: inline-block;
border-bottom: none !important;
vertical-align: middle;
min-width: 120px;
z-index: 1;
}
#oe_snippets .nav > li {
display: block;
float: none;
}
#oe_snippets .nav > li.active {
background: black !important;
}
#oe_snippets .nav > li > a {
padding: 2px 10px !important;
width: 100%;
display: block;
border: 0;
}
#oe_snippets .pill-content {
border: 0;
}
#oe_snippets .tab-content {
display: inline-block;
white-space: nowrap;
background: black;
}
#oe_snippets .tab-content > div {
background: black;
}
#oe_snippets .tab-content > div label {
width: 44px;
color: white;
padding-left: 10px;
}
#oe_snippets .tab-content > div label div {
width: 100px;
text-align: center;
-webkit-transform: translate(-39px, 44px);
-moz-transform: translate(-39px, 44px);
-ms-transform: translate(-39px, 44px);
-o-transform: translate(-39px, 44px);
transform: translate(-39px, 44px);
-webkit-transform-origin: 50% 50% 50%;
-moz-transform-origin: 50% 50% 50%;
-ms-transform-origin: 50% 50% 50%;
-o-transform-origin: 50% 50% 50%;
transform-origin: 50% 50% 50%;
}
.oe_snippet {
float: left;
vertical-align: top;
width: 93px;
margin-left: 1px;
margin-top: 0px;
position: relative;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
cursor: move;
pointer-events: none;
}
.oe_snippet .oe_snippet_thumbnail {
pointer-events: auto;
text-align: center;
height: 100%;
background: transparent;
color: white;
position: relative;
}
.oe_snippet .oe_snippet_thumbnail:hover .oe_snippet_thumbnail_img {
-webkit-transform: scale(0.95, 0.95);
-moz-transform: scale(0.95, 0.95);
-ms-transform: scale(0.95, 0.95);
-o-transform: scale(0.95, 0.95);
transform: scale(0.95, 0.95);
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title {
font-size: 12px;
display: block;
text-shadow: 0 0 2px black;
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img {
height: 74px;
-webkit-transition: all 150ms linear;
-moz-transition: all 150ms linear;
-o-transition: all 150ms linear;
transition: all 150ms linear;
-webkit-box-shadow: inset 0px 0px 0px 3px #333333;
-moz-box-shadow: inset 0px 0px 0px 3px #333333;
box-shadow: inset 0px 0px 0px 3px #333333;
-webkit-transform: scale(1, 1);
-moz-transform: scale(1, 1);
-ms-transform: scale(1, 1);
-o-transform: scale(1, 1);
transform: scale(1, 1);
}
.oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div {
line-height: 18px;
}
.oe_snippet > :not(.oe_snippet_thumbnail) {
display: none !important;
}
#oe_snippets .oe_snippet_thumbnail {
background: #747474, -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 100, color-stop(0%, rgba(0, 0, 0, 0.25)), color-stop(100%, rgba(0, 0, 0, 0.4)));
background: #747474, -webkit-radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
background: #747474, -moz-radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
background: #747474, -o-radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
background: #747474, radial-gradient(rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.4));
}
/* ---- SNIPPETS DROP ZONES ---- {{{ */
.oe_drop_zone.oe_insert {
display: block;
height: 48px;
margin: 0px;
margin-top: -4px;
margin-bottom: -44px;
-webkit-transition: margin 250ms linear;
-moz-transition: margin 250ms linear;
-o-transition: margin 250ms linear;
transition: margin 250ms linear;
width: 100%;
position: absolute;
z-index: 1000;
}
.oe_drop_zone.oe_insert:not(.oe_vertical):before {
content: "";
display: block;
border-top: dashed 2px rgba(209, 178, 255, 0.72);
position: relative;
top: 0px;
}
.oe_drop_zone.oe_insert.oe_hover:before {
border-top: dashed 2px rgba(116, 255, 161, 0.72);
}
.oe_drop_zone.oe_insert.oe_vertical {
width: 48px;
float: left;
position: relative;
margin: 0px -24px !important;
}
.oe_drop_zone.oe_insert.oe_overlay {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
background: rgba(153, 0, 255, 0.5);
}
.oe_drop_zone, .oe_drop_zone_style {
border: none;
background: rgba(153, 0, 255, 0.3);
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
-o-border-radius: 4px;
border-radius: 4px;
}
.oe_drop_zone.oe_hover, .oe_drop_zone_style.oe_hover {
background: rgba(0, 255, 133, 0.3);
z-index: 1001;
}
.oe_drop_zone_style {
color: white;
height: 48px;
margin-bottom: 32px;
padding-top: 12px;
}
/* ---- SNIPPET MANIPULATOR ---- {{{ */
.resize_editor_busy {
background-color: rgba(0, 0, 0, 0.3);
}
.oe_overlay {
display: none;
position: absolute;
background: transparent;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
-webkit-transition: opacity 100ms linear;
-moz-transition: opacity 100ms linear;
-o-transition: opacity 100ms linear;
transition: opacity 100ms linear;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
pointer-events: none;
}
.oe_overlay.oe_active {
display: block;
border-style: dashed;
border-width: 1px;
-webkit-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
-moz-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
border-color: rgba(0, 0, 0, 0.5);
}
.oe_overlay .oe_handle {
display: block !important;
pointer-events: auto;
position: absolute;
top: 50%;
left: 50%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 16px;
height: 16px;
margin: -2px;
}
.oe_overlay .oe_handle.e:before, .oe_overlay .oe_handle.w:before, .oe_overlay .oe_handle.s:before, .oe_overlay .oe_handle.n:before, .oe_overlay .oe_handle.size .oe_handle_button {
position: relative;
top: 50%;
left: 50%;
display: block;
background: white;
border: solid 1px rgba(0, 0, 0, 0.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
width: 18px;
height: 18px;
margin: -9px;
padding-left: 1px;
font-size: 14px;
line-height: 14px;
font-family: FontAwesome;
color: rgba(0, 0, 0, 0.5);
-webkit-transition: background 100ms linear;
-moz-transition: background 100ms linear;
-o-transition: background 100ms linear;
transition: background 100ms linear;
}
.oe_overlay .oe_handle.e:hover:before, .oe_overlay .oe_handle.w:hover:before, .oe_overlay .oe_handle.s:hover:before, .oe_overlay .oe_handle.n:hover:before {
background: rgba(0, 0, 0, 0.5);
color: white;
-webkit-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
-moz-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
}
.oe_overlay .oe_handle.e {
left: auto;
top: 2px;
height: 100%;
right: -6px;
cursor: w-resize;
}
.oe_overlay .oe_handle.e:before {
content: "\F061";
}
.oe_overlay .oe_handle.s {
top: auto;
left: 2px;
width: 100%;
bottom: -6px;
cursor: n-resize;
}
.oe_overlay .oe_handle.s:before {
z-index: 0;
content: "\F063";
}
.oe_overlay .oe_handle.size {
top: auto;
left: 2px;
width: 100%;
bottom: -6px;
}
.oe_overlay .oe_handle.size .oe_handle_button {
z-index: 1;
content: "Resize";
width: 64px;
text-align: center;
margin-left: -32px;
margin-top: -10px;
cursor: row-resize;
}
.oe_overlay .oe_handle.size .oe_handle_button:hover {
background: rgba(30, 30, 30, 0.8);
color: white;
-webkit-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
-moz-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
}
.oe_overlay .oe_handle.size div {
border-style: dashed;
border-width: 0 0 1px 0;
border-color: rgba(0, 0, 0, 0.5);
position: relative;
top: 8px;
}
.oe_overlay .oe_handle.w {
top: 2px;
height: 100%;
left: -6px;
cursor: e-resize;
}
.oe_overlay .oe_handle.w:before {
content: "\F060";
}
.oe_overlay .oe_handle.n {
left: 2px;
width: 100%;
top: -6px;
cursor: s-resize;
}
.oe_overlay .oe_handle.n:before {
content: "\F062";
}
.oe_overlay .icon.btn {
display: inline-block;
}
.oe_overlay .oe_overlay_options {
position: absolute;
width: 100%;
text-align: center;
top: -11px;
z-index: 1002;
}
.oe_overlay .oe_overlay_options .btn, .oe_overlay .oe_overlay_options a {
pointer-events: auto;
cursor: pointer;
}
.oe_overlay .oe_overlay_options .dropdown {
display: inline-block;
}
.oe_overlay .oe_overlay_options .dropdown-menu {
text-align: left;
min-width: 180px;
}
.oe_overlay .oe_overlay_options .dropdown-menu select, .oe_overlay .oe_overlay_options .dropdown-menu input {
display: block;
}
.s-resize-important, .s-resize-important * {
cursor: s-resize !important;
}
.n-resize-important, .n-resize-important * {
cursor: n-resize !important;
}
.e-resize-important, .e-resize-important * {
cursor: e-resize !important;
}
.w-resize-important, .w-resize-important * {
cursor: w-resize !important;
}
.move-important, .move-important * {
cursor: move !important;
}
/* add CSS for bootstrap dropdown multi level */
.dropdown-submenu{position:relative; z-index: 1000}
.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
.dropdown-submenu:hover>.dropdown-menu{display:block;}
.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}
.dropdown-submenu:hover>a:after{border-left-color:#ffffff;}
.dropdown-submenu.pull-left{float:none;}
.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
/*
.oe_snippet_demo .oe_page{
margin-top: 50px;
margin-bottom: 300px;
padding-bottom: 10px;
}
.oe_snippet_demo .oe_page .oe_container{
min-height: 200px;
}
.oe_snippet_demo .oe_page *{
outline: 1px solid transparent;
-webkit-transiton: all 150ms linear;
}
.oe_snippet_demo .oe_page .oe_selected{
position: relative;
outline: 2px dashed rgba(151, 137, 255,0.5) !important;
cursor: pointer;
}
.oe_snippet_demo .oe_page .oe_selected:after{
content:'Insert Snippet Here';
position: absolute;
height:20px; left:-2px; right:-2px; bottom:-10px;
background: rgba(151, 137, 255, 1);
border-radius: 2px;
z-index: 800;
pointer-events :none;
color: white;
text-shadow: none;
font-size: 14px;
line-height: 20px;
text-align: center;
}
.oe_snippet_demo.oe_new .oe_page .oe_selected:after{
content:'';
height:100%;
top:0px; left:0px; right:0px; bottom:0px;
background: rgba(151, 137, 255, 0.2);
}
*/
.oe_snippet_editor{
position: fixed;
z-index: 1000;
bottom: 0;
left: 0;
right: 0;
height: 214px;
background: rgb(160,160,160);
box-shadow: 0 1px 3px rgb(100,100,100) inset;
.dropdown-submenu {
position: relative;
z-index: 1000;
}
.oe_snippet_list{
width: auto;
white-space: nowrap;
margin-left: 20px;
.dropdown-submenu > .dropdown-menu {
top: 0;
left: 100%;
margin-top: -6px;
margin-left: -1px;
-webkit-border-radius: 0 6px 6px 6px;
-moz-border-radius: 0 6px 6px 6px;
border-radius: 0 6px 6px 6px;
}
.oe_snippet_editor .oe_snippet{
box-sizing: border-box;
display: inline-block;
width: 220px;
height: 160px;
border-radius: 3px;
background: white;
margin: 20px 20px 20px 0;
cursor: pointer;
border: 2px solid transparent;
box-shadow: 0 1px 3px rgb(100,100,100);
position: relative;
top: 0;
overflow: hidden;
vertical-align: top;
user-select: none;
white-space: normal;
.dropdown-submenu:hover > .dropdown-menu {
display: block;
}
.dropdown-submenu:hover > a:after {
border-left-color: white;
}
.dropdown-submenu > a:after {
display: block;
content: " ";
float: right;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 5px 0 5px 5px;
border-left-color: #cccccc;
margin-top: 5px;
margin-right: -10px;
}
.dropdown-submenu.pull-left {
float: none;
}
.dropdown-submenu.pull-left > .dropdown-menu {
left: -100%;
margin-left: 10px;
-webkit-border-radius: 6px 0 6px 6px;
-moz-border-radius: 6px 0 6px 6px;
border-radius: 6px 0 6px 6px;
}
.oe_snippet_list {
width: auto;
white-space: nowrap;
margin-left: 20px;
}
.oe_snippet_editor .oe_snippet:after{
content: attr(name);
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
background: rgba(255,255,255,0.8);
text-align: center;
color: black;
padding: 8px;
.oe_snippet_editor {
position: fixed;
z-index: 1000;
bottom: 0;
left: 0;
right: 0;
height: 214px;
background: #a0a0a0;
box-shadow: 0 1px 3px #646464 inset;
}
.oe_snippet_editor .oe_snippet.oe_selected, .oe_snippet_editor .oe_snippet.oe_active{
border: 2px solid rgb(151, 137, 255);
box-shadow: 0px 3px 17px rgba(99, 53, 150, 0.59);
.oe_snippet_editor .oe_snippet {
box-sizing: border-box;
display: inline-block;
width: 220px;
height: 160px;
border-radius: 3px;
background: white;
margin: 20px 20px 20px 0;
cursor: pointer;
border: 2px solid transparent;
box-shadow: 0 1px 3px #646464;
position: relative;
top: 0;
overflow: hidden;
vertical-align: top;
user-select: none;
white-space: normal;
}
.oe_snippet_editor .oe_snippet > *{
pointer-events: none;
margin-top: 16px;
line-height: 1em;
zoom: 0.6;
.oe_snippet_editor .oe_snippet:after {
content: attr(name);
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
background: rgba(255, 255, 255, 0.8);
text-align: center;
color: black;
padding: 8px;
}
.oe_snippet_editor .oe_snippet > .container{
margin-top: 15px;
zoom: 0.17;
line-height: 0.999em;
line-height: 1em;
.oe_snippet_editor .oe_snippet.oe_selected, .oe_snippet_editor .oe_snippet.oe_active {
border: 2px solid #9789ff;
box-shadow: 0px 3px 17px rgba(99, 53, 150, 0.59);
}
.oe_snippet_editor .oe_snippet > .row{
margin-top: 0px;
zoom: 0.23;
line-height: 0.999em;
.oe_snippet_editor .oe_snippet > * {
pointer-events: none;
margin-top: 16px;
line-height: 1em;
zoom: 0.6;
}
.oe_snippet_editor .oe_snippet > .span6{
margin-top: 18px;
zoom: 0.34;
.oe_snippet_editor .oe_snippet > .container {
margin-top: 15px;
zoom: 0.17;
line-height: 0.999em;
line-height: 1em;
}
.oe_snippet_editor .oe_snippet > .span12{
margin-top: 16px;
zoom: 0.23;
.oe_snippet_editor .oe_snippet > .row {
margin-top: 0px;
zoom: 0.23;
line-height: 0.999em;
}
.oe_snippet_editor .oe_snippet > p{
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
font-size: 20px;
padding: 16px;
zoom: 1;
margin: 0px;
.oe_snippet_editor .oe_snippet > .span6 {
margin-top: 18px;
zoom: 0.34;
}
.oe_snippet_editor .oe_snippet.oe_new{
background: gray;
box-shadow: 0px 1px 3px rgb(90,90,90) inset;
border: 0px;
.oe_snippet_editor .oe_snippet > .span12 {
margin-top: 16px;
zoom: 0.23;
}
.oe_snippet_editor .oe_snippet.oe_new.oe_selected, .oe_snippet_editor .oe_snippet.oe_new.oe_active{
box-shadow: 0px 2px 0px 0px rgb(151,137,255) inset, 0px 3px 17px rgba(99, 53, 150, 0.59) inset;
.oe_snippet_editor .oe_snippet > p {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
font-size: 20px;
padding: 16px;
zoom: 1;
margin: 0px;
}
.oe_snippet_editor .oe_snippet.oe_new > *{
zoom:1;
margin: 0;
line-height: 160px;
text-align: center;
color: white;
font-size: 48px;
.oe_snippet_editor .oe_snippet.oe_new {
background: gray;
box-shadow: 0px 1px 3px #5a5a5a inset;
border: 0px;
}
.oe_snippet_editor .oe_snippet.oe_new:after{
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
background: transparent;
color: white;
text-shadow: 0px 1px 3px black;
line-height: 160px;
padding: 0px;
.oe_snippet_editor .oe_snippet.oe_new.oe_selected, .oe_snippet_editor .oe_snippet.oe_new.oe_active {
box-shadow: 0px 2px 0px 0px #9789ff inset, 0px 3px 17px rgba(99, 53, 150, 0.59) inset;
}
.oe_snippet_editor .oe_snippet.oe_new > * {
zoom: 1;
margin: 0;
line-height: 160px;
text-align: center;
color: white;
font-size: 48px;
}
.oe_snippet_editor .oe_snippet.oe_new:after {
position: absolute;
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
background: transparent;
color: white;
text-shadow: 0px 1px 3px black;
line-height: 160px;
padding: 0px;
}
.oe_snippet_drop {
position: relative;
border: 2px dashed rgb(174, 52, 255);
background: rgba(147, 52, 255, 0.1);
min-height: 28px;
margin: -16px auto;
border-radius: 5px;
max-width: 50%;
position: relative;
border: 2px dashed #ae34ff;
background: rgba(147, 52, 255, 0.1);
min-height: 28px;
margin: -16px auto;
border-radius: 5px;
max-width: 50%;
}
.oe_snippet_drop.oe_accepting {
border: 2px dashed rgb(52, 255, 166);
background: rgba(52, 255, 190, 0.1);
border: 2px dashed #34ffa6;
background: rgba(52, 255, 190, 0.1);
}
/*
[class*="span"]{
margin-left: 0px !important;
}
*/
#website-top-edit li.oe_snippet_editorbar {
padding: 1px 8px 2px;
font: normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif;
float: left;
margin-top: 6px;
border: 1px solid #a6a6a6;
border-bottom-color: #979797;
background: #eeeeee;
border-radius: 3px;
padding: 1px 8px 2px;
font: normal normal normal 12px Arial, Helvetica, Tahoma, Verdana, Sans-Serif;
float: left;
margin-top: 6px;
border: 1px solid #a6a6a6;
border-bottom-color: #979797;
background: #eeeeee;
border-radius: 3px;
}
#website-top-edit li.oe_snippet_editorbar > * {
display: inline-block;
height: 22px;
padding: 4px 6px;
outline: 0;
border: 0;
display: inline-block;
height: 22px;
padding: 4px 6px;
outline: 0;
border: 0;
}
#website-top-edit li.oe_snippet_editorbar a.button .icon {
cursor: inherit;
background-repeat: no-repeat;
margin-top: 1px;
width: 16px;
height: 16px;
display: inline-block;
cursor: inherit;
background-repeat: no-repeat;
margin-top: 1px;
width: 16px;
height: 16px;
display: inline-block;
}
[data-snippet-id] {
min-height: 10px;
min-width: 10px;
min-height: 10px;
min-width: 10px;
}

View File

@ -0,0 +1,467 @@
@import "compass/css3"
@import "compass/css3/user-interface"
@import "compass/css3/transition"
/* ---- SNIPPET EDITOR ---- {{{ */
#oe_snippets
position: fixed
left: 0px
right: 0px
// top property is set programmatically
background: rgb(40,40,40)
+box-shadow(0px 10px 10px -10px black inset)
z-index: 1010
overflow: hidden
&:hover
height: auto
.scroll
white-space: nowrap
overflow-y: none
.nav
display: inline-block
border-bottom: none !important
vertical-align: middle
min-width: 120px
> li
display: block
float: none
&.active
background: black !important
> a
padding: 2px 10px !important
width: 100%
display: block
border: 0
z-index: 1
.pill-content
border: 0
.tab-content
display: inline-block
white-space: nowrap
background: black
> div
background: rgb(0,0,0)
label
width: 44px
color: #fff
padding-left: 10px
div
width: 100px
text-align: center
@include transform( translate(-39px, 44px) , rotate(-90deg) )
@include transform-origin(50% 50%)
.oe_snippet
float: left
vertical-align: top
width: 93px
margin-left: 1px
margin-top: 0px
position: relative
overflow: hidden
+user-select(none)
cursor: move
pointer-events: none
.oe_snippet_thumbnail
pointer-events: auto
text-align: center
height: 100%
background: transparent
color: white
position: relative
&:hover
.oe_snippet_thumbnail_img
@include transform( scale(.95,.95))
.oe_snippet_thumbnail_title
font-size: 12px
display: block
+text-shadow(0 0 2px rgb(0,0,0))
.oe_snippet_thumbnail_img
height: 74px
@include transition(all 150ms linear)
+box-shadow(inset 0px 0px 0px 3px #333333)
@include transform( scale(1,1))
span, div
line-height: 18px
& > :not(.oe_snippet_thumbnail)
display: none !important
#oe_snippets .oe_snippet_thumbnail
@include background(#747474, radial-gradient(rgba(0,0,0,0.25),rgba(0,0,0,0.4)))
// }}}}
/* ---- SNIPPETS DROP ZONES ---- {{{ */
.oe_drop_zone.oe_insert
display: block
height: 48px
margin: 0px
margin-top: -4px
margin-bottom: -44px
@include transition(margin 250ms linear)
width: 100%
position: absolute
z-index: 1000
&:not(.oe_vertical):before
content: ""
display: block
border-top: dashed 2px rgba(209, 178, 255, 0.72)
position: relative
top: 0px
&.oe_hover:before
border-top: dashed 2px rgba(116, 255, 161, 0.72)
&.oe_vertical
width: 48px
float: left
position: relative
margin: 0px -24px !important
&.oe_overlay
+border-radius(3px)
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
//background-size: 100px 100px
background: rgba(153, 0, 255,.5)
.oe_drop_zone, .oe_drop_zone_style
border: none
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
//background-size: 100px 100px
background: rgba(153, 0, 255, .3)
+border-radius(4px)
&.oe_hover
background: rgba(0, 255, 133, .3)
z-index: 1001
.oe_drop_zone_style
color: white
height: 48px
margin-bottom: 32px
padding-top: 12px
// }}}
/* ---- SNIPPET MANIPULATOR ---- {{{ */
.resize_editor_busy
background-color: rgba(0,0,0,0.3)
.oe_overlay
display: none
position: absolute
background: transparent
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.02) ,rgba(255,255,255,.02) 35px, rgba(0,0,0,.02) 35px, rgba(0,0,0,.02) 75px))
+border-radius(3px)
@include transition(opacity 100ms linear)
+box-sizing(border-box)
pointer-events: none
&.oe_active
display: block
border-style: dashed
border-width: 1px
+box-shadow(0px 0px 0px 1px rgba(255,255,255,0.3), 0px 0px 0px 1px rgba(255,255,255,0.3) inset)
border-color: rgba(0, 0, 0, 0.5)
.oe_handle
display: block !important
pointer-events: auto
position: absolute
top: 50%
left: 50%
+box-sizing(border-box)
width: 16px
height: 16px
margin: -2px
&.e:before, &.w:before, &.s:before, &.n:before, &.size .oe_handle_button
position: relative
top: 50%
left: 50%
display: block
background: rgba(255, 255, 255, 1)
border: solid 1px rgba(0, 0, 0, .2)
+border-radius(5px)
width: 18px
height: 18px
margin: -9px
padding-left: 1px
font-size: 14px
line-height: 14px
font-family: FontAwesome
color: rgba(0,0,0,.5)
@include transition(background 100ms linear)
&.e, &.w, &.s, &.n
&:hover:before
background: rgba(0, 0, 0, .5)
color: #fff
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
&.e
left: auto
top: 2px
height: 100%
right: -6px
cursor: w-resize
&:before
content: "\F061"
&.s
top: auto
left: 2px
width: 100%
bottom: -6px
cursor: n-resize
&:before
z-index: 0
content: "\F063"
&.size
top: auto
left: 2px
width: 100%
bottom: -6px
.oe_handle_button
z-index: 1
content: "Resize"
width: 64px
text-align: center
margin-left: -32px
margin-top: -10px
cursor: row-resize
&:hover
background: rgba(30, 30, 30, .8)
color: #fff
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
div
border-style: dashed
border-width: 0 0 1px 0
border-color: rgba(0, 0, 0, 0.5)
position: relative
top: 8px
&.w
top: 2px
height: 100%
left: -6px
cursor: e-resize
&:before
content: "\F060"
&.n
left: 2px
width: 100%
top: -6px
cursor: s-resize
&:before
content: "\F062"
.icon.btn
display: inline-block
.oe_overlay_options
position: absolute
width: 100%
text-align: center
top: -11px
z-index: 1002
.btn, a
pointer-events: auto
cursor: pointer
.dropdown
display: inline-block
.dropdown-menu
text-align: left
min-width: 180px
.dropdown-menu select,.dropdown-menu input
display: block
.s-resize-important, .s-resize-important *
cursor: s-resize !important
.n-resize-important, .n-resize-important *
cursor: n-resize !important
.e-resize-important, .e-resize-important *
cursor: e-resize !important
.w-resize-important, .w-resize-important *
cursor: w-resize !important
.move-important, .move-important *
cursor: move !important
// }}}
/* add CSS for bootstrap dropdown multi level */
.dropdown-submenu
position: relative
z-index: 1000
.dropdown-submenu
&>.dropdown-menu
top: 0
left: 100%
margin-top: -6px
margin-left: -1px
-webkit-border-radius: 0 6px 6px 6px
-moz-border-radius: 0 6px 6px 6px
border-radius: 0 6px 6px 6px
&:hover
&>.dropdown-menu
display: block
&>a:after
border-left-color: #ffffff
&>a:after
display: block
content: " "
float: right
width: 0
height: 0
border-color: transparent
border-style: solid
border-width: 5px 0 5px 5px
border-left-color: #cccccc
margin-top: 5px
margin-right: -10px
&.pull-left
float: none
&>.dropdown-menu
left: -100%
margin-left: 10px
-webkit-border-radius: 6px 0 6px 6px
-moz-border-radius: 6px 0 6px 6px
border-radius: 6px 0 6px 6px
.oe_snippet_list
width: auto
white-space: nowrap
margin-left: 20px
.oe_snippet_editor
position: fixed
z-index: 1000
bottom: 0
left: 0
right: 0
height: 214px
background: rgb(160,160,160)
box-shadow: 0 1px 3px rgb(100,100,100) inset
.oe_snippet
box-sizing: border-box
display: inline-block
width: 220px
height: 160px
border-radius: 3px
background: white
margin: 20px 20px 20px 0
cursor: pointer
border: 2px solid transparent
box-shadow: 0 1px 3px rgb(100,100,100)
position: relative
top: 0
overflow: hidden
vertical-align: top
user-select: none
white-space: normal
&:after
content: attr(name)
position: absolute
bottom: 0px
left: 0px
right: 0px
background: rgba(255,255,255,0.8)
text-align: center
color: black
padding: 8px
&.oe_selected, &.oe_active
border: 2px solid rgb(151, 137, 255)
box-shadow: 0px 3px 17px rgba(99, 53, 150, 0.59)
& > *
pointer-events: none
margin-top: 16px
line-height: 1em
zoom: 0.6
& > .container
margin-top: 15px
zoom: 0.17
line-height: 0.999em
line-height: 1em
& > .row
margin-top: 0px
zoom: 0.23
line-height: 0.999em
& > .span6
margin-top: 18px
zoom: 0.34
& > .span12
margin-top: 16px
zoom: 0.23
& > p
position: absolute
top: 0
right: 0
left: 0
bottom: 0
font-size: 20px
padding: 16px
zoom: 1
margin: 0px
&.oe_new
background: gray
box-shadow: 0px 1px 3px rgb(90,90,90) inset
border: 0px
&.oe_selected, &.oe_active
box-shadow: 0px 2px 0px 0px rgb(151,137,255) inset, 0px 3px 17px rgba(99, 53, 150, 0.59) inset
& > *
zoom: 1
margin: 0
line-height: 160px
text-align: center
color: white
font-size: 48px
&:after
position: absolute
left: 0px
right: 0px
top: 0px
bottom: 0px
background: transparent
color: white
text-shadow: 0px 1px 3px black
line-height: 160px
padding: 0px
.oe_snippet_drop
position: relative
border: 2px dashed rgb(174, 52, 255)
background: rgba(147, 52, 255, 0.1)
min-height: 28px
margin: -16px auto
border-radius: 5px
max-width: 50%
&.oe_accepting
border: 2px dashed rgb(52, 255, 166)
background: rgba(52, 255, 190, 0.1)
#website-top-edit
li.oe_snippet_editorbar
padding: 1px 8px 2px
font: normal normal normal 12px Arial,Helvetica,Tahoma,Verdana,Sans-Serif
float: left
margin-top: 6px
border: 1px solid #a6a6a6
border-bottom-color: #979797
background: #eeeeee
border-radius: 3px
& > *
display: inline-block
height: 22px
padding: 4px 6px
outline: 0
border: 0
a.button .icon
cursor: inherit
background-repeat: no-repeat
margin-top: 1px
width: 16px
height: 16px
display: inline-block
[data-snippet-id]
min-height: 10px
min-width: 10px

View File

@ -1,3 +1,4 @@
@charset "utf-8";
/* THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
*
* css for editor buttons, openerp widget included in the website and other
@ -141,6 +142,7 @@ footer {
.row {
min-height: 32px;
width: 100%;
}
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
@ -324,6 +326,10 @@ ul.nav-stacked > li > a {
right: 10px;
}
.quotecarousel {
padding-bottom: 16px;
}
/* Parallax Theme */
div.carousel[data-snippet-id="slider"] .carousel-indicators li {
border: 1px solid grey;

View File

@ -101,6 +101,7 @@ footer
.row
min-height: 32px
width: 100%
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
@ -256,6 +257,8 @@ ul.nav-stacked > li > a
&.right span
right: 10px
.quotecarousel
padding-bottom: 16px
/* Parallax Theme */

View File

@ -49,7 +49,7 @@
function is_editable_node(element) {
return !(element.data('oe-model') === 'ir.ui.view'
|| element.data('cke-realelement')
|| is_editing_host(element)
|| (is_editing_host(element) && element.getAttribute('attributeEditable') !== 'true')
|| element.isReadOnly());
}

View File

@ -148,10 +148,13 @@
});
self.$el.css('top', this.parent.get('height'));
},
_get_snippet_url: function () {
return '/website/snippets';
},
fetch_snippet_templates: function () {
var self = this;
openerp.jsonRpc("/website/snippets", 'call', {})
openerp.jsonRpc(this._get_snippet_url(), 'call', {})
.then(function (html) {
var $html = $(html);
@ -180,11 +183,11 @@
$el.css({
'position': 'absolute',
'width': $target.outerWidth(),
'height': $target.outerHeight() + mt + mb,
'height': $target.outerHeight() + mt + mb+1,
'top': pos.top - mt,
'left': pos.left
});
$el.find(".oe_handle.size").css("bottom", mb+'px');
$el.find(".oe_handle.size").css("bottom", (mb-7)+'px');
},
show: function () {
this.$el.removeClass("hidden");
@ -970,7 +973,7 @@
this.$overlay.append($box.find(".oe_handles").html());
this.$overlay.find(".oe_handle").on('mousedown', function (event){
this.$overlay.find(".oe_handle:not(:has(.oe_handle_button)), .oe_handle .oe_handle_button").on('mousedown', function (event){
event.preventDefault();
var $handle = $(this);
@ -1004,7 +1007,6 @@
if (compass === 'size') {
var grid = resize[0];
var offset = self.$target.offset().top;
if (self.$target.css("background").match(/rgba\(0, 0, 0, 0\)/)) {
self.$target.addClass("resize_editor_busy");
@ -1032,10 +1034,10 @@
event.preventDefault();
if (compass === 'size') {
var dy = event.pageY-offset;
dy = dy - dy%resize[0];
if (dy <= 0) dy = resize[0];
dy = dy - dy%resize;
if (dy <= 0) dy = resize;
self.$target.css("height", dy+"px");
self.on_resize(compass, beginClass, current);
self.on_resize(compass, null, dy);
self.parent.cover_target(self.$overlay, self.$target);
return;
}
@ -1080,7 +1082,8 @@
// list of class (Array), grid (Array), default value (INT)
n: [_.map(grid, function (v) {return 'mt'+v;}), grid],
s: [_.map(grid, function (v) {return 'mb'+v;}), grid],
size: [8]
// INT if the user can resize the snippet (resizing per INT px)
size: null
};
return this.grid;
},
@ -1292,6 +1295,11 @@
});
website.snippet.editorRegistry.carousel = website.snippet.editorRegistry.slider.extend({
getSize: function () {
this.grid = this._super();
this.grid.size = 8;
return this.grid;
},
clean_for_save: function () {
this._super();
this.$target.css("background-image", "");
@ -1355,11 +1363,20 @@
self.$target.carousel( $(this).data('slide')); });
this.$target.find('.carousel-image, .content').attr('contentEditable', 'true');
this.$target.find('.carousel-image').attr('attributeEditable', 'true');
this._super();
},
});
website.snippet.editorRegistry.parallax = website.snippet.editorRegistry.resize.extend({
getSize: function () {
this.grid = this._super();
this.grid.size = 8;
return this.grid;
},
on_resize: function (compass, beginClass, current) {
this.$target.data("snippet-view").set_values();
},
start : function () {
var self = this;
this._super();

View File

@ -86,7 +86,7 @@
<div class='oe_handle n'></div>
<div class='oe_handle e'></div>
<div class='oe_handle w'></div>
<div class='oe_handle size'></div>
<div class='oe_handle size'><div class="oe_handle_button size">Resize</div><div class="oe_border"/></div>
<div class='oe_handle s'></div>
</div>
<div class='oe_snippet_thumbnail'>Margin resize</div>

View File

@ -117,7 +117,7 @@
Write one sentence to convince visitor about your message.
</p>
<p>
<a class="btn btn-primary btn-lg" href="/website.contactus">
<a class="btn btn-primary btn-lg" href="/page/website.contactus">
Contact us
</a>
</p>
@ -277,7 +277,7 @@
<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 slide mb0" style="height: 240px;">
<div id="myQuoteCarousel" class="oe_snippet_body carousel quotecarousel slide mb0">
<!-- Indicators -->
<ol class="carousel-indicators mb0">
<li data-target="#myQuoteCarousel" data-slide-to="0" class="active"></li>
@ -825,7 +825,7 @@
data-scroll-background-ratio="0.3">
<div>
<div class="oe_structure">
<div id="myQuoteCarousel" class="carousel slide mb0" style="height: 240px;" data-snippet-id="slider">
<div id="myQuoteCarousel" class="carousel quotecarousel slide mb0" data-snippet-id="slider">
<!-- Indicators -->
<ol class="carousel-indicators mb0">
<li data-target="#myQuoteCarousel" data-slide-to="0" class="active"></li>

View File

@ -75,7 +75,7 @@
<script type="text/javascript" src="/website/static/src/js/website.js"></script>
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.snippets.animation.js"></script>
<t t-raw="head or ''"/>
<t t-raw="head or ''" name='layout_head'/>
</head>
<body>
<div id="wrapwrap">
@ -196,7 +196,7 @@
</template>
<template id="editor_head" inherit_id="website.layout" name="Editor" groups="base.group_website_publisher">
<xpath expr="//head" position="inside">
<xpath expr='//t[@name="layout_head"]' position="before">
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
<link rel='stylesheet' href='/website/static/src/css/editor.css'/>
<link rel='stylesheet' href='/website/static/lib/bootstrap-tour/bootstrap-tour.css'/>

View File

@ -15,4 +15,5 @@ OpenERP Contact Form
'views/website_crm.xml',
],
'installable': True,
'auto_install': True,
}

View File

@ -28,7 +28,10 @@
'author': 'OpenERP SA',
'depends': ['website', 'mail'],
'data': [
'views/snippets.xml',
'views/website_mail.xml',
'views/website_email_designer.xml',
'views/email_template_view.xml',
'security/website_mail.xml',
],
'css': [

View File

@ -1 +1,2 @@
import email_designer
import main

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website.models import website
class WebsiteEmailDesigner(http.Controller):
@website.route('/website_mail/email_designer/<model("email.template"):template>/', type='http', auth="public", multilang=True)
def index(self, template, **kw):
values = {
'template': template,
}
print template
return request.website.render("website_mail.designer_index", values)
@website.route(['/website_mail/snippets'], type='json', auth="public")
def snippets(self):
return request.website._render('website_mail.email_designer_snippets')

View File

@ -1,2 +1,3 @@
import mail_message
import mail_thread
import email_template

View File

@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2014-Today OpenERP SA (<http://www.openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import lxml
import urlparse
from openerp.osv import osv, fields
from openerp.tools.translate import _
class EmailTemplate(osv.Model):
_inherit = 'email.template'
def _get_website_link(self, cr, uid, ids, name, args, context=None):
return dict((id, _('<a href="website_mail/email_designer/%s">Edit in Website</a>') % id) for id in ids)
_columns = {
'website_link': fields.function(
_get_website_link, type='text',
string='Website Link',
help='Link to the website',
),
}
def _postprocess_html_replace_links(self, cr, uid, body_html, context=None):
""" Post-processing of body_html. Indeed the content generated by the
website builder contains references to local addresses, for example
for images. This method changes those addresses to absolute addresses. """
html = body_html
if not body_html:
return html
# form a tree
root = lxml.html.fromstring(html)
if not len(root) and root.text is None and root.tail is None:
html = '<div>%s</div>' % html
root = lxml.html.fromstring(html)
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
(base_scheme, base_netloc, bpath, bparams, bquery, bfragment) = urlparse.urlparse(base_url)
def _process_link(url):
new_url = url
(scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
if not scheme and not netloc:
new_url = urlparse.urlunparse((base_scheme, base_netloc, path, params, query, fragment))
return new_url
# check all nodes, replace :
# - img src -> check URL
# - a href -> check URL
for node in root.iter():
if node.tag == 'a':
node.set('href', _process_link(node.get('href')))
elif node.tag == 'img' and not node.get('src', 'data').startswith('data'):
node.set('src', _process_link(node.get('src')))
html = lxml.etree.tostring(root, pretty_print=False)
return html
def create(self, cr, uid, values, context=None):
if 'body_html' in values:
values['body_html'] = self._postprocess_html_replace_links(cr, uid, values['body_html'], context=context)
return super(EmailTemplate, self).create(cr, uid, values, context=context)
def write(self, cr, uid, ids, values, context=None):
if 'body_html' in values:
values['body_html'] = self._postprocess_html_replace_links(cr, uid, values['body_html'], context=context)
return super(EmailTemplate, self).write(cr, uid, ids, values, context=context)

View File

@ -0,0 +1,17 @@
(function () {
'use strict';
var website = openerp.website;
website.snippet.BuildingBlock.include({
// init: function (parent) {
// this._super.apply(this, arguments);
// },
_get_snippet_url: function () {
return '/website_mail/snippets';
}
});
})();

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="email_template_form_inherit_website_link">
<field name="name">email.template.form</field>
<field name="model">email.template</field>
<field name="inherit_id" ref="email_template.email_template_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@string='Mailing Template']/group" position="before">
<field name="website_link" widget='html' radonly='1'/>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@ -0,0 +1,459 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="email_designer_snippets">
<div class="scroll" t-ignore="1">
<ul class="nav navbar-nav nav-tabs">
<li class="active"><a href="#snippet_structure" data-toggle="tab">Structure</a></li>
<li><a href="#snippet_content" data-toggle="tab">Content</a></li>
<li><a href="#snippet_feature" data-toggle="tab">Features</a></li>
<li><a href="#snippet_effect" data-toggle="tab">Effects</a></li>
</ul>
<div class="tab-content">
<div id="snippet_structure" class="tab-pane fade in active">
<div data-snippet-id="text-image" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:600px" valign="top">
<div style="padding:0px 5px">
<table style="font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top">
<h3 style="text-align: center; padding:0px 5px">A Section Subtitle</h3>
<p style="overflow:hidden; font-size:12px">
Write one or two paragraphs describing your product,
services or a specific feature. To be successful
your content needs to be useful to your readers.
</p><p style="overflow:hidden; font-size:12px">
Start with the customer find out what they want
and give it to them.
</p>
</td>
<td width="10"></td>
<td valign="top" width="290">
<img width="270" style="display:block;border:none;min-height:150px" src="/website/static/src/img/text_image.png"/>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="image-text" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px 5px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td style="width:600px" valign="top">
<div style="padding:0px 5px">
<table style="font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" width="290">
<img width="270" style="display:block;border:none;min-height:150px" alt="" src="/website/static/src/img/image_text.jpg"/>
</td>
<td width="10"></td>
<td valign="top">
<h3 style="text-align: center; padding:0px 5px">A Section Subtitle</h3>
<p style="overflow:hidden; font-size:12px">
Write one or two paragraphs describing your product,
services or a specific feature. To be successful
your content needs to be useful to your readers.
</p><p style="overflow:hidden; font-size:12px">
Start with the customer find out what they want
and give it to them.
</p>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="text-image" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px 5px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:600px">
<div style="padding:0px 5px">
<h1 style="text-align: center">Sell Online. Easily.</h1>
<p style="overflow:hidden">
Write one sentence to convince visitor about your message.
</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="text-image" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px 5px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:600px">
<h2 style="text-align: center">
A Great Headline
</h2>
<h3 style="text-align: center">
A good subtitle
</h3>
</td>
</tr>
<tr>
<td valign="top" style="width:600px">
<div style="padding:0px 5px">
<p style="overflow:hidden">
A great way to catch your reader's attention is to tell a story.
Everything you consider writing can be told as a story.
</p>
<p style="overflow:hidden">
<strong>Great stories have personality</strong>. Consider telling
a great story that provides personality. Writing a story
with personality for potential clients will asist with
making a relationship connection. This shows up in small
quirks like word choices or phrases. Write from your point
of view, not from someone else's experience.
</p>
<p style="overflow:hidden">
<strong>Great stories are for everyone even when only written for
just one person</strong>. If you try to write with a wide general
audience in mind, your story will ring false and be bland.
No one will be interested. Write for one person. If its genuine
for the one, its genuine for the rest.
</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="hr" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:600px">
<div style="padding:0px 5px">
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0"/>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="big-picture" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:600px">
<h2 style="text-align: center; padding:0px 5px">A Punchy Headline</h2>
</td>
</tr>
<tr>
<td valign="top" style="width:600px">
<img width="500" style="display:block;border:none;min-height:250px;margin:0 auto;" src="/website/static/src/img/big_picture.png"/>
</td>
</tr>
<tr>
<td valign="top" style="width:600px">
<p style="text-align: center; overflow:hidden">
<h3 style="text-align: center; padding:0px 5px">A Small Subtitle</h3>
</p>
<p style="text-align: center; overflow:hidden">
Choose a vibrant image and write an inspiring paragraph
about it. It does not have to be long, but it should
reinforce your image.
</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="three-columns" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:200px">
<img width="175" style="display:block;border:none;min-height:50px" src="/website/static/src/img/desert_thumb.jpg"/>
</td>
<td valign="top" style="width:200px">
<img width="175" style="display:block;border:none;min-height:50px" src="/website/static/src/img/deers_thumb.jpg"/>
</td>
<td valign="top" style="width:200px">
<img width="175" style="display:block;border:none;min-height:50px" src="/website/static/src/img/china_thumb.jpg"/>
</td>
</tr>
<tr>
<td valign="top" style="width:200px">
<h3 style="text-align: center; padding:0px 5px">Feature One</h3>
<p style="overflow:hidden">
Choose a vibrant image and write an inspiring paragraph
about it. It does not have to be long, but it should
reinforce your image.
</p>
</td>
<td valign="top" style="width:200px">
<h3 style="text-align: center; padding:0px 5px">Feature Two</h3>
<p style="overflow:hidden">
Choose a vibrant image and write an inspiring paragraph
about it. It does not have to be long, but it should
reinforce your image.
</p>
</td>
<td valign="top" style="width:200px">
<h3 style="text-align: center; padding:0px 5px">Feature Three</h3>
<p style="overflow:hidden">
Choose a vibrant image and write an inspiring paragraph
about it. It does not have to be long, but it should
reinforce your image.
</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="snippet_feature" class="tab-pane fade">
<div data-snippet-id="pricing" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<div style="width:600px">
<h2 style="text-align: center">Our Offers</h2>
</div>
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:200px; bgcolor: #bce8f1; background-color: #bce8f1;">
<h2 style="text-align: center">Beginner</h2>
<p style="text-align: center; overflow:hidden">Starter Package</p>
</td>
<td valign="top" style="width:200px; bgcolor: #428bca; background-color: #428bca;">
<h2 style="text-align: center">Professional</h2>
<p style="text-align: center; overflow:hidden">Enterprise package</p>
</td>
<td valign="top" style="width:200px; bgcolor: #bce8f1; background-color: #bce8f1;">
<h2 style="text-align: center">Expert</h2>
<p style="text-align: center; overflow:hidden">The top of the top</p>
</td>
</tr>
<tr>
<td valign="top" style="width:200px">
<h2 style="margin: 0; text-align: center">$<strong style="font-size: 30px">450</strong><small>.00</small></h2>
<p style="text-align: center">per month</p>
</td>
<td valign="top" style="width:200px">
<h2 style="margin: 0; text-align: center">$<strong style="font-size: 30px">590</strong><small>.00</small></h2>
<p style="text-align: center">per month</p>
</td>
<td valign="top" style="width:200px">
<h2 style="margin: 0; text-align: center">$<strong style="font-size: 30px">890</strong><small>.00</small></h2>
<p style="text-align: center">per month</p>
</td>
</tr>
<tr>
<td valign="top" style="width:200px">
<ul>
<li>Battery: 8 hours</li>
<li>Screen: 2.5 inch</li>
<li>Weight: 1.1 ounces</li>
<li>No support</li>
</ul>
</td>
<td valign="top" style="width:200px">
<ul>
<li>Battery: 12 hours</li>
<li>Screen: 2.8 inch</li>
<li>Weight: 1.2 ounces</li>
<li>Limited support</li>
</ul>
</td>
<td valign="top" style="width:200px">
<ul>
<li>Battery: 20 hours</li>
<li>Screen: 2.8 inch</li>
<li>Weight: 1.2 ounces</li>
<li>Unlimited support</li>
</ul>
</td>
</tr>
<tr>
<td valign="top" style="width:200px">
<p style="text-align: center; overflow: hidden">
<i>Free shipping, satisfied or reimbursed.</i><br/>
<a href="/page/website.contactus">Order now</a>
</p>
</td>
<td valign="top" style="width:200px">
<p style="text-align: center; overflow: hidden">
<i>Free shipping, satisfied or reimbursed.</i><br/>
<a href="/page/website.contactus">Order now</a>
</p>
</td>
<td valign="top" style="width:200px">
<p style="text-align: center; overflow: hidden">
<i>Free shipping, satisfied or reimbursed.</i><br/>
<a href="/page/website.contactus">Contact us</a>
</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div data-snippet-id="cta" data-selector-children=".oe_structure, [data-oe-type=html]">
<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>
<div class="oe_snippet_body" style="padding:0px; margin:0px">
<table cellspacing="0" cellpadding="0" style="margin:10px 0px 0px;vertical-align:top;padding:0px;font-family:arial;font-size:12px;color:rgb(51,51,51)">
<tbody>
<tr>
<td valign="top" style="width:200px">
<div style="padding:0px 5px">
<table style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;background-color:rgb(153,153,153);border-collapse:collapse;width:70px;font-family:arial;font-size:12px;color:rgb(51,51,51);margin-left:60px" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:15px 5px;border-collapse:collapse;background-color:rgb(101,101,101)" align="center" valign="middle">
<a href="http://r.info.openerp.com/3bbh9o3y3tjskrk.html" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
<span style="color:rgb(255,255,255);font-family:arial;font-size:12px;display:block;width:auto;text-align:center;white-space:nowrap">View Product</span>
</a>
</td>
</tr>
<tr>
</tr>
</tbody>
</table>
</div>
</td>
<td valign="top" style="width:200px">
<div style="padding:0px 5px">
<table style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;background-color:rgb(153,153,153);border-collapse:collapse;width:70px;font-family:arial;font-size:12px;color:rgb(51,51,51);margin-left:60px" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:15px 5px;border-collapse:collapse;background-color:rgb(101,101,101)" align="center" valign="middle">
<a href="http://r.info.openerp.com/3bbh9o3y3tjskrk.html" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
<span style="color:rgb(255,255,255);font-family:arial;font-size:12px;display:block;width:auto;text-align:center;white-space:nowrap">View Product</span>
</a>
</td>
</tr>
<tr>
</tr>
</tbody>
</table>
</div>
</td>
<td valign="top" style="width:200px">
<div style="padding:0px 5px">
<table style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;background-color:rgb(153,153,153);border-collapse:collapse;width:70px;font-family:arial;font-size:12px;color:rgb(51,51,51);margin-left:60px" border="0" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td style="border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:4px;border-bottom-left-radius:4px;padding:15px 5px;border-collapse:collapse;background-color:rgb(101,101,101)" align="center" valign="middle">
<a href="http://r.info.openerp.com/3bbh9o3y3tjskrk.html" style="text-decoration:none;border:none rgb(221,221,221);font-weight:bold;line-height:100%;text-align:center;color:rgb(0,136,204);word-wrap:break-word!important;background-color:rgb(101,101,101)" target="_blank">
<span style="color:rgb(255,255,255);font-family:arial;font-size:12px;display:block;width:auto;text-align:center;white-space:nowrap">View Product</span>
</a>
</td>
</tr>
<tr>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="snippet_effect" class="tab-pane fade">
</div>
<div id="snippet_styles" class="hidden">
</div>
</div>
</div>
</template>
</data>
</openerp>

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Email Designer main page -->
<template id="designer_index" name="Email Designer">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_mail/static/src/js/website_email_designer.js"></script>
</t>
<div id="wrap">
<div class="oe_structure container">
<h1 t-field="template.name"/>
<div class="row" style="width: 600px;">
<div class="row">
<div class="col-lg-3"><b>Email From</b></div>
<div class="col-lg-9"><span t-field="template.email_from"/></div>
</div>
<div class="row">
<div class="col-lg-3"><b>To (Email)</b></div>
<div class="col-lg-9"><span t-field="template.email_to"/></div>
</div>
<div class="row">
<div class="col-lg-3"><b>To (Partners)</b></div>
<div class="col-lg-9"><span t-field="template.partner_to"/></div>
</div>
<div class="row">
<div class="col-lg-3"><b>Reply To</b></div>
<div class="col-lg-9"><span t-field="template.reply_to"/></div>
</div>
<div class="row">
<div class="col-lg-3"><b>Subject</b></div>
<div class="col-lg-9"><span t-field="template.subject"/></div>
</div>
<div class="row well">
<div t-field="template.body_html"/>
</div>
</div>
</div>
</div>
</t>
<t t-set="website.footer"></t>
</template>
</data>
</openerp>

View File

@ -114,10 +114,10 @@ class Ecommerce(http.Controller):
_order = 'website_published desc, website_sequence desc'
def get_attribute_ids(self):
attributes_obj = request.registry['product.attribute']
attributes_ids = attributes_obj.search(request.cr, request.uid, [], context=request.context)
return attributes_obj.browse(request.cr, request.uid, attributes_ids, context=request.context)
def get_characteristic_ids(self):
characteristics_obj = request.registry['product.characteristic']
characteristics_ids = characteristics_obj.search(request.cr, request.uid, [], context=request.context)
return characteristics_obj.browse(request.cr, request.uid, characteristics_ids, context=request.context)
def get_pricelist(self):
""" Shortcut to get the pricelist from the website model """
@ -134,13 +134,13 @@ class Ecommerce(http.Controller):
product_ids = [id for id in product_ids if id in product_obj.search(request.cr, request.uid, [("id", 'in', product_ids)], context=request.context)]
return product_obj.browse(request.cr, request.uid, product_ids, context=request.context)
def has_search_filter(self, attribute_id, value_id=None):
def has_search_filter(self, characteristic_id, value_id=None):
if request.httprequest.args.get('filters'):
filters = simplejson.loads(request.httprequest.args['filters'])
else:
filters = []
for key_val in filters:
if key_val[0] == attribute_id and (not value_id or value_id in key_val[1:]):
if key_val[0] == characteristic_id and (not value_id or value_id in key_val[1:]):
return key_val
return False
@ -176,11 +176,11 @@ class Ecommerce(http.Controller):
post.get("category") and ("&category=%s" % post.get("category")) or ""
))
def attributes_to_ids(self, attributes):
obj = request.registry.get('product.attribute.product')
def characteristics_to_ids(self, characteristics):
obj = request.registry.get('product.characteristic.product')
domain = []
for key_val in attributes:
domain.append(("attribute_id", "=", key_val[0]))
for key_val in characteristics:
domain.append(("characteristic_id", "=", key_val[0]))
if isinstance(key_val[1], list):
domain.append(("value", ">=", key_val[1][0]))
domain.append(("value", "<=", key_val[1][1]))
@ -215,7 +215,7 @@ class Ecommerce(http.Controller):
if filters:
filters = simplejson.loads(filters)
if filters:
ids = self.attributes_to_ids(filters)
ids = self.characteristics_to_ids(filters)
domain.append(('id', 'in', ids or [0]))
product_count = product_obj.search_count(cr, uid, domain, context=context)
@ -491,10 +491,6 @@ class Ecommerce(http.Controller):
shipping_partner = orm_partner.browse(cr, SUPERUSER_ID, shipping_ids[0], context)
checkout.update(info.from_partner(shipping_partner, address_type='shipping'))
for field_name in info.mandatory_fields():
if not checkout[field_name]:
error[field_name] = 'missing'
return request.website.render("website_sale.checkout", values)
@website.route(['/shop/confirm_order/'], type='http', auth="public", multilang=True)
@ -549,7 +545,7 @@ class Ecommerce(http.Controller):
company_ids = orm_parter.search(cr, SUPERUSER_ID, [("name", "ilike", company_name), ('is_company', '=', True)], context=context)
company_id = (company_ids and company_ids[0]) or orm_parter.create(cr, SUPERUSER_ID, {'name': company_name, 'is_company': True}, context)
billing_info = dict(checkout)
billing_info = dict((k, v) for k,v in checkout.items() if "shipping_" not in k and k != "company")
billing_info['parent_id'] = company_id
if request.uid != request.registry['website'].get_public_user(cr, uid, context):

View File

@ -2,6 +2,11 @@
<openerp>
<data noupdate="1">
<record id="product.group_product_characteristics" model="res.groups">
<field name="name">Product Characteristic (not supported)</field>
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="menu_shop" model="website.menu">
<field name="name">Shop</field>
<field name="url">/shop</field>

View File

@ -1,6 +1,7 @@
import website_styles
import payment_transaction
import product
import product_attributes
import product_characteristics
import res_config
import sale_order
import website

View File

@ -1,87 +0,0 @@
from openerp.osv import osv, fields
class attributes(osv.Model):
_name = "product.attribute"
def _get_float_max(self, cr, uid, ids, field_name, arg, context=None):
result = dict.fromkeys(ids, 0)
if ids:
cr.execute("""
SELECT attribute_id, MAX(value)
FROM product_attribute_product
WHERE attribute_id in (%s)
GROUP BY attribute_id
""" % ",".join(map(str, ids)))
result.update(dict(cr.fetchall()))
return result
def _get_float_min(self, cr, uid, ids, field_name, arg, context=None):
result = dict.fromkeys(ids, 0)
if ids:
cr.execute("""
SELECT attribute_id, MIN(value)
FROM product_attribute_product
WHERE attribute_id in (%s)
GROUP BY attribute_id
""" % ",".join(map(str, ids)))
result.update(dict(cr.fetchall()))
return result
def _get_min_max(self, cr, uid, ids, context=None):
result = {}
for value in self.pool.get('product.attribute.product').browse(cr, uid, ids, context=context):
if value.type == 'float':
result[value.attribute_id.id] = True
return result.keys()
_columns = {
'name': fields.char('Name', size=64, translate=True, required=True),
'type': fields.selection([('distinct', 'Textual Value'), ('float', 'Numeric Value')], "Type", required=True),
'value_ids': fields.one2many('product.attribute.value', 'attribute_id', 'Values'),
'attr_product_ids': fields.one2many('product.attribute.product', 'attribute_id', 'Products'),
'float_max': fields.function(_get_float_max, type='float', string="Max", store={
'product.attribute.product': (_get_min_max, ['value','attribute_id'], 20),
}),
'float_min': fields.function(_get_float_min, type='float', string="Min", store={
'product.attribute.product': (_get_min_max, ['value','attribute_id'], 20),
}),
'visible': fields.boolean('Display Filter on Website'),
}
_defaults = {
'type': 'distinct',
'visible': True,
}
class attributes_value(osv.Model):
_name = "product.attribute.value"
_columns = {
'name': fields.char('Value', size=64, translate=True, required=True),
'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True),
'atr_product_ids': fields.one2many('product.attribute.product', 'value_id', 'Products'),
}
class attributes_product(osv.Model):
_name = "product.attribute.product"
_order = 'attribute_id, value_id, value'
_columns = {
'value': fields.float('Numeric Value'),
'value_id': fields.many2one('product.attribute.value', 'Textual Value'),
'attribute_id': fields.many2one('product.attribute', 'Attribute', required=True),
'product_tmpl_id': fields.many2one('product.template', 'Product', required=True),
'type': fields.related('attribute_id', 'type', type='selection',
selection=[('distinct', 'Distinct'), ('float', 'Float')], string='Type'),
}
def onchange_attribute_id(self, cr, uid, ids, attribute_id, context=None):
attribute = self.pool.get('product.attribute').browse(cr, uid, attribute_id, context=context)
return {'value': {'type': attribute.type, 'value_id': False, 'value': ''}}
class product_template(osv.Model):
_inherit = "product.template"
_columns = {
'website_attribute_ids': fields.one2many('product.attribute.product', 'product_tmpl_id', 'Product Attributes'),
}

View File

@ -0,0 +1,87 @@
from openerp.osv import osv, fields
class characteristics(osv.Model):
_name = "product.characteristic"
def _get_float_max(self, cr, uid, ids, field_name, arg, context=None):
result = dict.fromkeys(ids, 0)
if ids:
cr.execute("""
SELECT characteristic_id, MAX(value)
FROM product_characteristic_product
WHERE characteristic_id in (%s)
GROUP BY characteristic_id
""" % ",".join(map(str, ids)))
result.update(dict(cr.fetchall()))
return result
def _get_float_min(self, cr, uid, ids, field_name, arg, context=None):
result = dict.fromkeys(ids, 0)
if ids:
cr.execute("""
SELECT characteristic_id, MIN(value)
FROM product_characteristic_product
WHERE characteristic_id in (%s)
GROUP BY characteristic_id
""" % ",".join(map(str, ids)))
result.update(dict(cr.fetchall()))
return result
def _get_min_max(self, cr, uid, ids, context=None):
result = {}
for value in self.pool.get('product.characteristic.product').browse(cr, uid, ids, context=context):
if value.type == 'float':
result[value.characteristic_id.id] = True
return result.keys()
_columns = {
'name': fields.char('Name', size=64, translate=True, required=True),
'type': fields.selection([('distinct', 'Textual Value'), ('float', 'Numeric Value')], "Type", required=True),
'value_ids': fields.one2many('product.characteristic.value', 'characteristic_id', 'Values'),
'attr_product_ids': fields.one2many('product.characteristic.product', 'characteristic_id', 'Products'),
'float_max': fields.function(_get_float_max, type='float', string="Max", store={
'product.characteristic.product': (_get_min_max, ['value','characteristic_id'], 20),
}),
'float_min': fields.function(_get_float_min, type='float', string="Min", store={
'product.characteristic.product': (_get_min_max, ['value','characteristic_id'], 20),
}),
'visible': fields.boolean('Display Filter on Website'),
}
_defaults = {
'type': 'distinct',
'visible': True,
}
class characteristics_value(osv.Model):
_name = "product.characteristic.value"
_columns = {
'name': fields.char('Value', size=64, translate=True, required=True),
'characteristic_id': fields.many2one('product.characteristic', 'Characteristic', required=True),
'atr_product_ids': fields.one2many('product.characteristic.product', 'value_id', 'Products'),
}
class characteristics_product(osv.Model):
_name = "product.characteristic.product"
_order = 'characteristic_id, value_id, value'
_columns = {
'value': fields.float('Numeric Value'),
'value_id': fields.many2one('product.characteristic.value', 'Textual Value'),
'characteristic_id': fields.many2one('product.characteristic', 'Characteristic', required=True),
'product_tmpl_id': fields.many2one('product.template', 'Product', required=True),
'type': fields.related('characteristic_id', 'type', type='selection',
selection=[('distinct', 'Distinct'), ('float', 'Float')], string='Type'),
}
def onchange_characteristic_id(self, cr, uid, ids, characteristic_id, context=None):
characteristic = self.pool.get('product.characteristic').browse(cr, uid, characteristic_id, context=context)
return {'value': {'type': characteristic.type, 'value_id': False, 'value': ''}}
class product_template(osv.Model):
_inherit = "product.template"
_columns = {
'website_characteristic_ids': fields.one2many('product.characteristic.product', 'product_tmpl_id', 'Product Characteristics'),
}

View File

@ -0,0 +1,11 @@
from openerp.osv import osv, fields
class sale_configuration(osv.osv_memory):
_inherit = 'sale.config.settings'
_columns = {
'group_product_characteristics': fields.boolean("Support multiple characteristics per products ",
implied_group='product.group_product_characteristics',
help="""Allow to manage several characteristics per product. This characteristics are used for filter and compare your products. As an example, if you sell all in one computers, you may have characteristics like RAM, Processor Speed, Manufacturing, to compare products"""),
}

View File

@ -7,8 +7,8 @@ access_product_pricelist_version_public,product.pricelist.version.public,product
access_product_pricelist_public,product.pricelist.public,product.model_product_pricelist,base.group_public,1,0,0,0
access_product_pricelist_item_public,product.pricelist.item.public,product.model_product_pricelist_item,base.group_public,1,0,0,0
access_product_product_price_type_public,product.price.type.public,product.model_product_price_type,base.group_public,1,0,0,0
access_product_attribute,product.attribute.public,website_sale.model_product_attribute,,1,0,0,0
access_product_attribute_value,product.attribute.value.public,website_sale.model_product_attribute_value,,1,0,0,0
access_product_attribute_product,product.attribute.product.public,website_sale.model_product_attribute_product,,1,0,0,0
access_product_characteristic,product.characteristic.public,website_sale.model_product_characteristic,,1,0,0,0
access_product_characteristic_value,product.characteristic.value.public,website_sale.model_product_characteristic_value,,1,0,0,0
access_product_characteristic_product,product.characteristic.product.public,website_sale.model_product_characteristic_product,,1,0,0,0
access_website_product_style,website.product.style.public,website_sale.model_website_product_style,,1,0,0,0
access_product_supplierinfo,product.supplierinfo.public,product.model_product_supplierinfo,base.group_public,1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
7 access_product_pricelist_public product.pricelist.public product.model_product_pricelist base.group_public 1 0 0 0
8 access_product_pricelist_item_public product.pricelist.item.public product.model_product_pricelist_item base.group_public 1 0 0 0
9 access_product_product_price_type_public product.price.type.public product.model_product_price_type base.group_public 1 0 0 0
10 access_product_attribute access_product_characteristic product.attribute.public product.characteristic.public website_sale.model_product_attribute website_sale.model_product_characteristic 1 0 0 0
11 access_product_attribute_value access_product_characteristic_value product.attribute.value.public product.characteristic.value.public website_sale.model_product_attribute_value website_sale.model_product_characteristic_value 1 0 0 0
12 access_product_attribute_product access_product_characteristic_product product.attribute.product.public product.characteristic.product.public website_sale.model_product_attribute_product website_sale.model_product_characteristic_product 1 0 0 0
13 access_website_product_style website.product.style.public website_sale.model_website_product_style 1 0 0 0
14 access_product_supplierinfo product.supplierinfo.public product.model_product_supplierinfo base.group_public 1 0 0 0

View File

@ -92,7 +92,7 @@
<div class="oe_structure"/>
<div class="container oe_website_sale">
<div class="products_pager">
<div>
<div class="row">
<form action="/shop/" method="get" class="pagination form-inline col-md-3">
<t t-call="website_sale.search" />
</form>
@ -371,13 +371,13 @@
</xpath>
</template>
<!-- Product option: attributes -->
<template id="product_attributes" inherit_option_id="website_sale.product" name="Product Attributes">
<!-- Product option: characteristics -->
<template id="product_characteristics" inherit_id="website_sale.product" inherit_option_id="website_sale.product" name="Product Characteristics" groups="product.group_product_characteristics">
<xpath expr="//p[@t-field='product.description_sale']" position="after">
<hr t-if="product.website_attribute_ids"/>
<hr t-if="product.website_characteristic_ids"/>
<p class="text-muted">
<t t-set="attr" t-value="None"/>
<t t-foreach="product.website_attribute_ids" t-as="attribute"><br t-if="attr and attribute.attribute_id.id != attr"/><t t-if="attribute.attribute_id.id != attr"><span t-field="attribute.attribute_id"/>: </t><t t-if="attribute.attribute_id.id == attr">, </t><t t-if="attribute.attribute_id.type == 'distinct'"><span t-field="attribute.value_id"/></t><t t-if="attribute.attribute_id.type == 'float'"><span t-field="attribute.value"/></t><t t-set="attr" t-value="attribute.attribute_id.id"/></t>
<t t-foreach="product.website_characteristic_ids" t-as="characteristic"><br t-if="attr and characteristic.characteristic_id.id != attr"/><t t-if="characteristic.characteristic_id.id != attr"><span t-field="characteristic.characteristic_id"/>: </t><t t-if="characteristic.characteristic_id.id == attr">, </t><t t-if="characteristic.characteristic_id.type == 'distinct'"><span t-field="characteristic.value_id"/></t><t t-if="characteristic.characteristic_id.type == 'float'"><span t-field="characteristic.value"/></t><t t-set="attr" t-value="characteristic.characteristic_id.id"/></t>
</p>
</xpath>
</template>
@ -595,36 +595,36 @@
</xpath>
</template>
<template id="products_attributes" inherit_option_id="website_sale.products" name="Product Filters and Attributes">
<template id="products_characteristics" inherit_id="website_sale.products" inherit_option_id="website_sale.products" name="Product Characteristic's Filters" groups="product.group_product_characteristics">
<xpath expr="//div[@id='products_grid_before']" position="inside">
<form t-action="/shop/filters/" method="post" t-keep-query="category,search">
<ul class="nav nav-pills nav-stacked mt16">
<t t-set="attribute_ids" t-value="Ecommerce.get_attribute_ids()"/>
<t t-foreach="attribute_ids" t-as="attribute_id">
<t t-if="attribute_id.visible">
<li t-if="attribute_id.value_ids and attribute_id.type == 'distinct'">
<div t-field="attribute_id.name"/>
<t t-set="characteristic_ids" t-value="Ecommerce.get_characteristic_ids()"/>
<t t-foreach="characteristic_ids" t-as="characteristic_id">
<t t-if="characteristic_id.visible">
<li t-if="characteristic_id.value_ids and characteristic_id.type == 'distinct'">
<div t-field="characteristic_id.name"/>
<ul class="nav nav-pills nav-stacked">
<t t-foreach="attribute_id.value_ids" t-as="value_id">
<li t-att-class="Ecommerce.has_search_filter(attribute_id.id, value_id.id) and 'active' or ''">
<t t-foreach="characteristic_id.value_ids" t-as="value_id">
<li t-att-class="Ecommerce.has_search_filter(characteristic_id.id, value_id.id) and 'active' or ''">
<label style="margin: 0 20px;">
<input type="checkbox" t-att-name="'att-%s-%s' % (attribute_id.id, value_id.id)"
t-att-checked="Ecommerce.has_search_filter(attribute_id.id, value_id.id) and 'checked' or ''"/>
<input type="checkbox" t-att-name="'att-%s-%s' % (characteristic_id.id, value_id.id)"
t-att-checked="Ecommerce.has_search_filter(characteristic_id.id, value_id.id) and 'checked' or ''"/>
<span style="font-weight: normal" t-field="value_id.name"/>
</label>
</li>
</t>
</ul>
</li>
<li t-if="attribute_id.type == 'float' and attribute_id.float_min != attribute_id.float_max">
<div t-field="attribute_id.name"/>
<t t-set="attribute" t-value="Ecommerce.has_search_filter(attribute_id.id)"/>
<li t-if="characteristic_id.type == 'float' and characteristic_id.float_min != characteristic_id.float_max">
<div t-field="characteristic_id.name"/>
<t t-set="characteristic" t-value="Ecommerce.has_search_filter(characteristic_id.id)"/>
<div style="margin: 0 20px;" class="js_slider"
t-att-data-id="attribute_id.id"
t-att-data-value-min="attribute and attribute[1][0] or attribute_id.float_min"
t-att-data-value-max="attribute and attribute[1][1] or attribute_id.float_max"
t-att-data-min="attribute_id.float_min"
t-att-data-max="attribute_id.float_max"></div>
t-att-data-id="characteristic_id.id"
t-att-data-value-min="characteristic and characteristic[1][0] or characteristic_id.float_min"
t-att-data-value-max="characteristic and characteristic[1][1] or characteristic_id.float_max"
t-att-data-min="characteristic_id.float_min"
t-att-data-max="characteristic_id.float_max"></div>
</li>
</t>
</t>
@ -733,112 +733,110 @@
<a t-if="not partner" t-attf-href="/web#action=redirect&amp;url=#{ request.httprequest.url }">sign in</a>
</small>
</h3>
<div class="row">
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Your Name</label>
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name')"/>
</div>
<div t-attf-class="form-group #{error.get('company') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="company" style="font-weight: normal">Your Company</label>
<input type="text" name="company" class="form-control" t-att-value="checkout.get('company')"/>
</div>
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Email</label>
<input type="email" name="email" class="form-control" t-att-value="checkout.get('email')"/>
</div>
<div t-attf-class="form-group #{ error.get('phone') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="phone">Phone</label>
<input type="tel" name="phone" class="form-control" t-att-value="checkout.get('phone')"/>
</div>
<div t-attf-class="form-group #{error.get('street') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="street">Street</label>
<input type="text" name="street" class="form-control" t-att-value="checkout.get('street')"/>
</div>
<div class="clearfix"/>
<div t-attf-class="form-group #{error.get('city') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="city">City</label>
<input type="text" name="city" class="form-control" t-att-value="checkout.get('city')"/>
</div>
<div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="zip">Zip / Postal Code</label>
<input type="text" name="zip" class="form-control" t-att-value="checkout.get('zip')"/>
</div>
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="state_id" style="font-weight: normal">State / Province</label>
<select name="state_id" class="form-control">
<option value="">select...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Country</label>
<select name="country_id" class="form-control">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
<div class="clearfix"/>
<div class="form-group col-lg-6">
<label>
<input t-if="not shipping" type="checkbox" name="shipping_different"/>
<input t-if="shipping" type="checkbox" name="shipping_different" checked="1"/>
Ship to a different address
</label>
</div>
<div class="row">
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Your Name</label>
<input type="text" name="name" class="form-control" t-att-value="checkout.get('name')"/>
</div>
<div t-attf-class="form-group #{error.get('company') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="company" style="font-weight: normal">Your Company</label>
<input type="text" name="company" class="form-control" t-att-value="checkout.get('company')"/>
</div>
<div t-attf-class="form-group #{error.get('email') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Email</label>
<input type="email" name="email" class="form-control" t-att-value="checkout.get('email')"/>
</div>
<div t-attf-class="form-group #{error.get('phone') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="phone">Phone</label>
<input type="tel" name="phone" class="form-control" t-att-value="checkout.get('phone')"/>
</div>
<div class="js_shipping row mb16" t-att-style="not shipping and 'display:none' or ''">
<h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3>
<div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Name (Shipping)</label>
<input type="text" name="shipping_name" class="form-control" t-att-value="checkout.get('shipping_name', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_phone') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Phone</label>
<input type="tel" name="shipping_phone" class="form-control" t-att-value="checkout.get('shipping_phone', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_street') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Street</label>
<input type="text" name="shipping_street" class="form-control" t-att-value="checkout.get('shipping_street', '')"/>
</div>
<div class="clearfix"/>
<div t-attf-class="form-group #{error.get('shipping_city') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">City</label>
<input type="text" name="shipping_city" class="form-control" t-att-value="checkout.get('shipping_city', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_zip') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Zip / Postal Code</label>
<input type="text" name="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name" style="font-weight: normal">State / Province</label>
<select name="shipping_state_id" class="form-control">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('shipping_state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('shipping_country_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Country</label>
<select name="shipping_country_id" class="form-control">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('shipping_country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('street') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="street">Street</label>
<input type="text" name="street" class="form-control" t-att-value="checkout.get('street')"/>
</div>
<button type="submit" class="btn btn-default btn-primary pull-right mb32">Confirm <span class="fa fa-long-arrow-right"/></button>
<div class="clearfix"/>
<div t-attf-class="form-group #{error.get('city') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="city">City</label>
<input type="text" name="city" class="form-control" t-att-value="checkout.get('city')"/>
</div>
<div t-attf-class="form-group #{error.get('zip') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="zip">Zip / Postal Code</label>
<input type="text" name="zip" class="form-control" t-att-value="checkout.get('zip')"/>
</div>
<div t-attf-class="form-group #{error.get('state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="state_id" style="font-weight: normal">State / Province</label>
<select name="state_id" class="form-control">
<option value="">select...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('country_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Country</label>
<select name="country_id" class="form-control">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
<div class="clearfix"/>
<div class="form-group col-lg-6" groups="sale.group_delivery_invoice_address">
<label>
<input type="checkbox" name="shipping_different" t-att-checked="shipping"/>
Ship to a different address
</label>
</div>
</div>
<div class="js_shipping row mb16" t-att-style="not shipping and 'display:none' or ''" groups="sale.group_delivery_invoice_address">
<h3 class="oe_shipping col-lg-12 mt16">Shipping Information</h3>
<div t-attf-class="form-group #{error.get('shipping_name') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Name (Shipping)</label>
<input type="text" name="shipping_name" class="form-control" t-att-value="checkout.get('shipping_name', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_phone') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Phone</label>
<input type="tel" name="shipping_phone" class="form-control" t-att-value="checkout.get('shipping_phone', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_street') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Street</label>
<input type="text" name="shipping_street" class="form-control" t-att-value="checkout.get('shipping_street', '')"/>
</div>
<div class="clearfix"/>
<div t-attf-class="form-group #{error.get('shipping_city') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">City</label>
<input type="text" name="shipping_city" class="form-control" t-att-value="checkout.get('shipping_city', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_zip') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Zip / Postal Code</label>
<input type="text" name="shipping_zip" class="form-control" t-att-value="checkout.get('shipping_zip', '')"/>
</div>
<div t-attf-class="form-group #{error.get('shipping_state_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name" style="font-weight: normal">State / Province</label>
<select name="shipping_state_id" class="form-control">
<option value="">State / Province...</option>
<t t-foreach="states or []" t-as="state">
<option t-att-value="state.id" t-att-selected="state.id == checkout.get('shipping_state_id')"><t t-esc="state.name"/></option>
</t>
</select>
</div>
<div t-attf-class="form-group #{error.get('shipping_country_id') and 'has-error' or ''} col-lg-6">
<label class="control-label" for="contact_name">Country</label>
<select name="shipping_country_id" class="form-control">
<option value="">Country...</option>
<t t-foreach="countries or []" t-as="country">
<option t-att-value="country.id" t-att-selected="country.id == checkout.get('shipping_country_id')"><t t-esc="country.name"/></option>
</t>
</select>
</div>
</div>
<button type="submit" class="btn btn-default btn-primary pull-right mb32">Confirm <span class="fa fa-long-arrow-right"/></button>
</div>
<div class="col-lg-offset-1 col-lg-3 text-muted">
<h3 class="page-header mt16">Your Order <small><a href="/shop/mycart"><span class="fa fa-arrow-right"/> change</a></small></h3>
@ -962,19 +960,19 @@
<div>
<a href="/shop/checkout"><span class="fa fa-arrow-right"/> Change Address</a>
</div>
<h4 class="mt32">Ship To:</h4>
<t t-if="website_sale_order.partner_shipping_id and website_sale_order.partner_shipping_id.id != website_sale_order.partner_invoice_id.id">
<div t-field="order.partner_shipping_id" t-field-options='{
"widget": "contact",
"fields": ["address", "name", "phone"]
}'/>
<t groups="sale.group_delivery_invoice_address">
<h4 class="mt32">Ship To:</h4>
<t t-if="website_sale_order.partner_shipping_id and website_sale_order.partner_shipping_id.id != website_sale_order.partner_invoice_id.id">
<div t-field="order.partner_shipping_id" t-field-options='{
"widget": "contact",
"fields": ["address", "name", "phone"]
}'/>
</t>
<address t-if="website_sale_order.partner_shipping_id.id == website_sale_order.partner_invoice_id.id">Ship to the same address</address>
<div class="mb32">
<a href="/shop/checkout"><span class="fa fa-arrow-right"/> Change Address</a>
</div>
</t>
<address t-if="website_sale_order.partner_shipping_id.id == website_sale_order.partner_invoice_id.id">Ship to the same address</address>
<div class="mb32">
<a href="/shop/checkout"><span class="fa fa-arrow-right"/> Change Address</a>
</div>
</div>
</div>
@ -1036,14 +1034,16 @@
"widget": "contact",
"fields": ["address", "name", "phone", "email"]
}'/>
<h4 class="mt32">Ship To:</h4>
<t t-if="order.partner_shipping_id and order.partner_shipping_id.id != order.partner_invoice_id.id">
<div t-field="order.partner_shipping_id" t-field-options='{
"widget": "contact",
"fields": ["address", "name", "phone"]
}'/>
<t groups="sale.group_delivery_invoice_address">
<h4 class="mt32">Ship To:</h4>
<t t-if="order.partner_shipping_id and order.partner_shipping_id.id != order.partner_invoice_id.id">
<div t-field="order.partner_shipping_id" t-field-options='{
"widget": "contact",
"fields": ["address", "name", "phone"]
}'/>
</t>
<address t-if="order.partner_shipping_id.id == order.partner_invoice_id.id">Ship to the same address</address>
</t>
<address t-if="order.partner_shipping_id.id == order.partner_invoice_id.id">Ship to the same address</address>
</div>
</div>

View File

@ -2,6 +2,19 @@
<openerp>
<data>
<record id="view_sales_config_website_sale" model="ir.ui.view">
<field name="name">sale settings</field>
<field name="model">sale.config.settings</field>
<field name="inherit_id" ref="sale.view_sales_config"/>
<field name="arch" type="xml">
<xpath expr="//group[@name='Product Features']/div" position="inside">
<div>
<field name="group_product_characteristics" class="oe_inline"/>
<label for="group_product_characteristics"/>
</div>
</xpath>
</field>
</record>
<record id="product_normal_form_view" model="ir.ui.view">
<field name="name">product.normal.form.inherit</field>
@ -49,15 +62,15 @@
<group colspan="4" string="Website Options">
<field name="suggested_product_ids" widget="many2many_tags"/>
<field name="website_style_ids" widget="many2many_tags"/>
<field colspan="4" name="website_attribute_ids" nolabel="1">
<tree string="Product Attributes" editable="bottom">
<field name="attribute_id" on_change="onchange_attribute_id(attribute_id)"/>
<field colspan="4" name="website_characteristic_ids" nolabel="1" groups="product.group_product_characteristics">
<tree string="Product Characteristics" editable="bottom">
<field name="characteristic_id" on_change="onchange_characteristic_id(characteristic_id)"/>
<field name="type" invisible="1"/>
<field name="value" attrs="{'required': [('type','=','float')]}"/>
<field name="value_id"
attrs="{'required': [('type','=','distinct')]}"
context="{'default_attribute_id': attribute_id}"
domain="[('attribute_id', '=', attribute_id)]"/>
context="{'default_characteristic_id': characteristic_id}"
domain="[('characteristic_id', '=', characteristic_id)]"/>
</tree>
</field>
</group>
@ -66,11 +79,11 @@
</field>
</record>
<record model="ir.ui.view" id="view_product_attribute_form">
<field name="name">product.attribute.form</field>
<field name="model">product.attribute</field>
<record model="ir.ui.view" id="view_product_characteristic_form">
<field name="name">product.characteristic.form</field>
<field name="model">product.characteristic</field>
<field name="arch" type="xml">
<form string="Product Attributes" version="7.0">
<form string="Product Characteristics" version="7.0">
<group>
<field name="name"/>
<field name="type"/>