[MERGE] from trunk

bzr revid: fva@openerp.com-20130819141108-s2vsjqdzzzlib4oi
This commit is contained in:
Frédéric van der Essen 2013-08-19 16:11:08 +02:00
commit 63dd1b0bb7
7 changed files with 442 additions and 470 deletions

View File

@ -15,13 +15,5 @@ OpenERP Website CMS
'views/views.xml',
'views/res_config.xml',
'website_data.xml',
],
'js': [
'static/lib/bootstrap/js/bootstrap.js',
'static/src/js/website.js',
],
'css': [
'static/src/css/editor.css',
],
'qweb': ['static/src/xml/*.xml'],
}

View File

@ -164,9 +164,6 @@ class Website(openerp.addons.web.controllers.main.Home):
etag = request.httprequest.headers.get('If-None-Match')
hashed_session = hashlib.md5(request.session_id).hexdigest()
retag = hashed_session
print Model.search(request.cr, request.uid, [(1,'=',1)])
try:
if etag:
date = Model.read(request.cr, request.uid, [id], [last_update], request.context)[0].get(last_update)

View File

@ -1,418 +1,47 @@
openerp.website = function(instance) {
instance.web.ActionManager.include({
// Temporary fix until un-webclientization of the editorbar
ir_actions_client: function (action) {
if (instance.web.client_actions.get_object(action.tag)) {
return this._super.apply(this, arguments);
} else {
console.warn("Action '%s' not found in registry", action.tag);
return $.when();
}
}
});
var _lt = instance.web._lt;
var QWeb = instance.web.qweb;
instance.website.EditorBar = instance.web.Widget.extend({
template: 'Website.EditorBar',
events: {
'click button[data-action=edit]': 'edit',
'click button[data-action=save]': 'save',
'click button[data-action=cancel]': 'cancel',
'click button[data-action=snippet]': 'snippet',
},
container: 'body',
init: function () {
this._super.apply(this, arguments);
this.saving_mutex = new $.Mutex();
},
customize_setup: function() {
var self = this;
var view_name = $('html').data('view-xmlid');
var menu = $('#customize-menu');
this.$('#customize-menu-button').click(function(event) {
menu.empty();
self.rpc('/website/customize_template_get', { 'xml_id': view_name }).then(
function(result) {
_.each(result, function (item) {
if (item.header) {
menu.append('<li class="nav-header">' + item.name + '</li>');
} else {
menu.append(_.str.sprintf('<li><a href="#" data-view-id="%s"><strong class="icon-check%s"></strong> %s</a></li>',
item.id, item.active ? '' : '-empty', item.name));
}
});
}
);
});
menu.on('click', 'a', function (event) {
var view_id = $(event.target).data('view-id');
self.rpc('/website/customize_template_toggle', {
'view_id': view_id
}).then( function(result) {
window.location.reload();
});
});
},
start: function() {
var self = this;
this.$('#website-top-edit').hide();
this.$('#website-top-view').show();
$('.dropdown-toggle').dropdown();
this.customize_setup();
this.$buttons = {
edit: this.$('button[data-action=edit]'),
save: this.$('button[data-action=save]'),
cancel: this.$('button[data-action=cancel]'),
snippet: this.$('button[data-action=snippet]'),
};
this.rte = new instance.website.RTE(this);
this.rte.on('change', this, this.proxy('rte_changed'));
this.snippets = new instance.website.Snippets();
this.snippets.appendTo($("body"));
return $.when(
this._super.apply(this, arguments),
this.rte.insertBefore(this.$buttons.snippet.parent())
);
},
edit: function () {
this.$buttons.edit.prop('disabled', true);
this.$('#website-top-view').hide();
this.$('#website-top-edit').show();
// this.$buttons.cancel.add(this.$buttons.snippet).prop('disabled', false)
// .add(this.$buttons.save)
// .parent().show();
//
// TODO: span edition changing edition state (save button)
var $editables = $('[data-oe-model]')
.not('link, script')
// FIXME: propagation should make "meta" blocks non-editable in the first place...
.not('.oe_snippet_editor')
.prop('contentEditable', true)
.addClass('oe_editable');
var $rte_ables = $editables.not('[data-oe-type]');
var $raw_editables = $editables.not($rte_ables);
// temporary fix until we fix ckeditor
$raw_editables.each(function () {
$(this).parents().add($(this).find('*')).on('click', function(ev) {
ev.preventDefault();
ev.stopPropagation();
});
});
this.rte.start_edition($rte_ables);
$raw_editables.on('keydown keypress cut paste', function (e) {
var $target = $(e.target);
if ($target.hasClass('oe_dirty')) {
return;
}
$target.addClass('oe_dirty');
this.$buttons.save.prop('disabled', false);
}.bind(this));
},
rte_changed: function () {
this.$buttons.save.prop('disabled', false);
},
save: function () {
var self = this;
var defs = [];
$('.oe_dirty').each(function (i, v) {
var $el = $(this);
// TODO: Add a queue with concurrency limit in webclient
// https://github.com/medikoo/deferred/blob/master/lib/ext/function/gate.js
var def = self.saving_mutex.exec(function () {
return self.saveElement($el).then(function () {
$el.removeClass('oe_dirty');
}).fail(function () {
var data = $el.data();
console.error(_.str.sprintf('Could not save %s#%d#%s', data.oeModel, data.oeId, data.oeField));
});
});
defs.push(def);
});
return $.when.apply(null, defs).then(function () {
window.location.reload();
});
},
saveElement: function ($el) {
var data = $el.data();
var html = $el.html();
var xpath = data.oeXpath;
if (xpath) {
var $w = $el.clone();
$w.removeClass('oe_dirty');
_.each(['model', 'id', 'field', 'xpath'], function(d) {$w.removeAttr('data-oe-' + d);});
$w
.removeClass('oe_editable')
.prop('contentEditable', false);
html = $w.wrap('<div>').parent().html();
}
return (new instance.web.DataSet(this, 'ir.ui.view')).call('save', [data.oeModel, data.oeId, data.oeField, html, xpath]);
},
cancel: function () {
window.location.reload();
},
snippet: function (ev) {
this.snippets.toggle();
},
});
instance.website.RTE = instance.web.Widget.extend({
tagName: 'li',
id: 'oe_rte_toolbar',
className: 'oe_right oe_rte_toolbar',
// editor.ui.items -> possible commands &al
// editor.applyStyle(new CKEDITOR.style({element: "span",styles: {color: "#(color)"},overrides: [{element: "font",attributes: {color: null}}]}, {color: '#ff0000'}));
start_edition: function ($elements) {
var self = this;
this.snippet_carousel();
$elements
.not('span, [data-oe-type]')
.each(function () {
var $this = $(this);
CKEDITOR.inline(this, self._config()).on('change', function () {
$this.addClass('oe_dirty');
self.trigger('change', this, null);
});
});
},
_current_editor: function () {
return CKEDITOR.currentInstance;
},
_config: function () {
var removed_plugins = [
// remove custom context menu
'contextmenu,tabletools,liststyle',
// magicline captures mousein/mouseout => draggable does not work
'magicline'
];
return {
// Disable auto-generated titles
// FIXME: accessibility, need to generate user-sensible title, used for @title and @aria-label
title: false,
removePlugins: removed_plugins.join(','),
uiColor: '',
// Ensure no config file is loaded
customConfig: '',
// Disable ACF
allowedContent: true,
// Don't insert paragraphs around content in e.g. <li>
autoParagraph: false,
filebrowserImageUploadUrl: "/website/attach",
// Support for sharedSpaces in 4.x
extraPlugins: 'sharedspace',
// Place toolbar in controlled location
sharedSpaces: { top: 'oe_rte_toolbar' },
toolbar: [
{name: 'basicstyles', items: [
"Bold", "Italic", "Underline", "Strike", "Subscript",
"Superscript", "TextColor", "BGColor", "RemoveFormat"
]},{
name: 'span', items: [
"Link", "Unlink", "Blockquote", "BulletedList",
"NumberedList", "Indent", "Outdent",
]},{
name: 'justify', items: [
"JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock"
]},{
name: 'special', items: [
"Image", "Table"
]},{
name: 'styles', items: [
"Format", "Styles"
]}
],
// styles dropdown in toolbar
stylesSet: [
// emphasis
{name: "Muted", element: 'span', attributes: {'class': 'text-muted'}},
{name: "Primary", element: 'span', attributes: {'class': 'text-primary'}},
{name: "Warning", element: 'span', attributes: {'class': 'text-warning'}},
{name: "Danger", element: 'span', attributes: {'class': 'text-danger'}},
{name: "Success", element: 'span', attributes: {'class': 'text-success'}},
{name: "Info", element: 'span', attributes: {'class': 'text-info'}}
],
};
},
// TODO clean
snippet_carousel: function () {
var self = this;
$('.carousel .js_carousel_options .label').on('click', function (e) {
e.preventDefault();
var $button = $(e.currentTarget);
var $c = $button.parents(".carousel:first");
if($button.hasClass("js_add")) {
var cycle = $c.find(".carousel-inner .item").size();
$c.find(".carousel-inner").append(QWeb.render("Website.Snipped.carousel"));
$c.carousel(cycle);
}
else {
var cycle = $c.find(".carousel-inner .item.active").remove();
$c.find(".carousel-inner .item:first").addClass("active");
$c.carousel(0);
self.trigger('change', self, null);
}
});
$('.carousel .js_carousel_options').show();
}
});
instance.website.Snippets = instance.web.Widget.extend({
template: 'website.snippets',
init: function () {
this._super.apply(this, arguments);
},
start: function() {
var self = this;
$.ajax({
type: "GET",
url: "/page/website.snippets",
dataType: "text",
success: function(text){
self.$el.html(text);
},
});
// load snippets
// /page/website.snippets
},
setup_droppable: function () {
var self = this;
$('.oe_snippet_drop').remove();
var droppable = '<div class="oe_snippet_drop"></div>';
var $zone = $(':not(.oe_snippet) > .container');
$zone.after(droppable);//.after(droppable);
$(".oe_snippet_drop").droppable({
hoverClass: 'oe_accepting',
drop: function( event, ui ) {
console.log(event, ui, "DROP");
$(event.target).replaceWith($(ui.draggable).html());
$('.oe_selected').remove();
$('.oe_snippet_drop').remove();
}
});
},
toggle: function(){
if(this.$el.hasClass('oe_hidden')){
this.$el.removeClass('oe_hidden');
}else{
this.$el.addClass('oe_hidden');
}
},
snippet_start: function () {
var self = this;
$('.oe_snippet').draggable().click(function(ev) {
self.setup_droppable();
$(".oe_snippet_drop").show();
$('.oe_selected').removeClass('oe_selected');
$(ev.currentTarget).addClass('oe_selected');
});
},
});
$(function(){
function make_static(){
$('.oe_snippet_demo').removeClass('oe_new');
$('.oe_page *').off('mouseover mouseleave');
$('.oe_page .oe_selected').removeClass('oe_selected');
// Ugly. I'll clean this monday
if ($('html').attr('data-editable') !== '1'){
return;
}
var selected_snippet = null;
function snippet_click(event){
if(selected_snippet){
selected_snippet.removeClass('oe_selected');
if(selected_snippet[0] === $(this)[0]){
selected_snippet = null;
event.preventDefault();
make_static();
return;
}
}
$(this).addClass('oe_selected');
selected_snippet = $(this);
make_editable();
event.preventDefault();
}
//$('.oe_snippet').click(snippet_click);
// TODO fme: put everything in openerp.website scope and load templates on
// next tick or document ready
// Also check with xmo if jquery.keypress.js is still needed.
var hover_element = null;
/* ----- TEMPLATE LOADING ---- */
function make_editable( constraint_after, constraint_inside ){
if(selected_snippet && selected_snippet.hasClass('oe_new')){
$('.oe_snippet_demo').addClass('oe_new');
}else{
$('.oe_snippet_demo').removeClass('oe_new');
}
$('.oe_page *').off('mouseover');
$('.oe_page *').off('mouseleave');
$('.oe_page *').mouseover(function(event){
console.log('hover:',this);
if(hover_element){
hover_element.removeClass('oe_selected');
hover_element.off('click');
}
$(this).addClass('oe_selected');
$(this).click(append_snippet);
hover_element = $(this);
event.stopPropagation();
});
$('.oe_page *').mouseleave(function(){
if(hover_element && $(this) === hover_element){
hover_element = null;
$(this).removeClass('oe_selected');
}
});
}
function customier_option_get(event){
event.preventDefault();
}
function append_snippet(event){
console.log('click',this,event.button);
if(event.button === 0){
if(selected_snippet){
if(selected_snippet.hasClass('oe_new')){
var new_snippet = $("<div class='oe_snippet'></div>");
new_snippet.append($(this).clone());
new_snippet.click(snippet_click);
$('.oe_snippet.oe_selected').before(new_snippet);
}else{
$(this).after($('.oe_snippet.oe_selected').contents().clone());
function loadTemplates(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();
}
}
selected_snippet.removeClass('oe_selected');
selected_snippet = null;
make_static();
}
}else if(event.button === 1){
$(this).remove();
}
event.preventDefault();
});
});
return def;
}
});
$(function () {
var templates = [
'/website/static/src/xml/website.xml'
];
loadTemplates(templates).then(function(){
var editor = new EditorBar();
editor.prependTo($('body'));
$('body').css('padding-top', '50px'); // Not working properly: editor.$el.outerHeight());
// TODO: Create an openerp.Widget out of this
});
/* ----- PUBLISHING STUFF ---- */
$(document).on('click', '.js_publish, .js_unpublish', function (e) {
e.preventDefault();
var $link = $(this).parent();
@ -429,6 +58,327 @@ $(function () {
}
});
});
/* ----- TOP EDITOR BAR FOR ADMIN ---- */
var EditorBar = openerp.Widget.extend({
template: 'Website.EditorBar',
events: {
'click button[data-action=edit]': 'edit',
'click button[data-action=save]': 'save',
'click button[data-action=cancel]': 'cancel',
'click button[data-action=snippet]': 'snippet',
},
container: 'body',
customize_setup: function() {
var self = this;
var view_name = $('html').data('view-xmlid');
var menu = $('#customize-menu');
this.$('#customize-menu-button').click(function(event) {
menu.empty();
openerp.jsonRpc('/website/customize_template_get', 'call', { 'xml_id': view_name }).then(
function(result) {
_.each(result, function (item) {
if (item.header) {
menu.append('<li class="nav-header">' + item.name + '</li>');
} else {
menu.append(_.str.sprintf('<li><a href="#" data-view-id="%s"><strong class="icon-check%s"></strong> %s</a></li>',
item.id, item.active ? '' : '-empty', item.name));
}
});
}
);
});
menu.on('click', 'a', function (event) {
var view_id = $(event.target).data('view-id');
openerp.jsonRpc('/website/customize_template_toggle', 'call', {
'view_id': view_id
}).then( function(result) {
window.location.reload();
});
});
},
start: function() {
var self = this;
this.saving_mutex = new openerp.Mutex();
this.$('#website-top-edit').hide();
this.$('#website-top-view').show();
$('.dropdown-toggle').dropdown();
this.customize_setup();
this.$buttons = {
edit: this.$('button[data-action=edit]'),
save: this.$('button[data-action=save]'),
cancel: this.$('button[data-action=cancel]'),
snippet: this.$('button[data-action=snippet]'),
};
this.rte = new RTE(this);
this.rte.on('change', this, this.proxy('rte_changed'));
this.snippets = new Snippets();
this.snippets.appendTo($("body"));
return $.when(
this._super.apply(this, arguments),
this.rte.insertBefore(this.$buttons.snippet.parent())
);
},
edit: function () {
this.$buttons.edit.prop('disabled', true);
this.$('#website-top-view').hide();
this.$('#website-top-edit').show();
// this.$buttons.cancel.add(this.$buttons.snippet).prop('disabled', false)
// .add(this.$buttons.save)
// .parent().show();
//
// TODO: span edition changing edition state (save button)
var $editables = $('[data-oe-model]')
.not('link, script')
// FIXME: propagation should make "meta" blocks non-editable in the first place...
.not('.oe_snippet_editor')
.prop('contentEditable', true)
.addClass('oe_editable');
var $rte_ables = $editables.not('[data-oe-type]');
var $raw_editables = $editables.not($rte_ables);
// temporary fix until we fix ckeditor
$raw_editables.each(function () {
$(this).parents().add($(this).find('*')).on('click', function(ev) {
ev.preventDefault();
ev.stopPropagation();
});
});
this.rte.start_edition($rte_ables);
$raw_editables.on('keydown keypress cut paste', function (e) {
var $target = $(e.target);
if ($target.hasClass('oe_dirty')) {
return;
}
$target.addClass('oe_dirty');
this.$buttons.save.prop('disabled', false);
}.bind(this));
},
rte_changed: function () {
this.$buttons.save.prop('disabled', false);
},
save: function () {
var self = this;
var defs = [];
$('.oe_dirty').each(function (i, v) {
var $el = $(this);
// TODO: Add a queue with concurrency limit in webclient
// https://github.com/medikoo/deferred/blob/master/lib/ext/function/gate.js
var def = self.saving_mutex.exec(function () {
return self.saveElement($el).then(function () {
$el.removeClass('oe_dirty');
}).fail(function () {
var data = $el.data();
console.error(_.str.sprintf('Could not save %s#%d#%s', data.oeModel, data.oeId, data.oeField));
});
});
defs.push(def);
});
return $.when.apply(null, defs).then(function () {
window.location.reload();
});
},
saveElement: function ($el) {
var data = $el.data();
var html = $el.html();
var xpath = data.oeXpath;
if (xpath) {
var $w = $el.clone();
$w.removeClass('oe_dirty');
_.each(['model', 'id', 'field', 'xpath'], function(d) {$w.removeAttr('data-oe-' + d);});
$w
.removeClass('oe_editable')
.prop('contentEditable', false);
html = $w.wrap('<div>').parent().html();
}
return openerp.jsonRpc('/web/dataset/call', 'call', {
model: 'ir.ui.view',
method: 'save',
args: [data.oeModel, data.oeId, data.oeField, html, xpath]
});
},
cancel: function () {
window.location.reload();
},
snippet: function (ev) {
this.snippets.toggle();
},
});
/* ----- RICH TEXT EDITOR ---- */
var RTE = openerp.Widget.extend({
tagName: 'li',
id: 'oe_rte_toolbar',
className: 'oe_right oe_rte_toolbar',
// editor.ui.items -> possible commands &al
// editor.applyStyle(new CKEDITOR.style({element: "span",styles: {color: "#(color)"},overrides: [{element: "font",attributes: {color: null}}]}, {color: '#ff0000'}));
start_edition: function ($elements) {
var self = this;
this.snippet_carousel();
$elements
.not('span, [data-oe-type]')
.each(function () {
var $this = $(this);
CKEDITOR.inline(this, self._config()).on('change', function () {
$this.addClass('oe_dirty');
self.trigger('change', this, null);
});
});
},
_current_editor: function () {
return CKEDITOR.currentInstance;
},
_config: function () {
var removed_plugins = [
// remove custom context menu
'contextmenu,tabletools,liststyle',
// magicline captures mousein/mouseout => draggable does not work
'magicline'
];
return {
// Disable auto-generated titles
// FIXME: accessibility, need to generate user-sensible title, used for @title and @aria-label
title: false,
removePlugins: removed_plugins.join(','),
uiColor: '',
// Ensure no config file is loaded
customConfig: '',
// Disable ACF
allowedContent: true,
// Don't insert paragraphs around content in e.g. <li>
autoParagraph: false,
filebrowserImageUploadUrl: "/website/attach",
// Support for sharedSpaces in 4.x
extraPlugins: 'sharedspace',
// Place toolbar in controlled location
sharedSpaces: { top: 'oe_rte_toolbar' },
toolbar: [
{name: 'basicstyles', items: [
"Bold", "Italic", "Underline", "Strike", "Subscript",
"Superscript", "TextColor", "BGColor", "RemoveFormat"
]},{
name: 'span', items: [
"Link", "Unlink", "Blockquote", "BulletedList",
"NumberedList", "Indent", "Outdent",
]},{
name: 'justify', items: [
"JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock"
]},{
name: 'special', items: [
"Image", "Table"
]},{
name: 'styles', items: [
"Format", "Styles"
]}
],
// styles dropdown in toolbar
stylesSet: [
// emphasis
{name: "Muted", element: 'span', attributes: {'class': 'text-muted'}},
{name: "Primary", element: 'span', attributes: {'class': 'text-primary'}},
{name: "Warning", element: 'span', attributes: {'class': 'text-warning'}},
{name: "Danger", element: 'span', attributes: {'class': 'text-danger'}},
{name: "Success", element: 'span', attributes: {'class': 'text-success'}},
{name: "Info", element: 'span', attributes: {'class': 'text-info'}}
],
};
},
// TODO clean
snippet_carousel: function () {
var self = this;
$('.carousel .js_carousel_options .label').on('click', function (e) {
e.preventDefault();
var $button = $(e.currentTarget);
var $c = $button.parents(".carousel:first");
if($button.hasClass("js_add")) {
var cycle = $c.find(".carousel-inner .item").size();
$c.find(".carousel-inner").append(QWeb.render("Website.Snipped.carousel"));
$c.carousel(cycle);
}
else {
var cycle = $c.find(".carousel-inner .item.active").remove();
$c.find(".carousel-inner .item:first").addClass("active");
$c.carousel(0);
self.trigger('change', self, null);
}
});
$('.carousel .js_carousel_options').show();
}
});
/* ----- SNIPPET SELECTOR ---- */
var Snippets = openerp.Widget.extend({
template: 'website.snippets',
init: function () {
this._super.apply(this, arguments);
},
start: function() {
var self = this;
$.ajax({
type: "GET",
url: "/page/website.snippets",
dataType: "text",
success: function(text){
self.$el.html(text);
},
});
// load snippets
// /page/website.snippets
},
setup_droppable: function () {
var self = this;
$('.oe_snippet_drop').remove();
var droppable = '<div class="oe_snippet_drop"></div>';
var $zone = $(':not(.oe_snippet) > .container');
$zone.after(droppable);//.after(droppable);
$(".oe_snippet_drop").droppable({
hoverClass: 'oe_accepting',
drop: function( event, ui ) {
console.log(event, ui, "DROP");
$(event.target).replaceWith($(ui.draggable).html());
$('.oe_selected').remove();
$('.oe_snippet_drop').remove();
}
});
},
toggle: function(){
if(this.$el.hasClass('oe_hidden')){
this.$el.removeClass('oe_hidden');
}else{
this.$el.addClass('oe_hidden');
}
},
snippet_start: function () {
var self = this;
$('.oe_snippet').draggable().click(function(ev) {
self.setup_droppable();
$(".oe_snippet_drop").show();
$('.oe_selected').removeClass('oe_selected');
$(ev.currentTarget).addClass('oe_selected');
});
},
});
});
};

