[MERGE] from trunk
bzr revid: fva@openerp.com-20130819141108-s2vsjqdzzzlib4oi
This commit is contained in:
commit
63dd1b0bb7
|
@ -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'],
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
|
|
@ -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());
|
||||
});
|
||||
});
|
|
@ -20,10 +20,13 @@
|
|||
|
||||
<template id="layout">
|
||||
<!DOCTYPE html>
|
||||
<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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue