[MERGE] from parent

bzr revid: xmo@openerp.com-20130912141026-mmmyg91nwlzccr0g
This commit is contained in:
Xavier Morel
2013-09-12 16:10:26 +02:00
40 changed files with 1973 additions and 910 deletions
+1
View File
@@ -16,5 +16,6 @@ OpenERP Website CMS
'views/themes.xml',
'views/res_config.xml',
'website_data.xml',
'website_view.xml',
],
}
+14 -12
View File
@@ -57,8 +57,7 @@ class Website(openerp.addons.web.controllers.main.Home):
imd = request.registry['ir.model.data']
view = request.registry['ir.ui.view']
view_model, view_id = imd.get_object_reference(
request.cr, request.uid, 'website', 'default_page',
context=request.context)
request.cr, request.uid, 'website', 'default_page')
newview_id = view.copy(
request.cr, request.uid, view_id, context=request.context)
newview = view.browse(
@@ -92,7 +91,7 @@ class Website(openerp.addons.web.controllers.main.Home):
view = request.registry['ir.ui.view']
view_model, view_option_id = imd.get_object_reference(
request.cr, request.uid, 'website', 'theme', context=request.context)
request.cr, request.uid, 'website', 'theme')
views = view.search(
request.cr, request.uid, [('inherit_id', '=', view_option_id)],
context=request.context)
@@ -102,19 +101,21 @@ class Website(openerp.addons.web.controllers.main.Home):
if theme_id:
module, xml_id = theme_id.split('.')
view_model, view_id = imd.get_object_reference(
request.cr, request.uid, module, xml_id, context=request.context)
request.cr, request.uid, module, xml_id)
view.write(request.cr, request.uid, [view_id],
{'inherit_id': view_option_id}, context=request.context)
return request.webcontext.render('website.themes', {'theme_changed': True})
return request.website.render('website.themes', {'theme_changed': True})
@website.route('/page/<path:path>', type='http', auth="admin")
def page(self, path, **kwargs):
request.webcontext['path'] = path
values = {
'path': path,
}
try:
html = request.webcontext.render(path)
html = request.website.render(path, values)
except ValueError:
html = request.webcontext.render('website.404')
html = request.website.render('website.404', values)
return html
@website.route('/website/customize_template_toggle', type='json', auth='admin') # FIXME: auth
@@ -132,20 +133,21 @@ class Website(openerp.addons.web.controllers.main.Home):
return True
@website.route('/website/customize_template_get', type='json', auth='admin') # FIXME: auth
def customize_template_get(self, xml_id):
def customize_template_get(self, xml_id, optional=True):
imd = request.registry['ir.model.data']
view_model, view_theme_id = imd.get_object_reference(
request.cr, request.uid, 'website', 'theme', context=request.context)
request.cr, request.uid, 'website', 'theme')
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.inherit_option_id and v.inherit_option_id.id != view_theme_id:
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({
'name': v.inherit_option_id.name,
'id': v.id,
'header': True,
'active': False
})
@@ -267,6 +269,6 @@ class Website(openerp.addons.web.controllers.main.Home):
@website.route(['/website/kanban/'], type='http', auth="public")
def kanban(self, **post):
return request.registry['website'].kanban_col(**post)
return request.website.kanban_col(**post)
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
+150 -24
View File
@@ -82,6 +82,10 @@
}
/* ---- EDITOR BAR ---- */
.modal .tab-content {
padding-top: 5px;
}
table.editorbar-panel {
cursor: pointer;
width: 100%;
@@ -90,6 +94,10 @@ table.editorbar-panel td.selected {
background-color: #b1c9d9;
}
.modal .image-preview-container, .modal .image-preview {
margin-bottom: 0.5em;
}
/* ---- RTE ---- */
.oe_editable .btn {
-webkit-user-select: auto;
@@ -100,7 +108,7 @@ table.editorbar-panel td.selected {
}
/* ---- SNIPPET EDITOR ---- */
.oe_snippets {
#oe_snippets {
position: fixed;
left: 0px;
right: 0px;
@@ -112,6 +120,16 @@ table.editorbar-panel td.selected {
overflow-y: auto;
z-index: 100;
}
#oe_snippets .nav-pills {
padding: 3px 8px;
background: #444444;
}
#oe_snippets .nav-pills > li > a {
padding: 2px 10px !important;
}
#oe_snippets .pill-content {
height: 140px;
}
.oe_snippet {
display: inline-block;
@@ -137,6 +155,7 @@ table.editorbar-panel td.selected {
line-height: 120px;
color: white;
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95);
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset;
}
.oe_snippet .oe_snippet_body {
display: none;
@@ -144,6 +163,9 @@ table.editorbar-panel td.selected {
.oe_snippet > * {
pointer-events: none;
}
.oe_snippet > :not(.oe_snippet_body):not(.oe_snippet_thumbnail) {
display: none !important;
}
.oe_snippet > *:first-child:not(.oe_snippet_thumbnail) {
display: block;
-webkit-transform-origin-x: 5px;
@@ -195,64 +217,124 @@ table.editorbar-panel td.selected {
}
.oe_drop_zone.oe_hover {
background: rgba(0, 255, 133, 0.22);
z-index: 99;
z-index: 97;
}
/* ---- SNIPPET MANIPULATOR ---- */
.oe_snippet_manipulator {
.oe_overlay {
display: block;
position: absolute;
background: rgba(153, 0, 255, 0.1);
background: transparent;
border-radius: 3px;
border: solid 1px rgba(153, 0, 255, 0.5);
opacity: 0;
transition: opacity 100ms linear;
box-sizing: border-box;
pointer-events: none;
}
.oe_snippet_manipulator > .oe_handle {
display: none;
.oe_overlay .oe_handle {
display: none !important;
}
.oe_snippet_manipulator:hover, .oe_snippet_manipulator.oe_hover {
.oe_overlay.oe_hover {
opacity: 1;
cursor: pointer;
}
.oe_snippet_manipulator:hover > .oe_handle, .oe_snippet_manipulator.oe_hover > .oe_handle {
.oe_overlay.oe_selected, .oe_overlay.oe_active {
opacity: 1;
background: transparent;
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;
}
.oe_overlay.oe_selected {
border-color: rgba(0, 153, 255, 0.5);
}
.oe_overlay.oe_active {
border-color: rgba(153, 0, 255, 0.5);
}
.oe_overlay.oe_active .oe_handle {
display: block !important;
pointer-events: auto;
}
.oe_overlay .oe_overlay_options {
display: none;
z-index: 99;
}
.oe_overlay .oe_overlay_options .oe_option {
pointer-events: auto;
position: absolute;
}
.oe_overlay .oe_overlay_options .oe_option.n {
top: 0px;
}
.oe_overlay .oe_overlay_options .oe_option.e {
right: 0px;
}
.oe_overlay .oe_overlay_options .oe_option.s {
bottom: 0px;
}
.oe_overlay .oe_overlay_options .oe_option.w {
left: 0px;
}
.oe_overlay.oe_active .oe_overlay_options {
display: block;
}
.oe_handle {
pointer-events: auto;
position: absolute;
top: 50%;
left: 50%;
display: block;
background: white;
border: solid 1px rgba(153, 0, 255, 0.5);
box-sizing: border-box;
border-radius: 2px;
width: 16px;
height: 16px;
margin: -8px;
cursor: move;
-webkit-transition: background 100ms linear;
}
.oe_handle:hover {
background: #9900ff;
width: 8px;
height: 8px;
margin: -4px;
}
.oe_handle.nw, .oe_handle.n, .oe_handle.ne {
.oe_handle.n {
left: 2px;
width: 100%;
top: 0px;
cursor: s-resize;
}
.oe_handle.ne, .oe_handle.e, .oe_handle.se {
.oe_handle.e {
left: auto;
top: 2px;
height: 100%;
right: 0px;
cursor: w-resize;
}
.oe_handle.sw, .oe_handle.s, .oe_handle.se {
.oe_handle.s {
top: auto;
left: 2px;
width: 100%;
bottom: 0px;
cursor: n-resize;
}
.oe_handle.nw, .oe_handle.w, .oe_handle.sw {
.oe_handle.w {
top: 2px;
height: 100%;
left: 0px;
cursor: e-resize;
}
.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;
}
/* ---- MOBILE PREVIEW ---- */
@@ -312,3 +394,47 @@ table.editorbar-panel td.selected {
.oe_seo_configuration .oe_seo_suggestion {
cursor: pointer;
}
/* ---- ACE EDITOR ---- */
.oe_ace_view_editor {
transition: all 0.2s ease-in;
opacity: 0.3;
position: fixed;
top: 51px;
right: 0;
z-index: 1000;
height: 100%;
}
.oe_ace_view_editor .oe_ace_view_editor_title {
width: 100%;
padding-top: 4px;
padding-left: 4px;
height: 40px;
background: #2f3129;
}
.oe_ace_view_editor .oe_ace_view_editor_title .oe_view_list {
width: 50%;
height: 32px;
}
.oe_ace_view_editor .oe_ace_view_editor_title .btn {
height: 32px;
padding: 0 4px 0 4px;
}
.oe_ace_view_editor .ace_editor {
position: absolute;
top: 40px;
right: 0;
bottom: 51px;
left: 0;
width: 720px;
}
.oe_ace_view_editor:hover {
opacity: 1;
}
.oe_ace_view_editor.oe_ace_open {
width: 720px;
}
.oe_ace_view_editor.oe_ace_closed {
width: 0;
opacity: 0;
}
+128 -24
View File
@@ -74,12 +74,18 @@
/* ---- EDITOR BAR ---- */
.modal .tab-content
padding-top: 5px
table.editorbar-panel
cursor: pointer
width: 100%
td.selected
background-color: #b1c9d9
.modal .image-preview-container, .modal .image-preview
margin-bottom: 0.5em
/* ---- RTE ---- */
// bootstrap makes .btn elements unselectable -> RTE double-click can't know
@@ -93,7 +99,7 @@ table.editorbar-panel
/* ---- SNIPPET EDITOR ---- */
.oe_snippets
#oe_snippets
position: fixed
left: 0px
right: 0px
@@ -104,6 +110,13 @@ table.editorbar-panel
box-shadow: 0px 10px 10px -10px black inset
overflow-y: auto
z-index: 100
.nav-pills
padding: 3px 8px
background: #444444
> li > a
padding: 2px 10px !important
.pill-content
height: 140px
.oe_snippet
display: inline-block
@@ -129,11 +142,14 @@ table.editorbar-panel
line-height: 120px
color: white
text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.95)
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.07) inset
.oe_snippet_body
display: none
& > *
pointer-events: none
& > :not(.oe_snippet_body):not(.oe_snippet_thumbnail)
display: none !important
& > *:first-child:not(.oe_snippet_thumbnail)
display: block
@@ -179,52 +195,98 @@ table.editorbar-panel
border-radius: 3px
&.oe_hover
background: rgba(0, 255, 133, 0.22)
z-index: 99
z-index: 97
/* ---- SNIPPET MANIPULATOR ---- */
.oe_snippet_manipulator
.oe_overlay
display: block
position: absolute
background: rgba(153, 0, 255, 0.1)
background: transparent //rgba(153, 0, 255, 0.05)
border-radius: 3px
border: solid 1px rgba(153, 0, 255, 0.5)
opacity: 0
transition: opacity 100ms linear
& > .oe_handle
display: none
&:hover,&.oe_hover
box-sizing: border-box
pointer-events: none
.oe_handle
display: none !important
&.oe_hover
opacity: 1
& > .oe_handle
display: block
cursor: pointer
&.oe_selected, &.oe_active
opacity: 1
background: transparent
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
&.oe_selected
border-color: rgba(0, 153, 255, 0.5)
&.oe_active
border-color: rgba(153, 0, 255, 0.5)
.oe_handle
display: block !important
pointer-events: auto
.oe_overlay_options
display: none
z-index: 99
.oe_option
pointer-events: auto
position: absolute
&.n
top: 0px
&.e
right: 0px
&.s
bottom: 0px
&.w
left: 0px
&.oe_active .oe_overlay_options
display: block
.oe_handle
pointer-events: auto
position: absolute
top: 50%
left: 50%
display: block
background: rgba(255, 255, 255, 1)
border: solid 1px rgba(153, 0, 255, 0.5)
box-sizing: border-box
border-radius: 2px
width: 16px
height: 16px
margin: -8px
cursor: move
-webkit-transition: background 100ms linear
&:hover
background: rgb(153, 0, 255)
width: 8px
height: 8px
margin: -4px
.oe_handle.nw,.oe_handle.n,.oe_handle.ne
.oe_handle.n
left: 2px
width: 100%
top: 0px
.oe_handle.ne,.oe_handle.e,.oe_handle.se
cursor: s-resize
.oe_handle.e
left: auto
top: 2px
height: 100%
right: 0px
.oe_handle.sw,.oe_handle.s,.oe_handle.se
cursor: w-resize
.oe_handle.s
top: auto
left: 2px
width: 100%
bottom: 0px
.oe_handle.nw,.oe_handle.w,.oe_handle.sw
cursor: n-resize
.oe_handle.w
top: 2px
height: 100%
left: 0px
cursor: e-resize
.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
/* ---- MOBILE PREVIEW ---- */
@@ -280,3 +342,45 @@ $remove_color: $icon_close
color: $remove_color
.oe_seo_suggestion
cursor: pointer
/* ---- ACE EDITOR ---- */
$ace_width: 720px
$editorbar_height: 40px
// TODO Fix => might break with themes
$navbar_height: 51px
.oe_ace_view_editor
transition: all 0.2s ease-in
opacity: 0.3
position: fixed
top: $navbar_height
right: 0
z-index: 1000
height: 100%
.oe_ace_view_editor_title
width: 100%
padding-top: 4px
padding-left: 4px
height: $editorbar_height
background: #2F3129
.oe_view_list
width: 50%
height: $editorbar_height - 8px
.btn
height: $editorbar_height - 8px
padding: 0 4px 0 4px
.ace_editor
position: absolute
top: $editorbar_height
right: 0
bottom: $navbar_height
left: 0
width: $ace_width
&:hover
opacity: 1
&.oe_ace_open
width: $ace_width
&.oe_ace_closed
width: 0
opacity: 0
+33 -2
View File
@@ -88,7 +88,7 @@
padding: 8px;
}
.oe_snippet_editor .oe_snippet.oe_selected{
.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);
@@ -134,7 +134,7 @@
box-shadow: 0px 1px 3px rgb(90,90,90) inset;
border: 0px;
}
.oe_snippet_editor .oe_snippet.oe_new.oe_selected{
.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.oe_new > *{
@@ -176,3 +176,34 @@
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;
}
#website-top-edit li.oe_snippet_editorbar > * {
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;
}
[data-snippet-id] {
min-height: 10px;
min-width: 10px;
}
+3 -4
View File
@@ -127,7 +127,7 @@ footer {
margin-bottom: 0px;
}
#myCarousel .item {
.carousel .item {
color: white;
}
@@ -193,6 +193,8 @@ a[data-publish][data-publish='on']:hover .css_published {
[data-publish]:not(a) {
position: relative;
overflow: visible;
/*&:hover > [data-publish] */
/* display: block */
}
[data-publish]:not(a) > [data-publish] {
position: absolute;
@@ -200,6 +202,3 @@ a[data-publish][data-publish='on']:hover .css_published {
top: -10px;
display: none;
}
[data-publish]:not(a):hover > [data-publish] {
display: block;
}
+3 -3
View File
@@ -95,7 +95,7 @@ footer
// .nav > li a
// display: block
#myCarousel .item
.carousel .item
color: white
/* ---- HOMEPAGE THEME CUSTOMIZATION ---- */
@@ -156,5 +156,5 @@ a[data-publish]
right: -6px
top: -10px
display: none
&:hover > [data-publish]
display: block
/*&:hover > [data-publish]*/
/* display: block*/
+157
View File
@@ -0,0 +1,157 @@
(function () {
'use strict';
var globalEditor;
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.ace.xml');
website.EditorBar.include({
events: _.extend({}, website.EditorBar.prototype.events, {
'click a[data-action=ace]': 'launchAce',
}),
launchAce: function () {
if (globalEditor) {
globalEditor.open();
} else {
globalEditor = new website.ace.ViewEditor(this);
globalEditor.appendTo($(document.body));
}
},
});
website.ace = {};
website.ace.XmlDocument = openerp.Class.extend({
init: function (text) {
this.xml = text;
},
isWellFormed: function () {
try {
if (document.implementation.createDocument) {
var dom = new DOMParser().parseFromString(this.xml, "text/xml");
return dom.getElementsByTagName("parsererror").length === 0;
} else if (window.ActiveXObject) {
// TODO test in IE
var msDom = new ActiveXObject("Microsoft.XMLDOM");
msDom.async = false;
return !msDom.loadXML(this.xml);
} else {
throw Error("Not implemented");
}
} catch(exception) {
console.log(exception);
}
},
format: function () {
return vkbeautify.xml(this.xml, 4);
},
});
website.ace.ViewOption = openerp.Widget.extend({
template: 'website.ace_view_option',
init: function (parent, options) {
this.view_id = options.id;
this.view_name = options.name;
this._super(parent);
},
});
website.ace.ViewEditor = openerp.Widget.extend({
template: 'website.ace_view_editor',
events: {
'change #ace-view-list': 'displayView',
'click button[data-action=save]': 'saveView',
'click button[data-action=format]': 'formatXml',
'click button[data-action=close]': 'close',
},
start: function () {
var self = this;
var viewId = $(document.documentElement).data('view-xmlid');
openerp.jsonRpc('/website/customize_template_get', 'call', {
'xml_id': viewId,
'optional': false,
}).then(function (views) {
self.loadViewList.call(self, views);
});
this.$el.hover();
},
selectedViewId: function () {
return parseInt(this.$('#ace-view-list').val(), 10);
},
loadViewList: function (views) {
var activeViews = _.filter(views, function (view) {
return view.active;
});
var $viewList = this.$('#ace-view-list');
_.each(activeViews, function (view) {
if (view.id) {
new website.ace.ViewOption(this, view).appendTo($viewList);
}
});
var editor = ace.edit(this.$('#ace-view-editor')[0]);
editor.setTheme("ace/theme/monokai");
this.aceEditor = editor;
this.open();
},
displayView: function () {
var editor = this.aceEditor;
openerp.jsonRpc('/web/dataset/call', 'call', {
model: 'ir.ui.view',
method: 'read',
args: [[this.selectedViewId()], ['arch'], website.get_context()],
}).then(function(result) {
if (result && result.length > 0) {
var xml = new website.ace.XmlDocument(result[0].arch)
var editingSession = new ace.EditSession(xml.xml);
editingSession.setMode("ace/mode/xml");
editingSession.setUndoManager(new ace.UndoManager());
editor.setSession(editingSession);
} else {
throw Error("Could not load view XML");
}
});
},
formatXml: function () {
var xml = new website.ace.XmlDocument(this.aceEditor.getValue());
this.aceEditor.setValue(xml.format());
},
saveView: function () {
var self = this;
var xml = new website.ace.XmlDocument(this.aceEditor.getValue());
if (xml.isWellFormed()) {
openerp.jsonRpc('/web/dataset/call', 'call', {
model: 'ir.ui.view',
method: 'write',
args: [[this.selectedViewId()], { 'arch': xml.xml }, website.get_context()],
}).then(function(result) {
self.reloadPage();
}).fail(function (error) {
self.displayError(error);
});
} else {
self.displayError();
}
},
reloadPage: function () {
// TODO Reload { header + div#wrap + footer } only
window.location.reload();
},
displayError: function (error) {
// TODO Improve feedback (e.g. update 'Save' button + tooltip)
alert("Malformed XML document");
},
open: function () {
this.$el.removeClass('oe_ace_closed').addClass('oe_ace_open');
this.displayView();
},
close: function () {
var self = this;
this.$el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () {
globalEditor = null;
self.destroy.call(self);
}).removeClass('oe_ace_open').addClass('oe_ace_closed');
},
});
})();
+70 -56
View File
@@ -146,7 +146,11 @@
var editor = new website.EditorBar();
var $body = $(document.body);
editor.prependTo($body);
editor.prependTo($body).then(function () {
if (location.search.indexOf("unable_editor") >= 0) {
editor.edit();
}
});
$body.css('padding-top', '50px'); // Not working properly: editor.$el.outerHeight());
};
/* ----- TOP EDITOR BAR FOR ADMIN ---- */
@@ -176,10 +180,11 @@
});
// Adding Static Menus
menu.append('<li class="divider"></li><li><a href="/page/website.themes">Change Theme</a></li>');
menu.append('<li class="divider"></li><li><a data-action="ace" href="#">Advanced view editor</a></li>');
}
);
});
menu.on('click', 'a', function (event) {
menu.on('click', 'a[data-action!=ace]', function (event) {
var view_id = $(event.currentTarget).data('view-id');
openerp.jsonRpc('/website/customize_template_toggle', 'call', {
'view_id': view_id
@@ -251,7 +256,7 @@
});
}).value();
return $.when.apply(null, defs).then(function () {
window.location.reload();
window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
});
},
/**
@@ -268,11 +273,11 @@
return openerp.jsonRpc('/web/dataset/call', 'call', {
model: 'ir.ui.view',
method: 'save',
args: [element.data('oe-id'), data, element.data('oe-xpath')],
args: [element.data('oe-id'), data, element.data('oe-xpath'), website.get_context()],
});
},
cancel: function () {
window.location.reload();
window.location.href = window.location.href.replace(/unable_editor(=[^&]*)?|#.*/g, '');
},
});
@@ -284,6 +289,11 @@
// editor.ui.items -> possible commands &al
// editor.applyStyle(new CKEDITOR.style({element: "span",styles: {color: "#(color)"},overrides: [{element: "font",attributes: {color: null}}]}, {color: '#ff0000'}));
init: function (EditorBar) {
this.EditorBar = EditorBar;
this._super.apply(this, arguments);
},
start_edition: function ($elements) {
var self = this;
$elements
@@ -292,6 +302,7 @@
var $node = $(node);
var editor = CKEDITOR.inline(this, self._config());
editor.on('instanceReady', function () {
self.trigger('instanceReady');
observer.observe(node, OBSERVER_CONFIG);
});
$node.one('content_changed', function () {
@@ -337,8 +348,11 @@
extraPlugins: 'sharedspace,customdialogs,tablebutton,oeref',
// Place toolbar in controlled location
sharedSpaces: { top: 'oe_rte_toolbar' },
toolbar: [
{name: 'basicstyles', items: [
toolbar: [{
name: 'clipboard', items: [
"Undo"
]},{
name: 'basicstyles', items: [
"Bold", "Italic", "Underline", "Strike", "Subscript",
"Superscript", "TextColor", "BGColor", "RemoveFormat"
]},{
@@ -402,15 +416,11 @@
website.editor.LinkDialog = website.editor.Dialog.extend({
template: 'website.editor.dialog.link',
events: _.extend({}, website.editor.Dialog.prototype.events, {
'change .url-source': function (e) { this.changed($(e.target)); },
'click div.existing a': 'select_page',
}),
init: function (editor) {
this._super(editor);
// url -> name mapping for existing pages
this.pages = Object.create(null);
// name -> url mapping for the same
this.pages_by_name = Object.create(null);
},
start: function () {
var element;
@@ -471,24 +481,24 @@
},
save: function () {
var self = this, _super = this._super.bind(this);
var $e = this.$('.url-source').filter(function () { return !!this.value; });
var $active_tab = this.$('.tab-pane.active');
var $e = $active_tab.find('.url-source');
var val = $e.val(), done = $.when();
if ($e.hasClass('email-address')) {
if ($active_tab.is('#link-email')) {
this.make_link('mailto:' + val, false, val);
} else if ($e.hasClass('pages')) {
// ``val`` is the *name* of the page
var url = this.pages_by_name[val];
if (!url) {
// Create the page, get the URL back
done = $.get(_.str.sprintf(
'/pagenew/%s?noredirect', encodeURIComponent(val)))
.then(function (response) {
url = response;
});
}
} else if ($active_tab.is('#link-existing')) {
self.make_link(val, false, this.pages[val]);
} else if ($active_tab.is('#link-new')) {
// Create the page, get the URL back
done = $.get(_.str.sprintf(
'/pagenew/%s?noredirect', encodeURIComponent(val)))
.then(function (response) {
val = response;
});
done.then(function () {
self.make_link(url, false, val);
self.make_link(val, false);
});
} else {
this.make_link(val, this.$('input.window-new').prop('checked'));
@@ -502,36 +512,19 @@
var match, $control;
if (match = /(mailto):(.+)/.exec(href)) {
$control = this.$('input.email-address').val(match[2]);
$control = this.$('#link-email input').val(match[2]);
} else if(href in this.pages) {
$control = this.$('input.pages').val(this.pages[href]);
}
if (!$control) {
$control = this.$('input.url').val(href);
$control = this.$('#link-existing select').val(href);
} else {
$control = this.$('#link-external input:first').val(href);
}
this.changed($control);
var tab_name = $control.closest('.tab-pane').attr('id');
this.$('.nav a[href="#' + tab_name + '"]').tab('show');
this.$('input.window-new').prop(
'checked', this.element.getAttribute('target') === '_blank');
},
changed: function ($e) {
$e.closest('li.list-group-item').addClass('active')
.siblings().removeClass('active');
this.$('.url-source').not($e).val('');
},
/**
* Selected an existing page in dropdown
*/
select_page: function (e) {
e.preventDefault();
e.stopPropagation();
var $target = $(e.target);
this.$('input.pages').val($target.text()).change();
// No #dropdown('close'), and using #dropdown('toggle') sur
// #closest('.dropdown') makes the dropdown not work correctly
$target.closest('.open').removeClass('open')
},
/**
* CKEDITOR.plugins.link.getSelectedLink ignores the editor's root,
* if the editor is set directly on a link it will thus not work.
@@ -554,37 +547,50 @@
model: 'website',
method: 'list_pages',
args: [],
kwargs: {}
kwargs: {
context: website.get_context()
},
});
},
fill_pages: function (results) {
var self = this;
var $pages = this.$('div.existing ul').empty();
var pages = this.$('#link-existing-select')[0];
_(results).each(function (result) {
self.pages[result.url] = result.name;
self.pages_by_name[result.name] = result.url;
var $link = $('<a>').attr('href', result.url).text(result.name);
$('<li>').append($link).appendTo($pages);
pages.options[pages.options.length] =
new Option(result.name, result.url);
});
},
});
website.editor.ImageDialog = website.editor.Dialog.extend({
template: 'website.editor.dialog.image',
events: _.extend({}, website.editor.Dialog.prototype.events, {
'change .url-source': function (e) { this.changed($(e.target)); },
'click button.filepicker': function () {
this.$('input[type=file]').click();
},
'change input[type=file]': 'file_selection',
'change input.url': 'preview_image',
'change select.image-style': 'preview_image',
'click .existing-attachments a': 'select_existing',
}),
start: function () {
var selection = this.editor.getSelection();
var el = selection && selection.getSelectedElement();
this.element = null;
var $select = this.$('.image-style');
var $options = $select.children();
this.image_styles = $options.map(function () { return this.value; }).get();
if (el && el.is('img')) {
this.element = el;
_(this.image_styles).each(function (style) {
if (el.hasClass(style)) {
$select.val(style);
}
});
// set_image should follow setup of image style
this.set_image(el.getAttribute('src'));
}
@@ -594,6 +600,7 @@
},
save: function () {
var url = this.$('input.url').val();
var style = this.$('.image-style').val();
var element, editor = this.editor;
if (!(element = this.element)) {
element = editor.document.createElement('img');
@@ -607,7 +614,10 @@
}, 0);
}
element.setAttribute('src', url);
this._super();
$(element.$).removeClass(this.image_styles.join(' '));
if (style) { element.addClass(style); }
return this._super();
},
/**
@@ -645,7 +655,10 @@
var image = this.$('input.url').val();
if (!image) { return; }
this.$('img.image-preview').attr('src', image);
this.$('img.image-preview')
.attr('src', image)
.removeClass(this.image_styles.join(' '))
.addClass(this.$('select.image-style').val());
},
fetch_existing: function () {
@@ -658,6 +671,7 @@
fields: ['name'],
domain: [['res_model', '=', 'ir.ui.view']],
order: 'name',
context: website.get_context(),
}
});
},
+17 -39
View File
@@ -9,6 +9,13 @@
'/website/static/src/xml/website.xml'
];
website.get_context = function (dict) {
var html = document.documentElement;
return _.extend({
lang: html.getAttribute('lang').replace('-', '_')
}, dict);
};
/* ----- TEMPLATE LOADING ---- */
website.add_template = function(template) {
templates.push(template);
@@ -16,48 +23,19 @@
website.load_templates = function(templates) {
var def = $.Deferred();
var count = templates.length;
templates.forEach(function(t) {
openerp.qweb.add_template(t, function(err) {
if (err) {
def.reject();
} else {
count--;
if (count < 1) {
def.resolve();
var dones = _(templates).map(function (t) {
return new $.Deferred(function (d) {
openerp.qweb.add_template(t, function(err) {
if (err) {
d.reject(err);
} else {
d.resolve();
}
}
});
});
});
return def;
};
website.mutations = {
darken: function($el){
var $parent = $el.parent();
if($parent.hasClass('dark')){
$parent.replaceWith($el);
}else{
$el.replaceWith($("<div class='dark'></div>").append($el.clone()));
}
},
vomify: function($el){
var hue=0;
var beat = false;
var a = setInterval(function(){
$el.css({'-webkit-filter':'hue-rotate('+hue+'deg)'}); hue += 5;
}, 10);
setTimeout(function(){
clearInterval(a);
setInterval(function(){
var filter = 'hue-rotate('+hue+'deg)'+ (beat ? ' invert()' : '');
$(document.documentElement).css({'-webkit-filter': filter}); hue += 5;
if(hue % 35 === 0){
beat = !beat;
}
}, 10);
},5000);
$('<iframe width="1px" height="1px" src="http://www.youtube.com/embed/WY24YNsOefk?autoplay=1" frameborder="0"></iframe>').appendTo($el);
},
return $.when.apply(null, dones);
};
+68 -54
View File
@@ -27,7 +27,7 @@
},
headers: function (tag) {
return $('#wrap '+tag).map(function () {
return $(this).text();
return $(this).text();
});
},
images: function () {
@@ -70,11 +70,11 @@
perfect: 'success',
advised: 'primary',
used: 'warning',
new: 'default',
custom: 'default',
},
init: function (parent, options) {
this.keyword = options.keyword;
this.type = this.types[options.type || 'default'];
this.type = this.types[options.type] || 'default';
this._super(parent);
},
destroy: function () {
@@ -88,39 +88,33 @@
maxKeywords: 10,
keywords: function () {
var result = [];
this.$el.find('.js_seo_keyword').each(function () {
this.$('.js_seo_keyword').each(function () {
result.push($(this).data('keyword'));
});
return result;
},
suggestions: function () {
// TODO Refactor (Ugly)
return $('.js_seo_suggestion').map(function () {
return $(this).data('keyword');
});
},
isKeywordListFull: function () {
return this.keywords().length >= this.maxKeywords;
},
isExistingKeyword: function (word) {
return _.contains(this.keywords(), word);
},
add: function (candidate) {
add: function (candidate, suggested) {
var self = this;
// TODO Refine
var word = candidate ? candidate.replace(/[,;.:<>]+/g, " ").replace(/ +/g, " ").trim() : "";
if (word && !this.isKeywordListFull() && !this.isExistingKeyword(word)) {
var type = _.contains(this.suggestions(), word) ? 'advised' : 'new';
var keyword = new website.seo.Keyword(this, {
if (word && !self.isKeywordListFull() && !self.isExistingKeyword(word)) {
var type = suggested ? 'advised' : 'custom';
var keyword = new website.seo.Keyword(self, {
keyword: word,
type: type,
});
keyword.on('removed', null, function () {
self.trigger('list-not-full');
});
keyword.appendTo(this.$el);
keyword.appendTo(self.$el);
}
if (this.isKeywordListFull()) {
if (self.isKeywordListFull()) {
self.trigger('list-full');
}
},
@@ -148,6 +142,46 @@
},
});
website.seo.SuggestionList = openerp.Widget.extend({
template: 'website.seo_list',
init: function (parent, companyName) {
this.companyName = companyName;
this._super(parent);
},
start: function () {
var self = this;
self.$el.append("Loading...");
// cf. https://github.com/ddm/seo
// TODO Try with /recommend/
$.getJSON("http://seo.eu01.aws.af.cm/suggest/"+encodeURIComponent(self.companyName), function (list) {
self.$el.empty();
// TODO Improve algorithm + Ajust based on custom user keywords
var nameRegex = new RegExp(self.companyName, "gi");
var cleanList = _.map(list, function removeCompanyName (word) {
return word.replace(nameRegex, "").trim();
});
// TODO Order properly ?
cleanList.push(self.companyName);
_.each(_.uniq(cleanList), function (keyword) {
if (keyword) {
var suggestion = new website.seo.Suggestion(self, {
keyword: keyword
});
suggestion.on('selected', self, function () {
self.trigger('selected', keyword);
});
suggestion.appendTo(self.$el);
}
});
});
},
suggestions: function () {
return this.$('.js_seo_suggestion').map(function () {
return $(this).data('keyword');
});
},
});
website.seo.Image = openerp.Widget.extend({
template: 'website.seo_image',
init: function (parent, options) {
@@ -167,7 +201,7 @@
},
images: function () {
var result = [];
this.$el.find('input').each(function () {
this.$('input').each(function () {
var $input = $(this);
result.push({
src: $input.attr('src'),
@@ -192,16 +226,15 @@
maxTitleSize: 65,
maxDescriptionSize: 155,
start: function () {
var self = this;
var $modal = this.$el;
var pageParser = new website.seo.PageParser();
$modal.find('.js_seo_page_url').text(pageParser.url());
$modal.find('input[name=seo_page_title]').val(pageParser.title());
this.suggestImprovements(pageParser);
this.displayKeywordSuggestions(pageParser);
this.imageList = new website.seo.ImageList(this);
this.imageList.appendTo($modal.find('.js_seo_image_list'));
this.keywordList = new website.seo.KeywordList(this);
this.keywordList.appendTo($modal.find('.js_seo_keywords_list'));
this.keywordList.on('list-full', null, function () {
$modal.find('input[name=seo_page_keywords]')
.attr('readonly', "readonly")
@@ -215,6 +248,13 @@
$modal.find('button[data-action=add]')
.prop('disabled', false).removeClass('disabled');
});
this.keywordList.appendTo($modal.find('.js_seo_keywords_list'));
var companyName = pageParser.company().toLowerCase();
this.suggestionList = new website.seo.SuggestionList(this, companyName);
this.suggestionList.on('selected', self, function (word) {
self.acceptSuggestion(word);
});
this.suggestionList.appendTo($modal.find('.js_seo_suggestions_list'));
$modal.modal();
},
suggestImprovements: function (parser) {
@@ -224,7 +264,7 @@
new website.seo.Tip(this, {
message: message,
type: type
}).appendTo(self.$el.find('.js_seo_tips'));
}).appendTo(self.$('.js_seo_tips'));
}
var pageParser = parser || new website.seo.PageParser();
if (!pageParser.headers('h1').length === 0) {
@@ -247,50 +287,24 @@
displayTip("Your page makup is appropriate for search engines.", 'success');
}
},
displayKeywordSuggestions: function (pageParser) {
var $modal = this.$el;
var self = this;
$modal.find('.js_seo_company_suggestions').append("Loading...");
var companyName = pageParser.company().toLowerCase();
// cf. https://github.com/ddm/seo
// TODO Try with /recommend/
$.getJSON("http://seo.eu01.aws.af.cm/suggest/"+encodeURIComponent(companyName), function (list) {
$modal.find('.js_seo_company_suggestions').empty();
// TODO Improve algorithm + Ajust based on custom user keywords
var nameRegex = new RegExp(companyName, "gi");
var cleanList = _.map(list, function removeCompanyName (word) {
return word.replace(nameRegex, "").trim();
});
// TODO Order properly ?
cleanList.push(companyName);
_.each(_.uniq(cleanList), function (keyword) {
if (keyword) {
var suggestion = new website.seo.Suggestion(self, {
keyword: keyword
});
suggestion.on('selected', self, function () {
self.addKeyword(keyword);
});
suggestion.appendTo($modal.find('.js_seo_company_suggestions'));
}
});
});
},
confirmKeyword: function (e) {
if (e.keyCode == 13) {
this.addKeyword(this.$el.find('input[name=seo_page_keywords]').val());
this.addKeyword();
}
},
addKeyword: function (word) {
var $input = this.$el.find('input[name=seo_page_keywords]');
var $input = this.$('input[name=seo_page_keywords]');
var keyword = _.isString(word) ? word : $input.val();
this.keywordList.add(keyword);
this.keywordList.add(keyword, false);
$input.val("");
},
acceptSuggestion: function (suggestion) {
this.keywordList.add(suggestion, true);
},
update: function () {
var data = {
title: this.$el.find('input[name=seo_page_title]').val(),
description: this.$el.find('input[name=seo_page_title]').val(),
title: this.$('input[name=seo_page_title]').val(),
description: this.$('input[name=seo_page_title]').val(),
keywords: this.keywordList.keywords(),
images: this.imageList.images(),
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<t t-name="website.ace_view_editor">
<div class="oe_ace_view_editor oe_ace_closed">
<div class="form-inline oe_ace_view_editor_title">
<select id="ace-view-list" class="form-control oe_view_list">
<!-- filled in JS -->
</select>
<button data-action="save" type="submit" class="btn btn-success">Save</button>
<button data-action="format" type="button" class="btn btn-warning">Format</button>
<button data-action="close" type="button" class="btn btn-info">Close</button>
</div>
<div id="ace-view-editor"/>
</div>
</t>
<t t-name="website.ace_view_option">
<option t-att-value="widget.view_id"><t t-esc="widget.view_name"/></option>
</t>
</templates>
@@ -35,73 +35,87 @@
<t t-call="website.editor.dialog">
<t t-set="title">Link to</t>
<form>
<ul class="list-group form-group">
<li class="list-group-item active">
<h3 class="list-group-item-heading">Page on your website</h3>
<div class="input-group">
<input type="text" class="form-control pages url-source"
placeholder="Create new page"/>
<div class="input-group-btn existing dropdown">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">Existing page <span class="caret"></span></button>
<ul class="dropdown-menu pull-right"/>
</div>
</div>
<ul class="nav nav-pills nav-justified">
<li class="active">
<a href="#link-existing" data-toggle="pill">Your website</a>
</li>
<li class="list-group-item">
<li><a href="#link-new" data-toggle="pill">New page</a></li>
<li><a href="#link-external" data-toggle="pill">External Page</a></li>
<li><a href="#link-email" data-toggle="pill">Email Address</a></li>
</ul>
<div class="tab-content">
<div id="link-existing" class="tab-pane active form-group">
<select id="link-existing-select"
class="form-control url-source">
<option disabled="disabled">Select existing page:</option>
</select>
</div>
<div id="link-new" class="tab-pane form-group">
<input type="text" class="form-control pages url-source"
placeholder="Enter the name of the new page"/>
</div>
<div id="link-external" class="tab-pane">
<input type="text" class="form-control url url-source"
placeholder="example: http://openerp.com"/>
<div class="pull-right">
<label>
<input type="checkbox" class="window-new"/>
Open in new window
</label>
</div>
<h3 class="list-group-item-heading">Website URL</h3>
<input type="text" class="form-control url url-source"
placeholder="http://openerp.com"/>
</li>
<li class="list-group-item">
<h3 class="list-group-item-heading">Email Address</h3>
</div>
<div id="link-email" class="tab-pane">
<input type="email" class="form-control email-address url-source"
placeholder="you@yourwebsite.com"/>
</li>
</ul>
placeholder="example: you@yourwebsite.com"/>
</div>
</div>
</form>
</t>
</t>
<t t-name="website.editor.dialog.image">
<t t-call="website.editor.dialog">
<t t-set="title">Image:</t>
<div class="row">
<form method="POST" action="/website/attach"
enctype="multipart/form-data"
target="fileframe"
class="col-sm-8">
<div class="well">
<!-- a href="#" class="pull-left">Find image</a -->
<h3 class="list-group-item-heading">Image URL</h3>
<input type="text" class="form-control url"
placeholder="http://openerp.com"/>
</div>
<div class="text-center">
<p class="">— or —</p>
<input type="file" name="upload" style="position: absolute; opacity: 0; width: 1px; height: 1px;"/>
<button type="button" class="btn btn-primary btn-lg filepicker">
Upload an image from your computer
</button>
</div>
<p class="text-center">— or —</p>
<div class="well">
<h3 class="list-group-item-heading">Pick an existing attachment</h3>
<div class="existing-attachments"/>
</div>
<input type="hidden" name="func"/>
</form>
<div class="col-sm-4">
<div>
<div class="image-preview-container">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAC0lEQVQIHWP4zwAAAgEBAMVfG14AAAAASUVORK5CYII%3D"
class="pull-right img-rounded image-preview"
width="100%"/>
<select class="form-control image-style">
<option value="">No styling</option>
<option value="img-rounded">Rounded corners</option>
<option value="img-thumbnail">Box</option>
<option value="img-circle">Circle</option>
</select>
</div>
<form method="POST" action="/website/attach"
enctype="multipart/form-data"
target="fileframe">
<ul class="nav nav-pills nav-justified">
<li class="active"><a href="#image-upload" data-toggle="pill">
Upload
</a></li>
<li><a href="#image-existing" data-toggle="pill">Your images</a></li>
<li><a href="#image-external" data-toggle="pill">External Image</a></li>
</ul>
<div class="tab-content">
<div id="image-upload" class="tab-pane active form-group text-center">
<input type="file" name="upload" style="position: absolute; opacity: 0; width: 1px; height: 1px;"/>
<button type="button" class="btn btn-primary btn-lg filepicker">
Upload an image from your computer
</button>
</div>
<div id="image-existing" class="tab-pane well">
<div class="existing-attachments"/>
</div>
<div id="image-external" class="tab-pane well form-group">
<input type="text" class="form-control url"
placeholder="e.g. http://goo.gl/EDC325"/>
</div>
</div>
<input type="hidden" name="func"/>
</form>
<iframe src="about:blank" name="fileframe" class="hidden"/>
</div>
<iframe src="about:blank" name="fileframe" class="hidden"/>
</t>
</t>
<t t-name="website.editor.dialog.image.existing">
@@ -15,10 +15,8 @@
<h3 class="page-header">1. Define keywords <small>describing your page content</small></h3>
<dl class="dl-horizontal">
<dt>Suggestions</dt>
<dd>
<ul class="list-inline js_seo_company_suggestions">
<!-- filled in JS -->
</ul>
<dd class="js_seo_suggestions_list">
<!-- filled in JS -->
</dd>
</dl>
<div class="form-horizontal" role="form">
@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<!-- Editor -->
<t t-name="website.snippets">
<div id='oe_snippets' class='hide'>
<ul class="nav nav-pills">
<li class="active"><a data-toggle="pill" href="#snippet_structure">Structure</a></li>
<li class=""><a data-toggle="pill" href="#snippet_content">Content</a></li>
<li class=""><a data-toggle="pill" href="#snippet_emphasize">Emphasize</a></li>
<li class=""><a data-toggle="pill" href="#snippet_style">Style</a></li>
</ul>
<div class="pill-content">
<div class="pill-pane active" id="snippet_structure"></div>
<div class="pill-pane" id="snippet_content"></div>
<div class="pill-pane" id="snippet_emphasize"></div>
<div class="pill-pane" id="snippet_style"></div>
<div class="pill-pane" id="snippet_unsorted"></div>
</div>
</div>
</t>
<t t-name="website.snippet_manipulator">
<div class='oe_snippet_manipulator'></div>
</t>
<!-- Snippets -->
<div t-name="website.snippets.resize" data-snippet-id='resize'>
<!-- editor bar to display inside the top edit bar -->
<li class='oe_snippet_options'>
<a href="#" class="button js_box_move"><i class='icon icon-move'></i></a>
</li>
<li class='oe_snippet_options'>
<a href="#" class="button js_box_remove"><i class="icon icon-remove"></i></a>
</li>
<!-- custom data for the widget -->
<div class='oe_handles'>
<div class='oe_handle n'></div>
<div class='oe_handle e'></div>
<div class='oe_handle w'></div>
<div class='oe_handle s'></div>
</div>
</div>
<div t-name="website.snippets.carousel" data-snippet-id='carousel' data-category='emphasize' data-action='insert' data-selector-siblings='.container'>
<!-- editor bar to display inside the top edit bar -->
<li class='oe_snippet_options'>
<a href="#" class="button js_add"><i class="icon icon-plus-sign"></i></a>
</li>
<li class='oe_snippet_options'>
<a href="#" class="button js_remove"><i class="icon icon-minus-sign"></i></a>
</li>
<li class='oe_snippet_options'>
<select name="carousel-background">
<option value="/website/static/src/img/greenfields.jpg">greenfields</option>
<option value="/website/static/src/img/landscape.png">landscape</option>
<option value="/website/static/src/img/aqua.jpg">aqua</option>
</select>
</li>
<li class='oe_snippet_options'>
<select name="carousel-style">
<option value="no_image">No image</option>
<option value="image_left">Image left</option>
<option value="image_right">Image right</option>
</select>
</li>
<!-- thumbnail to display inside the bottom widget list editor -->
<div class='oe_snippet_thumbnail oe_label'>carousel</div>
<!-- body to insert after drag and drop thumbnail -->
<div id="myCarousel" class="oe_snippet_body carousel slide" data-interval="10000">
<!-- Carousel items -->
<div class="carousel-inner">
<div class="item active" style="background-image: url(/website/static/src/img/greenfields.jpg); background-size: cover;">
<div class="container">
<div class="content" style="padding-top: 90px; padding-bottom:45px;">
<h1>Create Awesome Websites</h1>
<h3>Super easy, fully flexible</h3>
<a href="/page/website.contactus" class="btn btn-success btn-large mt16">Contact us</a>
</div>
</div>
</div>
</div>
<!-- Carousel nav -->
<a class="carousel-control left" href="#myCarousel" data-slide="prev"></a>
<a class="carousel-control right" href="#myCarousel" data-slide="next"></a>
</div>
<!-- custom data for the widget -->
<div class="item" style="background-image: url(/website/static/src/img/china.jpg); background-size: cover; background-position: bottom;" >
<div class='container'>
<div class="content" style="padding-top: 90px; padding-bottom:45px;">
<h1>Your New Banner Slide</h1>
<h3>With another convincing subtitle</h3>
<a href="/page/website.contactus" class="btn btn-success btn-large mt16">Contact us</a>
</div>
</div>
</div>
</div>
<div t-name="website.snippets.darken" data-snippet-id='darken' data-category='style' data-action='mutate' data-selector='.container'>
<div class='oe_snippet_thumbnail oe_label'>Darken</div>
</div>
<div t-name="website.snippets.surprise" data-snippet-id='vomify' data-category='content' data-action='mutate' data-selector='.container'>
<div class='oe_snippet_thumbnail oe_label' style='background-image:radial-gradient(red,orange,yellow,green,blue);'>Surprise!</div>
</div>
<div t-name="website.snippets.spacer" data-snippet-id='spacer' data-category='structure' data-action='insert' data-selector-siblings='.container'>
<div class='oe_snippet_thumbnail oe_label'>Spacer</div>
<div class="oe_snippet_body container mt32"></div>
</div>
<div t-name="website.snippets.title" data-snippet-id='title' data-category='structure' data-action='insert' data-selector-siblings='.container'>
<div class='oe_snippet_thumbnail oe_label'>Main Title</div>
<section class="oe_snippet_body container">
<div class="row">
<div class="col-md-12 text-center">
<h1 class="mt64">Welcome To Your New Homepage,</h1>
<h2 class="mt32 subheader">where <b><em>everything</em></b> can be customized </h2>
</div>
</div>
</section>
</div>
<div t-name="website.snippets.three-collumns" data-snippet-id='three-collumns' data-category='structure' data-action='insert' data-selector-siblings='.container'>
<div class='oe_snippet_thumbnail oe_label'>three-collumns</div>
<section class="oe_snippet_body container">
<div class="row">
<div class="col-md-12 text-center">
<h2 class="mt48">Ut enim ad minim veniam</h2>
</div>
</div>
<div class="row mt32">
<div class="col-md-4">
<img class="img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg"/>
<h4 class="mt16">Cillum Dolore</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
</div>
<div class="col-md-4">
<img class="img-rounded img-responsive" src="/website/static/src/img/desert_thumb.jpg"/>
<h4 class="mt16">Mollit Anim</h4>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
</div>
<div class="col-md-4">
<img class="img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg"/>
<h4 class="mt16">Nemo Enim Ipsam</h4>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore
veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas</p>
</div>
</div>
</section>
</div>
<div t-name="website.snippets.header-block" data-snippet-id='header-block' data-category='structure' data-action='insert' data-selector-siblings='.container'>
<div class='oe_snippet_thumbnail oe_label'>header-block</div>
<section class="container oe_snippet_body">
<div class="row">
<div class="col-md-5">
<img class="img-rounded img-responsive" src="/website/static/src/img/island.jpg"/>
</div>
<div class="col-md-6 col-lg-offset-1">
<p class="mt16">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<div class="text-center">
<a href="http://www.openerp.com/start" class="btn btn-default mt16 btn-lg btn-primary">Call To <em>Action</em></a>
</div>
</div>
</div>
</section>
</div>
</templates>
-30
View File
@@ -57,34 +57,4 @@
</div>
</t>
<t t-name="website.carousel">
<div class="item" style="background-image: url(/website/static/src/img/china.jpg); background-size: cover; background-position: bottom;" >
<div class='container'>
<div class="content" style="padding-top: 90px; padding-bottom:45px;">
<h1>Your New Banner Slide</h1>
<h3>With another convincing subtitle</h3>
<a href="/page/website.contactus" class="btn btn-success btn-large mt16">Contact us</a>
</div>
</div>
</div>
</t>
<t t-name="website.snippets">
<div class='oe_snippets hide'>
</div>
</t>
<t t-name="website.snippet_manipulator">
<div class='oe_snippet_manipulator'>
<div class='oe_handle n'></div>
<div class='oe_handle ne'></div>
<div class='oe_handle e'></div>
<div class='oe_handle se'></div>
<div class='oe_handle s'></div>
<div class='oe_handle sw'></div>
<div class='oe_handle w'></div>
<div class='oe_handle nw'></div>
</div>
</t>
</templates>
+25 -122
View File
@@ -13,7 +13,9 @@
<template id="layout">
&lt;!DOCTYPE html&gt;
<html t-att-data-editable="'1' if editable else '0'" t-att-data-view-xmlid="str(__stack__[0])">
<html t-att-lang="lang.replace('_', '-')"
t-att-data-editable="'1' if editable else '0'"
t-att-data-view-xmlid="str(__stack__[0])">
<head>
<title><t t-esc="title or res_company.name"/></title>
<meta name="openerp.company" t-att-value="res_company.name" />
@@ -33,6 +35,8 @@
<script type="text/javascript" src="/website/static/lib/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ace/1.1.01/ace.js"></script>
<script type="text/javascript" src="//vkbeautify.googlecode.com/files/vkbeautify.0.99.00.beta.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
@@ -42,6 +46,7 @@
<script type="text/javascript" src="/website/static/src/js/website.mobile.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.seo.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.snippets.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
</t>
<t t-raw="head or ''"/>
@@ -66,16 +71,18 @@
<ul class="nav navbar-nav navbar-right" id="top_menu">
<li><a href="/page/website.contactus">Contact us</a></li>
<li><a href="/admin">Sign in</a></li>
<li t-if="len(lang_list) &gt; 1" class="dropdown">
<li t-if="len(website.language_ids) &gt; 1" class="dropdown">
<!-- TODO: use flags for language selection -->
<t t-set="lang_selected" t-value="[lg for lg in website.language_ids if lg.code == lang]"/>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<t t-esc="lang_selected['name']"/> <span class="caret"></span>
<t t-esc="lang_selected[0]['name']"/> <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<li t-foreach="lang_list" t-as="lg">
<li t-foreach="website.language_ids" t-as="lg">
<a href="#" role="menuitem">
<strong t-att-class="'icon-check' if lg['code'] == lang_selected['code']
<strong t-att-class="'icon-check' if lg.code == lang
else 'icon-check-empty'"></strong>
<t t-esc="lg['name']"/>
<t t-esc="lg.name"/>
</a>
</li>
</ul>
@@ -154,23 +161,7 @@
<template id="homepage" page="True">
<t t-call="website.layout">
<section>
<div id="myCarousel" class="carousel slide" data-interval="1000000">
<div class="oe_carousel_options js_carousel_options" t-ignore="1" t-if="editable">
<span class="label label-default js_add"><i class="icon-plus-sign"></i></span>
<span class="label label-default js_remove"><i class="icon-minus-sign"></i></span>
<select name="carousel-background" class="form-control">
<option value="">Chose an other background</option>
<option value="/website/static/src/img/greenfields.jpg">greenfields</option>
<option value="/website/static/src/img/landscape.png">landscape</option>
<option value="/website/static/src/img/aqua.jpg">aqua</option>
</select>
<select name="carousel-style" class="form-control">
<option value="">Chose an other style</option>
<option value="no_image">No image</option>
<option value="image_left">Image left</option>
<option value="image_right">Image right</option>
</select>
</div>
<div id="myCarousel" data-snippet-id="carousel" class="carousel slide" data-interval="1000000">
<!-- Carousel items -->
<div class="carousel-inner">
<div class="item active" style="background-image: url(/website/static/src/img/greenfields.jpg); background-size: cover;">
@@ -190,9 +181,9 @@
</section>
<div>
<section class="container">
<section class="container" data-snippet-id="resize">
<div class="row">
<div class="col-md-12 text-center">
<div class="col-md-12 text-center" data-snippet-id="colmd">
<h1>Welcome To Your New Homepage,</h1>
<h2>where <b>everything</b> can be <em>customized</em></h2>
</div>
@@ -200,12 +191,12 @@
</section>
<div class="dark mt64">
<section class="container">
<section class="container" data-snippet-id="resize">
<div class="row">
<div class="col-md-5">
<div class="col-md-5" data-snippet-id="colmd">
<img class="img-rounded img-responsive" src="/website/static/src/img/island.jpg" />
</div>
<div class="col-md-6 col-lg-offset-1">
<div class="col-md-6 col-lg-offset-1" data-snippet-id="colmd">
<p class="mt16">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
@@ -223,14 +214,14 @@
</section>
</div>
<section class="container">
<section class="container" data-snippet-id="resize">
<div class="row">
<div class="col-md-12 text-center">
<div class="col-md-12 text-center" data-snippet-id="colmd">
<h2 class="mt48">Ut enim ad minim veniam</h2>
</div>
</div>
<div class="row mt32">
<div class="col-md-4">
<div class="col-md-4" data-snippet-id="colmd">
<img class="img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg" />
<h4 class="mt16">Cillum Dolore</h4>
<p>
@@ -240,7 +231,7 @@
consequat.
</p>
</div>
<div class="col-md-4">
<div class="col-md-4" data-snippet-id="colmd">
<img class="img-rounded img-responsive" src="/website/static/src/img/desert_thumb.jpg"/>
<h4 class="mt16">Mollit Anim</h4>
<p>
@@ -249,7 +240,7 @@
proident, sunt in culpa qui officia deserunt mollit anim id est laborum
</p>
</div>
<div class="col-md-4">
<div class="col-md-4" data-snippet-id="colmd">
<img class="img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg"/>
<h4 class="mt16">Nemo Enim Ipsam</h4>
<p>
@@ -415,99 +406,11 @@
</a>
</template>
<template id="snippets">
<div class='oe_snippet' data-snippet-id='darken' data-action='mutate' data-selector='#wrap .container' data-action-function='openerp.website.mutations.darken'>
<div class='oe_snippet_thumbnail oe_label'>Darken</div>
</div>
<div class='oe_snippet' data-snippet-id='surprise' data-action='mutate' data-selector='#wrap .container' data-action-function='openerp.website.mutations.vomify'>
<div class='oe_snippet_thumbnail oe_label' style='background-image:radial-gradient(red,orange,yellow,green,blue);'>Surprise!</div>
</div>
<div class='oe_snippet' data-snippet-id='spacer' data-action='insert' data-selector-siblings='#wrap .container'>
<div class='oe_snippet_thumbnail oe_label'>Spacer</div>
<div class="oe_snippet_body container mt32"></div>
</div>
<div class='oe_snippet' data-snippet-id='title' data-action='insert' data-selector-siblings='#wrap .container'>
<div class='oe_snippet_thumbnail oe_label'>
Main Title
</div>
<section class="oe_snippet_body container">
<div class="row">
<div class="col-md-12 text-center">
<h1 class="mt64">Welcome To Your New Homepage,</h1>
<h2 class="mt32 subheader">where <b><em>everything</em></b> can be customized </h2>
</div>
</div>
</section>
</div>
<div class='oe_snippet' data-snippet-id='' data-action='insert' data-selector-siblings='#wrap .container'>
<section class="oe_snippet_body container">
<div class="row">
<div class="col-md-12 text-center">
<h2 class="mt48">Ut enim ad minim veniam</h2>
</div>
</div>
<div class="row mt32">
<div class="col-md-4">
<img class="img-rounded img-responsive" src="/website/static/src/img/china_thumb.jpg"/>
<h4 class="mt16">Cillum Dolore</h4>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
</div>
<div class="col-md-4">
<img class="img-rounded img-responsive" src="/website/static/src/img/desert_thumb.jpg"/>
<h4 class="mt16">Mollit Anim</h4>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
</div>
<div class="col-md-4">
<img class="img-rounded img-responsive" src="/website/static/src/img/deers_thumb.jpg"/>
<h4 class="mt16">Nemo Enim Ipsam</h4>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore
veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim
ipsam voluptatem quia voluptas</p>
</div>
</div>
</section>
</div>
<div class='oe_snippet' name='Header' data-action='insert' data-selector-siblings='#wrap .container'>
<section class="container oe_snippet_body">
<div class="row">
<div class="col-md-5">
<img class="img-rounded img-responsive" src="/website/static/src/img/island.jpg"/>
</div>
<div class="col-md-6 col-lg-offset-1">
<p class="mt16">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum</p>
<div class="text-center">
<a href="http://www.openerp.com/start" class="btn btn-default mt16 btn-lg btn-primary">Call To <em>Action</em></a>
</div>
</div>
</div>
</section>
</div>
</template>
<template id="kanban">
<t t-set="step"><t t-esc="step or 0"/></t>
<t t-set="scope"><t t-esc="scope or 0"/></t>
<t t-set="orderby"><t t-esc="orderby or 'name'"/></t>
<t t-raw="snipped['kanban'](model, domain, column, template, step=step, scope=scope, orderby=orderby)"/>
<t t-raw="website.kanban(model, domain, column, template, step=step, scope=scope, orderby=orderby)"/>
</template>
<template id="kanban_contain">
+66 -115
View File
@@ -5,7 +5,6 @@ import simplejson
import openerp
from openerp.osv import osv, fields
from openerp.addons.web import http
from openerp.addons.web.controllers import main
from openerp.addons.web.http import request
import urllib
import math
@@ -21,10 +20,10 @@ def route(*route_args, **route_kwargs):
@http.route(*route_args, **route_kwargs)
@functools.wraps(f, assigned=functools.WRAPPER_ASSIGNMENTS + ('func_name',))
def wrap(*args, **kwargs):
if not hasattr(request, 'webcontext'):
request.webcontext = WebContext()
request.context['lang'] = request.webcontext['lang_selected']['code']
request.route_lang = None # WIP: decorator will support lang argument
if not hasattr(request, 'website'):
request.website = request.registry['website'].get_current()
request.website.preprocess_request(*args, **kwargs)
return f(*args, **kwargs)
return wrap
return decorator
@@ -46,31 +45,15 @@ def urlplus(url, params):
url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
return url
class WebsiteError(Exception):
pass
class WebContext(dict):
def __init__(self):
self.website = request.registry.get("website")
lang = request.httprequest.host.split('.')[0]
context = self.website.get_webcontext(lang=lang)
dict.__init__(self, context)
def __getattr__(self, name):
if hasattr(self.website, name):
return getattr(self.website, name)
elif name in self:
return self[name]
else:
raise AttributeError
def render(self, template, values=None):
context = self.copy()
if values:
context.update(values)
return self.website.render(template, context)
class website(osv.osv):
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
_description = "Website"
_columns = {
'name': fields.char('Domain'),
'company_id': fields.many2one('res.company', string="Company"),
'language_ids': fields.many2many('res.lang', 'website_lang_rel', 'website_id', 'lang_id', 'Languages'),
'default_lang_id': fields.many2one('res.lang', string="Default language"),
}
public_user = None
@@ -80,100 +63,78 @@ class website(osv.osv):
self.public_user = request.registry[ref[0]].browse(request.cr, openerp.SUPERUSER_ID, ref[1])
return self.public_user
def get_lang_info(self, lang):
fields = ['id', 'name', 'code', 'website_default']
lang_obj = request.registry['res.lang']
languages = lang_obj.search_read(
request.cr, openerp.SUPERUSER_ID, [('website_activated', '=', True)], fields
)
activated = [lg['code'].lower() for lg in languages]
default = [lg['code'] for lg in languages if lg['website_default']]
default = default[0] if default else None
def get_lang(self):
website = request.registry['website'].get_current()
# Try to get the language from cookie
lang = lang or request.httprequest.cookies.get('lang', None)
if not lang or lang not in activated:
# Try to get the default language
if default:
lang = default
# Otherwise get the first activated language
elif activated:
lang = activated[0]
# Otherwise the language setup is broken
else:
raise WebsiteError("Could not aquire default language")
if hasattr(request, 'route_lang'):
lang = request.route_lang
else:
lang = request.params.get('lang', None) or request.httprequest.cookies.get('lang', None)
return {
'lang_list': languages,
'lang_default': default,
'lang_selected': (lg for lg in languages if lg['code'].lower() == lang.lower()).next(),
}
if lang not in [lg.code for lg in website.language_ids]:
lang = website.default_lang_id.code
def get_webcontext(self, additional_values=None, lang=None):
debug = 'debug' in request.params
is_logged = True
try:
request.session.check_security()
except: # TODO fme: check correct exception
is_logged = False
return lang
def preprocess_request(self, cr, uid, ids, *args, **kwargs):
is_public_user = request.uid == self.get_public_user().id
values = {
'debug': debug,
request.context.update({
'is_public_user': is_public_user,
'editable': is_logged and not is_public_user,
'request': request,
'registry': request.registry,
'cr': request.cr,
'uid': request.uid,
'host_url': request.httprequest.host_url,
'res_company': request.registry['res.company'].browse(request.cr, openerp.SUPERUSER_ID, 1),
'json': simplejson,
'snipped': {
'kanban': self.kanban
},
}
values.update(self.get_lang_info(lang))
'editable': not is_public_user, # TODO: check perms
})
request.context['lang'] = self.get_lang()
if additional_values:
values.update(additional_values)
return values
def get_current(self):
# WIP, currently hard coded
return self.browse(request.cr, request.uid, 1)
def render(self, template, values=None):
def render(self, cr, uid, ids, template, values=None):
view = request.registry.get("ir.ui.view")
IMD = request.registry.get("ir.model.data")
if not values:
qweb_context = request.context.copy()
if values is None:
values = {}
values.update({
'request': request,
'registry': request.registry,
'json': simplejson,
'website': request.website,
'res_company': request.website.company_id,
})
qweb_context.update(values)
context = {
'inherit_branding': values.get('editable', False),
'inherit_branding': qweb_context.get('editable', False),
}
# check if xmlid of the template exists
try:
model, xmlid = template.split('.', 1)
model, id = IMD.get_object_reference(request.cr, request.uid, model, xmlid)
model, id = IMD.get_object_reference(cr, uid, model, xmlid)
except ValueError:
logger.error("Website Rendering Error.\n\n%s" % traceback.format_exc())
return self.render('website.404', values)
return self.render('website.404', qweb_context)
# render template and catch error
try:
return view.render(request.cr, request.uid, template, values, context=context)
return view.render(cr, uid, template, qweb_context, context=context)
except (AccessError, AccessDenied), err:
logger.error(err)
values['error'] = err[1]
qweb_context['error'] = err[1]
logger.warn("Website Rendering Error.\n\n%s" % traceback.format_exc())
return self.render('website.401', values)
return self.render('website.401', qweb_context)
except Exception:
values['traceback'] = traceback.format_exc()
logger.error("Website Rendering Error.\n\n%s" % values['traceback'])
if values['editable']:
return view.render(request.cr, request.uid, 'website.500', values, context=context)
qweb_context['traceback'] = traceback.format_exc()
logger.error("Website Rendering Error.\n\n%s" % qweb_context['traceback'])
if qweb_context['editable']:
return view.render(cr, uid, 'website.500', qweb_context, context=context)
else:
return view.render(request.cr, request.uid, 'website.404', values, context=context)
return view.render(cr, uid, 'website.404', qweb_context, context=context)
def pager(self, url, total, page=1, step=30, scope=5, url_args=None):
def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None):
# Compute Pager
page_count = int(math.ceil(float(total) / step))
@@ -228,7 +189,7 @@ class website(osv.osv):
if xids[view['id']]
]
def kanban(self, model, domain, column, template, step=None, scope=None, orderby=None):
def kanban(self, cr, uid, ids, model, domain, column, template, step=None, scope=None, orderby=None):
step = step and int(step) or 10
scope = scope and int(scope) or 5
orderby = orderby or "name"
@@ -249,12 +210,12 @@ class website(osv.osv):
pages[int(col[0])] = int(col[1])
objects = []
for group in model_obj.read_group(request.cr, request.uid, domain, ["id", column], groupby=column):
for group in model_obj.read_group(cr, uid, domain, ["id", column], groupby=column):
obj = {}
# browse column
relation_id = group[column][0]
obj['column_id'] = relation_obj.browse(request.cr, request.uid, relation_id)
obj['column_id'] = relation_obj.browse(cr, uid, relation_id)
obj['kanban_url'] = kanban_url
for k, v in pages.items():
@@ -262,7 +223,7 @@ class website(osv.osv):
obj['kanban_url'] += "%s-%s" % (k, v)
# pager
number = model_obj.search(request.cr, request.uid, group['__domain'], count=True)
number = model_obj.search(cr, uid, group['__domain'], count=True)
obj['page_count'] = int(math.ceil(float(number) / step))
obj['page'] = pages.get(relation_id) or 1
if obj['page'] > obj['page_count']:
@@ -278,8 +239,8 @@ class website(osv.osv):
obj['orderby'] = orderby
# browse objects
object_ids = model_obj.search(request.cr, request.uid, group['__domain'], limit=step, offset=offset, order=orderby)
obj['object_ids'] = model_obj.browse(request.cr, request.uid, object_ids)
object_ids = model_obj.search(cr, uid, group['__domain'], limit=step, offset=offset, order=orderby)
obj['object_ids'] = model_obj.browse(cr, uid, object_ids)
objects.append(obj)
@@ -288,30 +249,20 @@ class website(osv.osv):
'range': range,
'template': template,
}
return request.webcontext.render("website.kanban_contain", values)
return request.website.render("website.kanban_contain", values)
def kanban_col(self, model, domain, page, template, step, orderby):
def kanban_col(self, cr, uid, ids, model, domain, page, template, step, orderby):
html = ""
model_obj = request.registry[model]
domain = safe_eval(domain)
step = int(step)
offset = (int(page)-1) * step
object_ids = model_obj.search(request.cr, request.uid, domain, limit=step, offset=offset, order=orderby)
object_ids = model_obj.browse(request.cr, request.uid, object_ids)
object_ids = model_obj.search(cr, uid, domain, limit=step, offset=offset, order=orderby)
object_ids = model_obj.browse(cr, uid, object_ids)
for object_id in object_ids:
html += request.webcontext.render(template, {'object_id': object_id})
html += request.website.render(template, {'object_id': object_id})
return html
class res_lang(osv.osv):
_inherit = "res.lang"
_columns = {
'website_activated': fields.boolean('Active on website'),
'website_default': fields.boolean('Website default language'),
}
# TODO: on write and create set website_default=False on other records if current is True
class res_partner(osv.osv):
_inherit = "res.partner"
+5 -29
View File
@@ -1,35 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="res_lang_tree" model="ir.ui.view">
<field name="name">res.lang.tree website</field>
<field name="model">res.lang</field>
<field name="inherit_id" ref="base.res_lang_tree"/>
<field name="arch" type="xml">
<field name="active" position="after">
<field name="website_activated"/>
<field name="website_default"/>
</field>
</field>
</record>
<record id="res_lang_form" model="ir.ui.view">
<field name="name">res.lang.form website</field>
<field name="model">res.lang</field>
<field name="inherit_id" ref="base.res_lang_form"/>
<field name="arch" type="xml">
<field name="active" position="after">
<field name="website_activated"/>
<field name="website_default"/>
</field>
</field>
</record>
</data>
<data noupdate="1">
<record id="base.lang_en" model="res.lang">
<field name="website_activated">True</field>
<field name="website_default">True</field>
<record id="default_website" model="website">
<field name="name">www.dundermufflin.com</field>
<field name="company_id" ref="base.main_company"/>
<field name="language_ids" eval="[(6, 0, [ ref('base.lang_en')])]"/>
<field name="default_lang_id" ref="base.lang_en"/>
</record>
<record id="public_user" model="res.users">
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="default_website" model="website">
<field name="name">localhost</field>
<field name="company_id" ref="base.main_company"/>
<field name="language_ids" eval="[(6, 0, [ ref('base.lang_en')])]"/>
<field name="default_lang_id" ref="base.lang_en"/>
</record>
</data>
<data>
<record id="action_website_form" model="ir.actions.act_window">
<field name="name">Websites</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">website</field>
<field name="view_type">form</field>
<field name="help">Create and manage the companies websites.</field>
</record>
<menuitem action="action_website_form" id="menu_action_website_form" parent="base.menu_res_company_global"/>
<record id="view_website_tree" model="ir.ui.view">
<field name="name">website.tree</field>
<field name="model">website</field>
<field name="arch" type="xml">
<tree string="Websites">
<field name="name"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="default_lang_id"/>
</tree>
</field>
</record>
<record id="view_website_form" model="ir.ui.view">
<field name="name">website.form</field>
<field name="model">website</field>
<field name="arch" type="xml">
<form string="Website" version="7.0">
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only"/>
<h1>
<field name="name" class="oe_inline"/>
</h1>
</div>
<group col="4">
<field name="company_id" groups="base.group_multi_company"/>
<field name="default_lang_id"/>
</group>
<group string="Website languages">
<field name="language_ids" nolabel="1" mode="tree,form">
<tree>
<field name="name"/>
<field name="code"/>
<field name="translatable"/>
</tree>
</field>
</group>
</sheet>
</form>
</field>
</record>
</data>
</openerp>
+13 -11
View File
@@ -11,7 +11,6 @@ class website_contract(http.Controller):
@website.route(['/references/', '/references/page/<int:page>/'], type='http', auth="public")
def references(self, page=0, **post):
website = request.registry['website']
partner_obj = request.registry['res.partner']
account_obj = request.registry['account.analytic.account']
@@ -31,10 +30,10 @@ class website_contract(http.Controller):
# public partner profile
partner_ids = partner_obj.search(
request.cr, openerp.SUPERUSER_ID,
domain + [('website_published', '=', True)], request.context)
domain + [('website_published', '=', True)], context=request.context)
google_map_partner_ids = ",".join([str(p) for p in partner_ids])
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
# search without website_published
partner_ids += partner_obj.search(request.cr, request.uid,
domain, context=request.context)
@@ -49,7 +48,7 @@ class website_contract(http.Controller):
countries.insert(0, {
'country_id_count': country_count,
'country_id': ("all", _("All Countries"))
}, context=request.context)
})
if post.get("country", "all") != 'all':
partner_ids = partner_obj.search(
@@ -60,7 +59,7 @@ class website_contract(http.Controller):
], context=request.context)
step = 20
pager = website.pager(url="/references/", total=len(partner_ids), page=page, step=step, scope=7, url_args=post)
pager = request.website.pager(url="/references/", total=len(partner_ids), page=page, step=step, scope=7, url_args=post)
partner_ids = partner_obj.search(
request.cr, openerp.SUPERUSER_ID, [('id', 'in', partner_ids)],
limit=step, offset=pager['offset'], context=request.context)
@@ -74,7 +73,7 @@ class website_contract(http.Controller):
'searches': post,
'search_path': "?%s" % urllib.urlencode(post),
}
return request.webcontext.render("website_contract.index", values)
return request.website.render("website_contract.index", values)
@website.route(['/references/<int:ref_id>/'], type='http', auth="public")
def references_ref(self, ref_id=0, **post):
@@ -84,12 +83,15 @@ class website_contract(http.Controller):
('website_published', '=', True),
('id', '=', ref_id)
], context=request.context)
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
partner_ids += partner_obj.search(
request.cr, request.uid, [('id', '=', ref_id)],
context=request.context)
request.webcontext['partner_id'] = partner_obj.browse(
request.cr, openerp.SUPERUSER_ID, partner_ids[0],
dict(request.context + {'show_address': True}))
return request.webcontext.render("website_contract.details")
values = {
'partner_id': partner_obj.browse(
request.cr, openerp.SUPERUSER_ID, partner_ids[0],
dict(request.context, show_address=True)),
}
return request.website.render("website_contract.details", values)
+2 -2
View File
@@ -13,10 +13,10 @@ class contactus(http.Controller):
post['user_id'] = False
request.registry['crm.lead'].create(request.cr, request.uid,
post, request.context)
company = request.webcontext['res_company']
company = request.website.company_id
values = {
'google_map_url': "http://maps.googleapis.com/maps/api/staticmap?center=%s&sensor=false&zoom=8&size=298x298" % quote_plus('%s, %s %s, %s' % (company.street, company.city, company.zip, company.country_id and company.country_id.name_get()[0][1] or ''))
}
return request.webcontext.render("website_crm.thanks", values)
return request.website.render("website_crm.thanks", values)
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -11,7 +11,6 @@ class website_crm_partner_assign(http.Controller):
@website.route(['/partners/', '/partners/page/<int:page>/'], type='http', auth="public")
def partners(self, page=0, **post):
website = request.registry['website']
partner_obj = request.registry['res.partner']
def dom_without(without):
@@ -66,7 +65,7 @@ class website_crm_partner_assign(http.Controller):
})
step = 20
pager = website.pager(url="/partners/", total=len(partner_ids), page=page, step=step, scope=7, url_args=post)
pager = request.website.pager(url="/partners/", total=len(partner_ids), page=page, step=step, scope=7, url_args=post)
partner_ids = partner_obj.search(
request.cr, openerp.SUPERUSER_ID, [('id', 'in', partner_ids)],
context=request.context, limit=step, offset=pager['offset'],
@@ -83,7 +82,7 @@ class website_crm_partner_assign(http.Controller):
'searches': post,
'search_path': "?%s" % urllib.urlencode(post),
}
return request.webcontext.render("website_crm_partner_assign.index", values)
return request.website.render("website_crm_partner_assign.index", values)
@website.route(['/partners/<int:ref_id>/'], type='http', auth="public")
def partners_ref(self, ref_id=0, **post):
@@ -93,13 +92,15 @@ class website_crm_partner_assign(http.Controller):
[('website_published', '=', True), ('id', '=', ref_id)],
context=request.context)
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
partner_ids += partner_obj.search(
request.cr, request.uid, [('id', '=', ref_id)],
context=request.context)
request.webcontext['partner_id'] = partner_obj.browse(
request.cr, openerp.SUPERUSER_ID, partner_ids[0],
context=dict(request.context + {'show_address': True}))
values = {
'partner_id': partner_obj.browse(
request.cr, openerp.SUPERUSER_ID, partner_ids[0],
context=dict(request.context, show_address=True)),
}
return request.webcontext.render("website_crm_partner_assign.details")
return request.website.render("website_crm_partner_assign.details", values)
+10 -12
View File
@@ -18,7 +18,6 @@ class website_event(http.Controller):
@website.route(['/event/', '/event/page/<int:page>/'], type='http', auth="public")
def events(self, page=1, **searches):
website = request.registry['website']
event_obj = request.registry['event.event']
searches.setdefault('date', 'all')
@@ -102,7 +101,7 @@ class website_event(http.Controller):
event_count = event_obj.search(
request.cr, request.uid, dom_without("none"), count=True,
context=request.context)
pager = website.pager(url="/event/", total=event_count, page=page, step=step, scope=5)
pager = request.website.pager(url="/event/", total=event_count, page=page, step=step, scope=5)
obj_ids = event_obj.search(
request.cr, request.uid, dom_without("none"), limit=step,
offset=pager['offset'], order="date_begin DESC", context=request.context)
@@ -119,20 +118,19 @@ class website_event(http.Controller):
'search_path': "?%s" % urllib.urlencode(searches),
}
return request.webcontext.render("website_event.index", values)
return request.website.render("website_event.index", values)
@website.route(['/event/<int:event_id>'], type='http', auth="public")
def event(self, event_id=None, **post):
event_obj = request.registry['event.event']
context = request.context.copy()
context.update({'show_address': 1})
values = {
'event_id': event_obj.browse(request.cr, request.uid, event_id, context),
'event_id': event_obj.browse(request.cr, request.uid, event_id,
dict(request.context, show_address=1)),
'message_ids': event_obj.browse(request.cr, request.uid, event_id, request.context).message_ids,
'subscribe': post.get('subscribe'),
'range': range
}
return request.webcontext.render("website_event.detail", values)
return request.website.render("website_event.detail", values)
@website.route(['/event/<int:event_id>/add_cart'], type='http', auth="public")
def add_cart(self, event_id=None, **post):
@@ -140,7 +138,7 @@ class website_event(http.Controller):
order_line_obj = request.registry.get('sale.order.line')
ticket_obj = request.registry.get('event.event.ticket')
order = request.webcontext['order']
order = request.context['website_sale_order']
if not order:
order = website_sale.controllers.main.get_order()
@@ -191,8 +189,8 @@ class website_event(http.Controller):
event_obj = request.registry['event.event']
user_obj = request.registry['res.users']
if event_id and 'subscribe' in post and (post.get('email') or not request.webcontext.is_public_user):
if request.webcontext.is_public_user:
if event_id and 'subscribe' in post and (post.get('email') or not request.context['is_public_user']):
if request.context['is_public_user']:
partner_ids = partner_obj.search(
request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))],
context=request.context)
@@ -220,8 +218,8 @@ class website_event(http.Controller):
event_obj = request.registry['event.event']
user_obj = request.registry['res.users']
if event_id and 'unsubscribe' in post and (post.get('email') or not request.webcontext.is_public_user):
if request.webcontext.is_public_user:
if event_id and 'unsubscribe' in post and (post.get('email') or not request.context['is_public_user']):
if request.context['is_public_user']:
partner_ids = partner_obj.search(
request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))],
context=request.context)
@@ -1,2 +0,0 @@
sass:
sass --compass --trace -t expanded hr.sass hr.css
@@ -1 +0,0 @@
@import "compass/css3"
@@ -26,7 +26,6 @@
<template id="index" name="Events" page="True">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_hr/static/src/js/website_hr.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Events</t>
@@ -16,7 +16,7 @@ class google_map(http.Controller):
'height': post.get('height', 460),
'partner_url': post.get('partner_url'),
}
return request.webcontext.render("website_google_map.google_map", values)
return request.website.render("website_google_map.google_map", values)
@website.route(['/google_map/partners.json'], type='http', auth="admin")
def google_map_data(self, *arg, **post):
@@ -26,7 +26,7 @@ class google_map(http.Controller):
domain_public = domain + [('website_published', '=', True)]
partner_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID,
domain_public, context=request.context)
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
partner_ids += partner_obj.search(request.cr, request.uid, domain,
context=request.context)
partner_ids = list(set(partner_ids))
@@ -42,7 +42,7 @@ class google_map(http.Controller):
latitude = post.get('latitude') and float(post['latitude'])
longitude = post.get('longitude') and float(post['longitude'])
if not request.webcontext.is_public_user and partner_id and (latitude or longitude):
if not request.context['is_public_user'] and partner_id and (latitude or longitude):
values = {
'partner_latitude': latitude,
'partner_longitude': longitude,
+1 -1
View File
@@ -15,4 +15,4 @@ class website_hr(http.Controller):
'employee_ids': hr_obj.browse(request.cr, request.uid, employee_ids,
request.context)
}
return request.webcontext.render("website.aboutus", values)
return request.website.render("website.aboutus", values)
@@ -1,2 +0,0 @@
sass:
sass --compass --trace -t expanded hr.sass hr.css
-1
View File
@@ -1 +0,0 @@
@import "compass/css3"
-1
View File
@@ -24,7 +24,6 @@
<template id="aboutus" inherit_id="website.aboutus">
<xpath expr="//div[@class='col-md-8']" position="inside">
<t t-set="head">
<script type="text/javascript" src="/website_hr/static/src/js/website_hr.js"></script>
<t t-raw="head or ''"/>
</t>
<h3>Our team</h3>
+10 -16
View File
@@ -17,7 +17,6 @@ class website_mail(http.Controller):
@website.route(['/blog/', '/blog/<int:mail_group_id>/', '/blog/<int:mail_group_id>/<int:blog_id>/',
'/blog/page/<int:page>/', '/blog/<int:mail_group_id>/page/<int:page>/', '/blog/<int:mail_group_id>/<int:blog_id>/page/<int:page>/'], type='http', auth="public")
def blog(self, mail_group_id=None, blog_id=None, page=0, **post):
website = request.registry['website']
group_obj = request.registry['mail.group']
message_obj = request.registry['mail.message']
user_obj = request.registry['res.users']
@@ -28,10 +27,9 @@ class website_mail(http.Controller):
'nav_list': dict(),
'mail_group_id': mail_group_id,
'subscribe': post.get('subscribe'),
'website': website,
}
if not request.webcontext.is_public_user and mail_group_id:
if not request.context['is_public_user'] and mail_group_id:
message_follower_ids = group_obj.read(request.cr, request.uid, [mail_group_id], ['message_follower_ids'], request.context)[0]['message_follower_ids']
parent_id = user_obj.browse(request.cr, SUPERUSER_ID, request.uid, request.context).partner_id.id
values['subscribe'] = parent_id in message_follower_ids
@@ -50,12 +48,12 @@ class website_mail(http.Controller):
else:
step = 20
message_count = len(group_obj.get_public_message_ids(request.cr, request.uid, domain=domain, order="create_date desc", context=request.context))
pager = website.pager(url="/blog/%s/" % mail_group_id, total=message_count, page=page, step=step, scope=7)
pager = request.website.pager(url="/blog/%s/" % mail_group_id, total=message_count, page=page, step=step, scope=7)
message_ids = group_obj.get_public_message_ids(request.cr, request.uid, domain=domain, order="create_date desc", limit=step, offset=pager['offset'], context=request.context)
values['pager'] = pager
values['blog_ids'] = message_obj.browse(request.cr, request.uid, message_ids, request.context)
return request.webcontext.render("website_mail.index", values)
return request.website.render("website_mail.index", values)
@website.route(['/blog/nav'], type='http', auth="public")
def nav(self, **post):
@@ -67,19 +65,17 @@ class website_mail(http.Controller):
url = request.httprequest.host_url
if post.get('body'):
request.session.body = post.get('body')
if request.webcontext.is_public_user:
if request.context['is_public_user']:
return '%s/admin#action=redirect&url=%s/blog/%s/%s/post' % (url, url, mail_group_id, blog_id)
if 'body' in request.session and request.session.body:
context = request.context.copy()
context.update({'mail_create_nosubsrequest.cribe': True})
request.registry['mail.group'].message_post(request.cr, request.uid, mail_group_id,
body=request.session.body,
parent_id=blog_id,
website_published=blog_id and True or False,
type='comment',
subtype='mt_comment',
context=context)
context=dict(request.context, mail_create_nosubcribe=True))
request.session.body = False
if post.get('body'):
@@ -89,15 +85,13 @@ class website_mail(http.Controller):
@website.route(['/blog/<int:mail_group_id>/new'], type='http', auth="public")
def new_blog_post(self, mail_group_id=None, **post):
context = request.context.copy()
context.update({'mail_create_nosubsrequest.cribe': True})
blog_id = request.registry['mail.group'].message_post(request.cr, request.uid, mail_group_id,
body=_("Blog content.<br/>Please edit this content then you can publish this blog."),
subject=_("Blog title"),
website_published=False,
type='comment',
subtype='mt_comment',
context=context)
context=dict(request.context, mail_create_nosubscribe=True))
return werkzeug.utils.redirect("/blog/%s/%s/" % (mail_group_id, blog_id))
@website.route(['/blog/<int:mail_group_id>/subscribe', '/blog/<int:mail_group_id>/<int:blog_id>/subscribe'], type='http', auth="public")
@@ -106,8 +100,8 @@ class website_mail(http.Controller):
group_obj = request.registry['mail.group']
user_obj = request.registry['res.users']
if mail_group_id and 'subscribe' in post and (post.get('email') or not request.webcontext.is_public_user):
if request.webcontext.is_public_user:
if mail_group_id and 'subscribe' in post and (post.get('email') or not request.context['is_public_user']):
if request.context['is_public_user']:
partner_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))], context=request.context)
if not partner_ids:
partner_ids = [partner_obj.create(request.cr, SUPERUSER_ID, {"email": post.get('email'), "name": "Subscribe: %s" % post.get('email')}, request.context)]
@@ -124,8 +118,8 @@ class website_mail(http.Controller):
group_obj = request.registry['mail.group']
user_obj = request.registry['res.users']
if mail_group_id and 'unsubscribe' in post and (post.get('email') or not request.webcontext.is_public_user):
if request.webcontext.is_public_user:
if mail_group_id and 'unsubscribe' in post and (post.get('email') or not request.context['is_public_user']):
if request.context['is_public_user']:
partner_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("email", "=", post.get('email'))], context=request.context)
else:
partner_ids = [user_obj.browse(request.cr, request.uid, request.uid, request.context).partner_id.id]
@@ -11,7 +11,6 @@ class website_crm_partner_assign(http.Controller):
@website.route(['/members/', '/members/page/<int:page>/'], type='http', auth="public")
def members(self, page=0, **post):
website = request.registry['website']
membership_obj = request.registry['membership.membership_line']
def dom_without(without):
@@ -41,7 +40,7 @@ class website_crm_partner_assign(http.Controller):
memberships.insert(0, {'membership_id_count': membership_obj.search(request.cr, request.uid, domain, count=True, context=request.context), 'membership_id': ("all", _("All Groups"))})
step = 20
pager = website.pager(url="/members/", total=len(membership_ids), page=page, step=step, scope=7, url_args=post)
pager = request.website.pager(url="/members/", total=len(membership_ids), page=page, step=step, scope=7, url_args=post)
membership_ids = membership_obj.search(
request.cr, openerp.SUPERUSER_ID, [('id', 'in', membership_ids)],
limit=step, offset=pager['offset'], order="membership_id ASC,date DESC",
@@ -55,20 +54,18 @@ class website_crm_partner_assign(http.Controller):
'searches': post,
'search_path': "?%s" % urllib.urlencode(post),
}
return request.webcontext.render("website_membership.index", values)
return request.website.render("website_membership.index", values)
@website.route(['/members/<int:ref_id>/'], type='http', auth="public")
def partners_ref(self, ref_id=0, **post):
partner_obj = request.registry['res.partner']
partner_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID, [('website_published', '=', True), ('id', '=', ref_id)], context=request.context)
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
partner_ids += partner_obj.search(request.cr, request.uid, [('id', '=', ref_id)], context=request.context)
context = request.context.copy()
context.update({'show_address': True})
values = {
'partner_id': partner_obj.browse(
request.cr, openerp.SUPERUSER_ID, partner_ids[0],
context=context),
context=dict(request.context, show_address=True)),
}
return request.webcontext.render("website_membership.details", values)
return request.website.render("website_membership.details", values)
+7 -7
View File
@@ -8,13 +8,13 @@ from openerp.addons.website import website
class Website(osv.osv):
_inherit = "website"
def get_webcontext(self, values={}, **kw):
def preprocess_request(self, cr, uid, ids, *args, **kwargs):
project_obj = request.registry['project.project']
project_ids = project_obj.search(request.cr, request.uid, [('privacy_visibility', "=", "public")], context=request.context)
values.update({
'project_ids': project_obj.browse(request.cr, request.uid, project_ids, request.context),
})
return super(Website, self).get_webcontext(values, **kw)
project_ids = project_obj.search(cr, uid, [('privacy_visibility', "=", "public")], context=request.context)
request.context['website_project_ids'] = project_obj.browse(cr, uid, project_ids, request.context)
return super(Website, self).preprocess_request(cr, uid, ids, *args, **kwargs)
class website_project(http.Controller):
@@ -23,4 +23,4 @@ class website_project(http.Controller):
def blog(self, project_id=None, **post):
project_obj = request.registry['project.project']
project = project_obj.browse(request.cr, request.uid, project_id, request.context)
return request.webcontext.render("website_project.index", {'project_id': project})
return request.website.render("website_project.index", {'project_id': project})
@@ -7,7 +7,7 @@
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
<xpath expr="//body/footer//ul[@name='products']" position="inside">
<li t-foreach="project_ids" t-as="project"><a t-attf-href="/project/#{ project.id }/"><t t-esc="project.name"/></a></li>
<li t-foreach="website_project_ids" t-as="project"><a t-attf-href="/project/#{ project.id }/"><t t-esc="project.name"/></a></li>
</xpath>
</template>
+20 -28
View File
@@ -30,11 +30,8 @@ def get_order(order_id=None):
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id, request.context)
request.httprequest.session['ecommerce_order_id'] = order.id
context = request.context.copy()
context.update({
'pricelist': order.pricelist_id.id,
})
return order_obj.browse(request.cr, SUPERUSER_ID, order_id, context=context)
return order_obj.browse(request.cr, SUPERUSER_ID, order_id,
context=dict(request.context, pricelist=order.pricelist_id.id))
def get_current_order():
if request.httprequest.session.get('ecommerce_order_id'):
@@ -44,12 +41,11 @@ def get_current_order():
class Website(osv.osv):
_inherit = "website"
def get_webcontext(self, values={}, **kw):
values.update({
'order': get_current_order(),
# 'website_sale_get_current_order': get_current_order, # TODO: replace 'order' key in templates
def preprocess_request(self, cr, uid, ids, *args, **kwargs):
request.context.update({
'website_sale_order': get_current_order(),
})
return super(Website, self).get_webcontext(values, **kw)
return super(Website, self).preprocess_request(cr, uid, ids, *args, **kwargs)
class Ecommerce(http.Controller):
@@ -64,8 +60,6 @@ class Ecommerce(http.Controller):
if 'promo' in post:
self.change_pricelist(post.get('promo'))
website = request.registry['website']
product_obj = request.registry.get('product.template')
domain = [("sale_ok", "=", True)]
@@ -84,7 +78,7 @@ class Ecommerce(http.Controller):
step = 20
product_count = len(product_obj.search(request.cr, request.uid, domain, context=request.context))
pager = website.pager(url="/shop/category/%s/" % cat_id, total=product_count, page=page, step=step, scope=7, url_args=post)
pager = request.website.pager(url="/shop/category/%s/" % cat_id, total=product_count, page=page, step=step, scope=7, url_args=post)
product_ids = product_obj.search(request.cr, request.uid, domain, limit=step, offset=pager['offset'], context=request.context)
@@ -97,7 +91,7 @@ class Ecommerce(http.Controller):
'search': post.get("search"),
'pager': pager,
}
return request.webcontext.render("website_sale.products", values)
return request.website.render("website_sale.products", values)
@website.route(['/shop/product/<product_id>/'], type='http', auth="public")
def product(self, cat_id=0, product_id=0, **post):
@@ -123,12 +117,13 @@ class Ecommerce(http.Controller):
'category_list': category_list,
'product': product,
}
return request.webcontext.render("website_sale.product", values)
return request.website.render("website_sale.product", values)
@website.route(['/shop/add_product/'], type='http', auth="public")
def add_product(self, **post):
product_id = request.registry.get('product.product').create(request.cr, request.uid, {'name': 'New Product'}, request.context)
return werkzeug.utils.redirect("/shop/product/%s/" % product_id)
@website.route(['/shop/add_product/', '/shop/category/<cat_id>/add_product/'], type='http', auth="public")
def add_product(self, cat_id=0, **post):
product_id = request.registry.get('product.product').create(request.cr, request.uid,
{'name': 'New Product', 'public_categ_id': cat_id}, request.context)
return werkzeug.utils.redirect("/shop/product/%s/?unable_editor=1" % product_id)
@website.route(['/shop/change_category/<product_id>/'], type='http', auth="public")
def edit_product(self, product_id=0, **post):
@@ -175,10 +170,7 @@ class Ecommerce(http.Controller):
if not order:
order = get_order()
context = request.context.copy()
context.update({
'pricelist': self.get_pricelist()
})
context = dict(request.context, pricelist=self.get_pricelist())
quantity = 0
@@ -248,7 +240,7 @@ class Ecommerce(http.Controller):
'categories': self.get_categories(),
'suggested_products': prod_obj.browse(request.cr, request.uid, suggested_products, request.context),
}
return request.webcontext.render("website_sale.mycart", values)
return request.website.render("website_sale.mycart", values)
@website.route(['/shop/<path:path>/add_cart/', '/shop/add_cart/'], type='http', auth="public")
def add_cart(self, path=None, product_id=None, order_line_id=None, remove=None, json=None):
@@ -292,7 +284,7 @@ class Ecommerce(http.Controller):
}
checkout = {}
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
partner = user_obj.browse(request.cr, request.uid, request.uid, request.context).partner_id
partner_id = partner.id
fields = ["name", "phone", "fax", "company", "email", "street", "city", "state_id", "zip", "country_id"]
@@ -314,7 +306,7 @@ class Ecommerce(http.Controller):
states_ids = country_state_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)], context=request.context)
values['states'] = country_state_obj.browse(request.cr, SUPERUSER_ID, states_ids, request.context)
return request.webcontext.render("website_sale.checkout", values)
return request.website.render("website_sale.checkout", values)
@website.route(['/shop/confirm_order/'], type='http', auth="public")
def confirm_order(self, **post):
@@ -361,7 +353,7 @@ class Ecommerce(http.Controller):
'country_id': post['country_id'],
'state_id': post['state_id'],
}
if not request.webcontext.is_public_user:
if not request.context['is_public_user']:
partner_id = user_obj.browse(request.cr, request.uid, request.uid, request.context).partner_id.id
partner_obj.write(request.cr, request.uid, [partner_id], partner_value, request.context)
else:
@@ -420,7 +412,7 @@ class Ecommerce(http.Controller):
content = payment_obj.render(request.cr, SUPERUSER_ID, payment.id, order, order.name, order.pricelist_id.currency_id, order.amount_total)
payment._content = content
return request.webcontext.render("website_sale.payment", values)
return request.website.render("website_sale.payment", values)
@website.route(['/shop/payment_validate/'], type='http', auth="public")
def payment_validate(self, **post):
@@ -22,13 +22,17 @@ $(document).ready(function () {
$(".oe_website_sale .oe_mycart input.js_quantity").change(function () {
var $input = $(this);
var value = parseInt($input.val());
if (!isNaN(value)) {
$.get("./set_cart/", {'order_line_id': $(this).data('id'), 'set_number': value, 'json': true}, function (data) {
var data = JSON.parse(data);
set_my_cart_quantity(data[1]);
$input.val(data[0]);
});
}
if (isNaN(value)) value = 0;
$.get("./set_cart/", {'order_line_id': $input.data('id'), 'set_number': value, 'json': true}, function (data) {
var data = JSON.parse(data);
set_my_cart_quantity(data[1]);
$input.val(data[0]);
if (!+data[0]) {
$.get('/shop/remove_cart/', {'order_line_id': $input.data('id'), 'json': true,}, function (data) {
location.reload();
});
}
});
});
$(".oe_website_sale #product_detail select[name='public_categ_id']").change(function () {
@@ -43,6 +47,9 @@ $(document).ready(function () {
$link = $(ev.currentTarget);
$.get($link.attr("href"), {'json': true}, function (data) {
var data = JSON.parse(data);
if (!+data[0]) {
location.reload();
}
set_my_cart_quantity(data[1]);
$link.parent().find(".js_quantity").val(data[0]);
});
+35 -37
View File
@@ -48,7 +48,8 @@
<li>
<a href="/shop/mycart/">
<i class="icon-shopping-cart"></i>
My cart <span class="my_cart_quantity" t-attf-class="badge #{(not order or not order.get_total_quantity()) and 'hidden' or ''}" t-esc="order and order.get_total_quantity() or ''"/>
My cart <span t-attf-class="my_cart_quantity badge #{(not website_sale_order or not website_sale_order.get_total_quantity()) and 'hidden' or ''}"
t-esc="website_sale_order and website_sale_order.get_total_quantity() or ''"/>
</a>
</li>
</xpath>
@@ -57,7 +58,8 @@
<li>
<a href="/shop/mycart/">
<i class="icon-shopping-cart"></i>
My cart <span class="my_cart_quantity" t-attf-class="badge #{(not order or not order.get_total_quantity()) and 'hidden' or ''}" t-esc="order and order.get_total_quantity() or ''"/>
My cart <span t-attf-class="my_cart_quantity badge #{(not website_sale_order or not website_sale_order.get_total_quantity()) and 'hidden' or ''}"
t-esc="website_sale_order and website_sale_order.get_total_quantity() or ''"/>
</a>
</li>
</xpath>
@@ -73,7 +75,6 @@
</t>
<t t-set="title">Shop - <t t-raw="title">Categories</t></t>
<div class="container oe_website_sale">
<a t-if="editable" href="/shop/add_product/" class="btn btn-default pull-right">Create New Product</a>
<div class="row">
<div class="col-md-12" id="shop_content">
<t t-raw="shop_content" />
@@ -121,6 +122,8 @@
</t>
<t t-set="title">Product</t>
<t t-set="shop_content">
<a t-if="editable" t-attf-href="/shop/#{ category_id and ('category/%s/' % category_id) or ''}add_product/" class="btn btn-default pull-right">Create New Product</a>
<div t-if="editable" class="clearfix"/>
<t t-call="website.pager">
<t t-set="classname">pull-left</t>
</t>
@@ -183,26 +186,21 @@
</label><br/>
<button class="btn btn-sm btn-success">Add to basket</button>
</form>
<img class="media-object img-responsive" t-att-src="product.img('image_medium')"/>
<div t-if="editable" t-att-class="'well css_non_editable_mode_hidden'">
<h2>Category<br/><small>Select the public category</small></h2>
<select name="public_categ_id" class="form-control" t-att-data-id="product.id">
<option value="0">Choose a Category</option>
<t t-foreach="category_list" t-as="cat">
<option t-att-value="cat[0]" t-att-selected="cat[0] == product.public_categ_id.id and 'selected'"><t t-esc="cat[1]"/></option>
</t>
</select>
<h2>Short Description for Quotations<br/><small>Displayed in your shop categories and for quotations</small></h2>
<div class="form-control" t-field="product.description_sale">Enter a short description for this product</div>
</div>
<div t-field="product.website_description">Enter a short Website description for this product</div>
<div>
<div class="pull-right">
<t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
<h5 class="text-error" style="text-decoration: line-through;" title="Price without reduction"><t t-field="product.product_variant_ids[0].lst_price" /> €</h5>
<h4><t t-esc="product.product_variant_ids[0].price" /> €</h4>
</t>
<h4 t-if="product.product_variant_ids[0].lst_price == product.product_variant_ids[0].price"><t t-field="product.product_variant_ids[0].lst_price" /> €</h4>
</div>
<img class="media-object img-responsive" t-att-src="product.img('image_medium')"/>
<div t-field="product.website_description">
<div class="container mt32"></div>
<div class="container" data-snippet-id="container">
Replace this text with your Website product description
</div>
<div class="container mt32"></div>
</div>
</div>
</t>
</t>
@@ -249,11 +247,11 @@
<th>Quantity</th>
</tr>
</thead>
<tbody t-if="not order or not order.order_line">
<tbody t-if="not website_sale_order or not website_sale_order.order_line">
<tr><td colspan="4"><h3>Your cart is empty</h3></td></tr>
</tbody>
<tbody t-if="order and order.order_line">
<t t-foreach="order.order_line" t-as="line">
<tbody t-if="website_sale_order and website_sale_order.order_line">
<t t-foreach="website_sale_order.order_line" t-as="line">
<tr>
<td colspan="2" t-if="not line.product_id.product_tmpl_id"></td>
<td t-if="line.product_id.product_tmpl_id">
@@ -288,12 +286,12 @@
<col width="160"/>
</colgroup>
<thead>
<tr> <th colspan="3">Subtotal </th> <th><t t-esc="order and order.amount_untaxed or 0"/> €</th></tr>
<tr> <th colspan="3">Taxes </th> <th><t t-esc="order and order.amount_tax or 0"/> €</th></tr>
<tr> <th colspan="3"><h4>Total</h4></th> <th><h4><t t-esc="order and order.amount_total or 0"/> €</h4></th></tr>
<tr> <th colspan="3">Subtotal </th> <th><t t-esc="website_sale_order and website_sale_order.amount_untaxed or 0"/> €</th></tr>
<tr> <th colspan="3">Taxes </th> <th><t t-esc="website_sale_order and website_sale_order.amount_tax or 0"/> €</th></tr>
<tr> <th colspan="3"><h4>Total</h4></th> <th><h4><t t-esc="website_sale_order and website_sale_order.amount_total or 0"/> €</h4></th></tr>
</thead>
</table>
<a t-if="order and order.order_line" href="/shop/checkout/" class="btn btn-success">Proceed To Payment</a>
<a t-if="website_sale_order and website_sale_order.order_line" href="/shop/checkout/" class="btn btn-success">Proceed To Payment</a>
</div>
</t>
</t>
@@ -353,8 +351,8 @@
</template>
<template id="reduction_code" inherit_option_id="website_sale.mycart" name="Reduction Code">
<xpath expr="//table[@id='mycart_total']" position="after">
<form t-if="order and order.order_line" class="well" action="/shop/mycart/" method="post">
<input name="promo" class='input' type="text" placeholder="Reduction Code..." t-att-value="order.pricelist_id.code or ''"/>
<form t-if="website_sale_order and website_sale_order.order_line" class="well" action="/shop/mycart/" method="post">
<input name="promo" class='input' type="text" placeholder="Reduction Code..." t-att-value="website_sale_order.pricelist_id.code or ''"/>
<button class="btn">Apply Code</button>
</form>
</xpath>
@@ -381,8 +379,8 @@
<th>Qty.</th>
</tr>
</thead>
<tbody t-if="order.order_line">
<t t-foreach="order.order_line" t-as="line">
<tbody t-if="website_sale_order.order_line">
<t t-foreach="website_sale_order.order_line" t-as="line">
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
@@ -391,15 +389,15 @@
</t>
</tbody>
<tfoot>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="order.amount_total"/> €</td></tr>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="website_sale_order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="website_sale_order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="website_sale_order.amount_total"/> €</td></tr>
</tfoot>
</table>
</div>
<form class="col-md-8 form-horizontal" action="/shop/confirm_order/" method="post">
<div class=" row">
<a t-if="not partner" t-attf-href="/admin#action=redirect&amp;url=#{ host_url }/shop/checkout/" class="btn btn-primary">Log me, I have an account</a>
<a t-if="not partner" t-attf-href="/admin#action=redirect&amp;url=#{ request.httprequest.host_url }/shop/checkout/" class="btn btn-primary">Log me, I have an account</a>
<h3 class="col-md-10">Billing Information</h3>
<div t-attf-class="form-group #{error.get('name') and 'has-error' or ''}">
<label class="col-lg-3 control-label" for="contact_name">Name and firstname</label>
@@ -567,8 +565,8 @@
<th>Qty.</th>
</tr>
</thead>
<tbody t-if="order.order_line">
<t t-foreach="order.order_line" t-as="line">
<tbody t-if="website_sale_order.order_line">
<t t-foreach="website_sale_order.order_line" t-as="line">
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
@@ -577,9 +575,9 @@
</t>
</tbody>
<tfoot>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="order.amount_total"/> €</td></tr>
<tr><th>Untaxed Amount</th><td></td><td><t t-esc="website_sale_order.amount_untaxed"/> €</td></tr>
<tr><th>Taxes</th><td></td><td><t t-esc="website_sale_order.amount_tax"/> €</td></tr>
<tr><th>Total</th><td></td><td><t t-esc="website_sale_order.amount_total"/> €</td></tr>
</tfoot>
</table>
</div>