View File

@ -1,19 +0,0 @@
$(function() {
// Init headless webclient
// TODO: Webclient research : use iframe embedding mode
// Meanwhile, let's HACK !!!
var s = new openerp.init(['web', 'website']);
s.web.WebClient.bind_hashchange = s.web.WebClient.show_common = s.web.blockUI = s.web.unblockUI = function() {};
s.web.WebClient.include({ do_push_state: function() {} });
var wc = new s.web.WebClient();
wc.start();
var instance = openerp.instances[wc.session.name];
// Another hack since we have no callback when webclient has loaded modules.
instance.web.qweb.add_template('/website/static/src/xml/website.xml');
$(function() {
var editor = new instance.website.EditorBar(instance.webclient);
editor.prependTo($('body'));
$('body').css('padding-top', '50px'); // Not working properly: editor.$el.outerHeight());
});
});

View File

@ -20,10 +20,13 @@
<template id="layout">
&lt;!DOCTYPE html&gt;
<html t-att-data-view-xmlid="__stack__[0]">
<html t-att-data-view-xmlid="__stack__[0]" t-att-data-editable="'1' if editable else '0'">
<head>
<title><t t-esc="title or res_company.name"/></title>
<script type="text/javascript" src="/web/static/lib/underscore/underscore.js"></script>
<script type="text/javascript" src="/web/static/lib/underscore.string/lib/underscore.string.js"></script>
<script type="text/javascript" src="/web/static/lib/jquery/jquery.js"></script>
<script type="text/javascript" src="/website/static/lib/bootstrap/js/bootstrap.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/ckeditor/4.2/ckeditor.js"></script>
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
<script type="text/javascript">
@ -33,11 +36,15 @@
</script>
<t t-if="editable">
<t t-raw="css"/>
<t t-raw="script"/>
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
<script type="text/javascript" src="/website/static/src/js/website_bootstrap.js"></script>
<link rel='stylesheet' href='/website/static/src/css/editor.css'/>
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
<script type="text/javascript" src="/web/static/lib/qweb/qweb2.js"></script>
<script type="text/javascript" src="/web/static/src/js/openerpframework.js"></script>
</t>
<script type="text/javascript" src="/website/static/src/js/website.js"></script>
<t t-raw="head or ''"/>
<t t-call="website.theme"/>
@ -280,6 +287,36 @@
</t>
</template>
<template id="500">
<t t-call="website.layout">
<div class="container">
<h1 class="mt32">500: Internal Server Error!</h1>
<pre t-esc="traceback"/>
</div>
</t>
</template>
<template id="401">
<t t-call="website.layout">
<div class="container">
<h1 class="mt32">401: Unauthorized Access!</h1>
<p>
The page you were looking for could not be
authorized.
</p><p>
Maybe you were looking for one of these
popular pages ?
</p>
<pre class="hidden" t-esc="error"/>
<ul>
<li><a href="/">Homepage</a></li>
<li><a href="/">Contact Us</a></li>
</ul>
</div>
</t>
</template>
<template id="contactus" name="Contact us">
<t t-call="website.layout">
<t t-set="title">Contact us - <t t-raw="res_company.name"/></t>

View File

@ -2,12 +2,16 @@
import simplejson
import openerp
from openerp.osv import osv
from openerp.osv import osv, orm
from openerp.addons.web import http
from openerp.addons.web.controllers import main
from openerp.addons.web.http import request
import urllib
import math
import traceback
import logging
logger = logging.getLogger(__name__)
def auth_method_public():
@ -42,11 +46,16 @@ class website(osv.osv):
def get_rendering_context(self, additional_values=None):
debug = 'debug' in request.params
is_logged = True
try:
request.session.check_security()
except: # TODO fme: check correct exception
is_logged = False
is_public_user = request.uid == self.get_public_user().id
values = {
'debug': debug,
'is_public_user': is_public_user,
'editable': not is_public_user,
'editable': is_logged and not is_public_user,
'request': request,
'registry': request.registry,
'cr': request.cr,
@ -55,11 +64,6 @@ class website(osv.osv):
'res_company': request.registry['res.company'].browse(request.cr, openerp.SUPERUSER_ID, 1),
'json': simplejson,
}
if values['editable']:
values.update({
'script': "\n".join(['<script type="text/javascript" src="%s"></script>' % i for i in main.manifest_list('js', db=request.db, debug=debug)]),
'css': "\n".join('<link rel="stylesheet" href="%s">' % i for i in main.manifest_list('css', db=request.db, debug=debug))
})
if additional_values:
values.update(additional_values)
return values
@ -68,7 +72,22 @@ class website(osv.osv):
context = {
'inherit_branding': values.get('editable', False),
}
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
try:
return request.registry.get("ir.ui.view").render(request.cr, request.uid, template, values, context=context)
except (osv.except_osv, orm.except_orm), err:
logger.error(err)
values['error'] = err[1]
return self.render('website.401', values)
except ValueError:
logger.error("Website Rendering Error.\n\n%s" % (traceback.format_exc()))
return self.render('website.404', values)
except Exception:
logger.error("Website Rendering Error.\n\n%s" % (traceback.format_exc()))
if values['editable']:
values['traceback'] = traceback.format_exc()
return self.render('website.500', values)
else:
return self.render('website.404', values)
def pager(self, url, total, page=1, step=30, scope=5, url_args=None):
# Compute Pager

View File

@ -49,7 +49,6 @@
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_sale/static/src/js/website_sale.js"></script>
<link rel='stylesheet' href='/website_sale/static/src/css/website_sale.css'/>
<t t-raw="head or ''"/>
</t>
<t t-set="title">Shop - <t t-raw="title">Categories</t></t>
@ -66,7 +65,7 @@
<xpath expr="//div[@id='shop_content']" position="before">
<div class="span4">
<ul class="nav nav-list">
<li t-att-class=" '' if current_category else 'active' " class='active'><a href='/shop/'>All Products</a></li>
<li t-att-class=" '' if current_category else 'active' " class='active'><a href="/shop/">All Products</a></li>
<t t-foreach="categories" t-as="category">
<t t-call="website_sale.categories_recursive"/>
</t>
@ -82,7 +81,7 @@
<template id="categories_recursive">
<li t-att-class="category.id == current_category and 'active' or ''">
<a t-att-href="'/shop/category/%%s/' %% category.id" t-field="category.name"></a>
<a t-attf-href="/shop/category/#{ category.id }/" t-field="category.name"></a>
<ul t-if="category.child_id" class="nav nav-list">
<t t-foreach="category.child_id" t-as="category">
<t t-call="website_sale.categories_recursive"/>
@ -108,18 +107,18 @@
</div>
</div>
<div class='row grid grid-align-top'>
<div t-foreach="products" t-as="product" class="oe_product span2 mb16 thumbnail text-center">
<a t-att-href="'/shop/product/%%s/' %% product.id">
<div t-foreach="products" t-as="product" class="span2 mb16 thumbnail text-center">
<a t-attf-href="/shop/product/#{ product.id }/ ">
<h5 t-field="product.name"> </h5>
</a>
<a t-att-href="'/shop/product/%%s/' %% product.id">
<a t-attf-href="/shop/product/#{ product.id }/">
<img class="img-rounded" t-att-src="product.img('image_small')"/>
</a>
<div>
<div t-field="product.description_sale"></div>
<div><span t-field="product.list_price"></span></div>
<div class="mb8 mt8">
<a t-att-href="'./add_cart/%s/' % product.id" class="btn btn-small btn-success">Add to cart</a>
<a t-attf-href="./add_cart/#{ product.id }/" class="btn btn-small btn-success">Add to cart</a>
</div>
</div>
</div>
@ -137,16 +136,13 @@
<t t-call="website_sale.layout">
<t t-set="title">Product</t>
<t t-set="shop_content">
<div class="oe_product_detail" id="product_detail">
<div id="product_detail">
<t t-call="website.publish"><t t-set="object" t-value="product"/></t>
<h2 t-field="product.name"></h2>
<div class="oe_button_cart">
<a t-att-href="'./add_cart/%s/' % product.id" class="btn btn-small btn-success">Add to cart</a>
</div>
<a t-attf-href="./add_cart/#{ product.id }/" class="btn btn-small btn-success pull-right">Add to cart</a>
<img class="media-object" t-att-src="product.img('image')"/>
<div t-field="product.description_website"></div>
<div class="oe_website_sale_price"><t t-field="product.list_price" /></div>
<div><t t-field="product.list_price" /></div>
</div>
</t>
</t>
@ -158,7 +154,7 @@
<div class='row mt16'>
<t t-foreach="product.recommended_products()" t-as="product">
<div class='span2 thumbnail'>
<a t-att-href="'/shop/product/%%s/' %% product.id">
<a t-attf-href="/shop/product/#{ product.id }/">
<div class='mt16 text-center'>
<img t-att-src="product.img('image_small')"/>
<h5 t-field='product.name'></h5>
@ -195,10 +191,10 @@
<t t-foreach="order.order_line" t-as="line">
<tr>
<td>
<a t-att-href="'/shop/product/%%s/' %% line.product_id"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
<a t-attf-href="/shop/product/#{ line.product_id.id }/"><img class="img-rounded" t-att-src="line.product_id.img('image_small')"/></a>
</td>
<td>
<a t-att-href="'/shop/product/%%s/' %% line.product_id"><span t-field="line.product_id.name"/></a><br/>
<a t-attf-href="/shop/product/#{ line.product_id.id }/"><span t-field="line.product_id.name"/></a><br/>
<small t-field="line.product_id.description_sale"/>
</td>
<td>
@ -241,7 +237,7 @@
<t t-set="title">Shop - Checkout</t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span4 oe_total">
<div class="span4">
<table class="table table-condensed">
<thead>
<tr>
@ -255,7 +251,7 @@
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td class="css_alignright"><t t-esc="line.product_id.list_price"/></td>
<td><t t-esc="line.product_id.list_price"/></td>
</tr>
</t>
</tbody>
@ -423,7 +419,7 @@
<t t-set="title">Shop - Payment</t>
<div class="container mt48 oe_website_sale">
<div class="row">
<div class="span4 oe_total">
<div class="span4">
<table class="table table-condensed">
<thead>
<tr>
@ -437,7 +433,7 @@
<tr>
<td><t t-esc="line.name"/></td>
<td><t t-esc="line.product_uom_qty"/></td>
<td class="css_alignright"><t t-esc="line.product_id.list_price"/></td>
<td><t t-esc="line.product_id.list_price"/></td>
</tr>
</t>
</tbody>
@ -449,7 +445,7 @@
</table>
</div>
<div class="span8">
<div class="js_payments row">
<div class="row">
<h3 class="span8">Click on your payment method</h3>
<t t-foreach="payments or []" t-as="payment">
<div t-att-title="payment.name">