[MERGE] Merge parents

bzr revid: rim@openerp.com-20131105103727-8uy08rsv0be3x1mv
This commit is contained in:
Richard Mathot (OpenERP)
2013-11-05 11:37:27 +01:00
48 changed files with 1388 additions and 285 deletions
-1
View File
@@ -155,7 +155,6 @@
<field name="type" ref="event_type_4"/>
<field name="user_id" ref="base.user_root"/>
<field name="address_id" ref="base.res_partner_2"/>
<field name="organizer_id" ref="base.res_partner_address_4"/>
<field name="description"><![CDATA[
<div class="oe_structure">
<center><strong>5-days Technical Training</strong></center>
File diff suppressed because one or more lines are too long
+15 -7
View File
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
import base64
import cStringIO
import contextlib
import hashlib
@@ -49,7 +48,19 @@ MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT = IMAGE_LIMITS = (1024, 768)
class Website(openerp.addons.web.controllers.main.Home):
@website.route('/', type='http', auth="public", multilang=True)
def index(self, **kw):
return self.page("website.homepage")
# TODO: check if plain SQL is needed
menu = request.registry['website.menu']
root_domain = [('parent_id', '=', False)] # TODO: multiwebsite ('website_id', '=', request.website.id),
root_id = menu.search(request.cr, request.uid, root_domain, limit=1, context=request.context)[0]
first_menu = menu.search_read(
request.cr, request.uid, [('parent_id', '=', root_id)], ['url'],
limit=1, order='sequence', context=request.context)
if first_menu:
first_menu = first_menu[0]['url']
if first_menu and first_menu != '/':
return request.redirect(first_menu)
else:
return self.page("website.homepage")
@website.route('/pagenew/<path:path>', type='http', auth="user")
def pagenew(self, path, noredirect=NOPE):
@@ -124,11 +135,8 @@ class Website(openerp.addons.web.controllers.main.Home):
values = {
'path': path,
}
try:
html = request.website.render(path, values)
except ValueError:
html = request.website.render('website.404', values)
return html
return request.website.render(path, values)
@website.route('/website/customize_template_toggle', type='json', auth='user')
def customize_template_set(self, view_id):
+16
View File
@@ -8,6 +8,22 @@
<field name="default_lang_id" ref="base.lang_en"/>
</record>
<record id="main_menu" model="website.menu">
<field name="name">Main Menu</field>
</record>
<record id="menu_homepage" model="website.menu">
<field name="name">Homepage</field>
<field name="url">/</field>
<field name="parent_id" ref="website.main_menu"/>
</record>
<record id="menu_contactus" model="website.menu">
<field name="name">Contact us</field>
<field name="url">/page/website.contactus</field>
<field name="parent_id" ref="website.main_menu"/>
</record>
<record id="public_user" model="res.users">
<field name="name">public</field>
<field name="login">public</field>
+105 -17
View File
@@ -1,22 +1,25 @@
# -*- coding: utf-8 -*-
import fnmatch
import functools
import operator
import logging
import math
import simplejson
import openerp
from openerp.osv import osv, fields
from openerp.addons.web import http
from openerp.addons.web.http import request
import traceback
import urllib
from urlparse import urljoin
import math
import traceback
from openerp.tools.safe_eval import safe_eval
from openerp.exceptions import AccessError, AccessDenied
import werkzeug
from openerp.addons.base.ir.ir_qweb import QWebException
import logging
import werkzeug
import werkzeug.exceptions
import werkzeug.wrappers
import openerp
from openerp.exceptions import AccessError, AccessDenied
from openerp.osv import osv, fields
from openerp.tools.safe_eval import safe_eval
from openerp.addons.web import http
from openerp.addons.web.http import request
logger = logging.getLogger(__name__)
def route(routes, *route_args, **route_kwargs):
@@ -179,8 +182,7 @@ class website(osv.osv):
try:
view_ref = IMD.get_object_reference(cr, uid, module, xmlid)
except ValueError:
logger.error("Website Rendering Error.\n\n%s" % traceback.format_exc())
return self.render(cr, uid, ids, 'website.404', qweb_context)
return self.error(cr, uid, 404, qweb_context, context=context)
if 'main_object' not in qweb_context:
try:
@@ -197,15 +199,23 @@ class website(osv.osv):
logger.error(err)
qweb_context['error'] = err[1]
logger.warn("Website Rendering Error.\n\n%s" % traceback.format_exc())
return self.render(cr, uid, ids, 'website.401', qweb_context)
return self.error(cr, uid, 401, qweb_context, context=context)
except Exception, e:
qweb_context['template'] = getattr(e, 'qweb_template', '')
node = getattr(e, 'qweb_node', None)
qweb_context['node'] = node and node.toxml()
qweb_context['expr'] = getattr(e, 'qweb_eval', '')
qweb_context['traceback'] = traceback.format_exc()
logger.error("Website Rendering Error.\n%(template)s\n%(expr)s\n%(node)s\n\n%(traceback)s" % qweb_context)
return view.render(cr, uid, 'website.500' if qweb_context['editable'] else 'website.404', qweb_context, context=context)
logger.exception("Website Rendering Error.\n%(template)s\n%(expr)s\n%(node)s" % qweb_context)
return self.error(cr, uid, 500 if qweb_context['editable'] else 404,
qweb_context, context=context)
def error(self, cr, uid, code, qweb_context, context=None):
View = request.registry['ir.ui.view']
return werkzeug.wrappers.Response(
View.render(cr, uid, 'website.%d' % code, qweb_context),
status=code,
content_type='text/html;charset=utf-8')
def pager(self, cr, uid, ids, url, total, page=1, step=30, scope=5, url_args=None):
# Compute Pager
@@ -352,6 +362,75 @@ class website(osv.osv):
html += request.website.render(template, {'object_id': object_id})
return html
def get_menu_tree(self, cr, uid, ids, context=None):
return self.pool['website.menu'].get_tree(cr, uid, ids[0], context=context)
class website_menu(osv.osv):
_name = "website.menu"
_description = "Website Menu"
_columns = {
'name': fields.char('Menu', size=64, required=True, translate=True),
'url': fields.char('Url', required=True, translate=True),
'new_window': fields.boolean('New Window'),
'sequence': fields.integer('Sequence'),
# TODO: support multiwebsite once done for ir.ui.views
'website_id': fields.many2one('website', 'Website'),
'parent_id': fields.many2one('website.menu', 'Parent Menu', select=True, ondelete="cascade"),
'parent_left': fields.integer('Parent Left', select=True),
'parent_right': fields.integer('Parent Right', select=True),
}
_defaults = {
'url': '',
'sequence': 0,
}
_order = "parent_left"
# TODO: ormcache
def get_tree(self, cr, uid, website_id, fields=None, context=None):
if not fields:
fields = ['id', 'name', 'url', 'new_window', 'sequence', 'parent_id']
root_domain = [('parent_id', '=', False)] # ('website_id', '=', website_id),
root_menu_id = self.search(cr, uid, root_domain, limit=1, context=context)[0]
menu_ids = self.search(cr, uid, [('id', 'child_of', root_menu_id)], 0, False, False, context)
menu_items = self.read(cr, uid, menu_ids, fields, context=context)
menu_items_map = dict((menu_item["id"], menu_item) for menu_item in menu_items)
for menu_item in menu_items:
if menu_item['parent_id']:
parent = menu_item['parent_id'][0]
else:
parent = False
if parent in menu_items_map:
parent_obj = menu_items_map[parent]
parent_obj.setdefault('level', 0)
parent_obj.setdefault('children', []).append(menu_item)
menu_item['level'] = parent_obj['level'] + 1
# sort by sequence a tree using parent_id
for menu_item in menu_items:
menu_item.setdefault('children', []).sort(
key=operator.itemgetter('sequence'))
return menu_items[0]
def save(self, cr, uid, website_id, data, context=None):
def replace_id(old_id, new_id):
for menu in data['data']:
if menu['id'] == old_id:
menu['id'] = new_id
if menu['parent_id'] == old_id:
menu['parent_id'] = new_id
to_delete = data['to_delete']
if to_delete:
self.unlink(cr, uid, to_delete, context=context)
for menu in data['data']:
mid = menu['id']
if isinstance(mid, str):
new_id = self.create(cr, uid, {'name': menu['name']}, context=context)
replace_id(mid, new_id)
for menu in data['data']:
self.write(cr, uid, [menu['id']], menu, context=context)
return True
class ir_attachment(osv.osv):
_inherit = "ir.attachment"
def _website_url_get(self, cr, uid, ids, name, arg, context=None):
@@ -392,6 +471,15 @@ class res_partner(osv.osv):
}
return urlplus('https://maps.google.be/maps' , params)
class res_company(osv.osv):
_inherit = "res.company"
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
partner = self.browse(cr, openerp.SUPERUSER_ID, ids[0], context=context).parent_id
return partner and partner.google_map_img(zoom, width, height, context=context) or None
def google_map_link(self, cr, uid, ids, zoom=8, context=None):
partner = self.browse(cr, openerp.SUPERUSER_ID, ids[0], context=context).parent_id
return partner and partner.google_map_link(zoom, context=context) or None
class base_language_install(osv.osv):
_inherit = "base.language.install"
_columns = {
@@ -1,6 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_website_public,website,website.model_website,base.group_public,1,0,0,0
access_website,website,website.model_website,base.group_user,1,0,0,0
access_website_menu,access_website_menu,model_website_menu,,1,0,0,0
access_website_converter_test,access_website_converter_test,model_website_converter_test,,1,1,1,1
access_website_converter_test_sub,access_website_converter_test_sub,model_website_converter_test_sub,,1,1,1,1
access_website_qweb,access_website_qweb,model_website_qweb,,0,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_website_public website website.model_website base.group_public 1 0 0 0
3 access_website website website.model_website base.group_user 1 0 0 0
4 access_website_menu access_website_menu model_website_menu 1 0 0 0
5 access_website_converter_test access_website_converter_test model_website_converter_test 1 1 1 1
6 access_website_converter_test_sub access_website_converter_test_sub model_website_converter_test_sub 1 1 1 1
7 access_website_qweb access_website_qweb model_website_qweb 0 0 0 0
@@ -0,0 +1,429 @@
/*
* jQuery UI Nested Sortable
* v 1.3.5 / 21 jun 2012
* http://mjsarfatti.com/code/nestedSortable
*
* Depends on:
* jquery.ui.sortable.js 1.8+
*
* Copyright (c) 2010-2012 Manuele J Sarfatti
* Licensed under the MIT License
* http://www.opensource.org/licenses/mit-license.php
*/
(function($) {
$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
options: {
tabSize: 20,
disableNesting: 'mjs-nestedSortable-no-nesting',
errorClass: 'mjs-nestedSortable-error',
doNotClear: false,
listType: 'ol',
maxLevels: 0,
protectRoot: false,
rootID: null,
rtl: false,
isAllowed: function(item, parent) { return true; }
},
_create: function() {
this.element.data('sortable', this.element.data('nestedSortable'));
if (!this.element.is(this.options.listType))
throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
return $.ui.sortable.prototype._create.apply(this, arguments);
},
destroy: function() {
this.element
.removeData("nestedSortable")
.unbind(".nestedSortable");
return $.ui.sortable.prototype.destroy.apply(this, arguments);
},
_mouseDrag: function(event) {
//Compute the helpers position
this.position = this._generatePosition(event);
this.positionAbs = this._convertPositionTo("absolute");
if (!this.lastPositionAbs) {
this.lastPositionAbs = this.positionAbs;
}
var o = this.options;
//Do scrolling
if(this.options.scroll) {
var scrolled = false;
if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
} else {
if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
}
if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
$.ui.ddmanager.prepareOffsets(this, event);
}
//Regenerate the absolute position used for position checks
this.positionAbs = this._convertPositionTo("absolute");
// Find the top offset before rearrangement,
var previousTopOffset = this.placeholder.offset().top;
//Set the helper position
if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
//Rearrange
for (var i = this.items.length - 1; i >= 0; i--) {
//Cache variables and intersection, continue if no intersection
var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
if (!intersection) continue;
if(itemElement != this.currentItem[0] //cannot intersect with itself
&& this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
&& !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
) {
$(itemElement).mouseenter();
this.direction = intersection == 1 ? "down" : "up";
if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
$(itemElement).mouseleave();
this._rearrange(event, item);
} else {
break;
}
// Clear emtpy ul's/ol's
this._clearEmpty(itemElement);
this._trigger("change", event, this._uiHash());
break;
}
}
var parentItem = (this.placeholder[0].parentNode.parentNode &&
$(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
? $(this.placeholder[0].parentNode.parentNode)
: null,
level = this._getLevel(this.placeholder),
childLevels = this._getChildLevels(this.helper);
// To find the previous sibling in the list, keep backtracking until we hit a valid list item.
var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
if (previousItem != null) {
while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
if (previousItem[0].previousSibling) {
previousItem = $(previousItem[0].previousSibling);
} else {
previousItem = null;
break;
}
}
}
// To find the next sibling in the list, keep stepping forward until we hit a valid list item.
var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
if (nextItem != null) {
while (nextItem[0].nodeName.toLowerCase() != 'li' || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
if (nextItem[0].nextSibling) {
nextItem = $(nextItem[0].nextSibling);
} else {
nextItem = null;
break;
}
}
}
var newList = document.createElement(o.listType);
this.beyondMaxLevels = 0;
// If the item is moved to the left, send it to its parent's level unless there are siblings below it.
if (parentItem != null && nextItem == null &&
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
!o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
parentItem.after(this.placeholder[0]);
this._clearEmpty(parentItem[0]);
this._trigger("change", event, this._uiHash());
}
// If the item is below a sibling and is moved to the right, make it a child of that sibling.
else if (previousItem != null &&
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
!o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
this._isAllowed(previousItem, level, level+childLevels+1);
if (!previousItem.children(o.listType).length) {
previousItem[0].appendChild(newList);
}
// If this item is being moved from the top, add it to the top of the list.
if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
previousItem.children(o.listType).prepend(this.placeholder);
}
// Otherwise, add it to the bottom of the list.
else {
previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
}
this._trigger("change", event, this._uiHash());
}
else {
this._isAllowed(parentItem, level, level+childLevels);
}
//Post events to containers
this._contactContainers(event);
//Interconnect with droppables
if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
//Call callbacks
this._trigger('sort', event, this._uiHash());
this.lastPositionAbs = this.positionAbs;
return false;
},
_mouseStop: function(event, noPropagation) {
// If the item is in a position not allowed, send it back
if (this.beyondMaxLevels) {
this.placeholder.removeClass(this.options.errorClass);
if (this.domPosition.prev) {
$(this.domPosition.prev).after(this.placeholder);
} else {
$(this.domPosition.parent).prepend(this.placeholder);
}
this._trigger("revert", event, this._uiHash());
}
// Clean last empty ul/ol
for (var i = this.items.length - 1; i >= 0; i--) {
var item = this.items[i].item[0];
this._clearEmpty(item);
}
$.ui.sortable.prototype._mouseStop.apply(this, arguments);
},
serialize: function(options) {
var o = $.extend({}, this.options, options),
items = this._getItemsAsjQuery(o && o.connected),
str = [];
$(items).each(function() {
var res = ($(o.item || this).attr(o.attribute || 'id') || '')
.match(o.expression || (/(.+)[-=_](.+)/)),
pid = ($(o.item || this).parent(o.listType)
.parent(o.items)
.attr(o.attribute || 'id') || '')
.match(o.expression || (/(.+)[-=_](.+)/));
if (res) {
str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
+ '='
+ (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
}
});
if(!str.length && o.key) {
str.push(o.key + '=');
}
return str.join('&');
},
toHierarchy: function(options) {
var o = $.extend({}, this.options, options),
sDepth = o.startDepthCount || 0,
ret = [];
$(this.element).children(o.items).each(function () {
var level = _recursiveItems(this);
ret.push(level);
});
return ret;
function _recursiveItems(item) {
var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
if (id) {
var currentItem = {"id" : id[2]};
if ($(item).children(o.listType).children(o.items).length > 0) {
currentItem.children = [];
$(item).children(o.listType).children(o.items).each(function() {
var level = _recursiveItems(this);
currentItem.children.push(level);
});
}
return currentItem;
}
}
},
toArray: function(options) {
var o = $.extend({}, this.options, options),
sDepth = o.startDepthCount || 0,
ret = [],
left = 2;
ret.push({
"item_id": o.rootID,
"parent_id": 'none',
"depth": sDepth,
"left": '1',
"right": ($(o.items, this.element).length + 1) * 2
});
$(this.element).children(o.items).each(function () {
left = _recursiveArray(this, sDepth + 1, left);
});
ret = ret.sort(function(a,b){ return (a.left - b.left); });
return ret;
function _recursiveArray(item, depth, left) {
var right = left + 1,
id,
pid;
if ($(item).children(o.listType).children(o.items).length > 0) {
depth ++;
$(item).children(o.listType).children(o.items).each(function () {
right = _recursiveArray($(this), depth, right);
});
depth --;
}
id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
if (depth === sDepth + 1) {
pid = o.rootID;
} else {
var parentItem = ($(item).parent(o.listType)
.parent(o.items)
.attr(o.attribute || 'id'))
.match(o.expression || (/(.+)[-=_](.+)/));
pid = parentItem[2];
}
if (id) {
ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
}
left = right + 1;
return left;
}
},
_clearEmpty: function(item) {
var emptyList = $(item).children(this.options.listType);
if (emptyList.length && !emptyList.children().length && !this.options.doNotClear) {
emptyList.remove();
}
},
_getLevel: function(item) {
var level = 1;
if (this.options.listType) {
var list = item.closest(this.options.listType);
while (list && list.length > 0 &&
!list.is('.ui-sortable')) {
level++;
list = list.parent().closest(this.options.listType);
}
}
return level;
},
_getChildLevels: function(parent, depth) {
var self = this,
o = this.options,
result = 0;
depth = depth || 0;
$(parent).children(o.listType).children(o.items).each(function (index, child) {
result = Math.max(self._getChildLevels(child, depth + 1), result);
});
return depth ? result + 1 : result;
},
_isAllowed: function(parentItem, level, levels) {
var o = this.options,
isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false,
maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
// Is the root protected?
// Are we trying to nest under a no-nest?
// Are we nesting too deep?
if (!o.isAllowed(this.currentItem, parentItem) ||
parentItem && parentItem.hasClass(o.disableNesting) ||
o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
this.placeholder.addClass(o.errorClass);
if (maxLevels < levels && maxLevels != 0) {
this.beyondMaxLevels = levels - maxLevels;
} else {
this.beyondMaxLevels = 1;
}
} else {
if (maxLevels < levels && maxLevels != 0) {
this.placeholder.addClass(o.errorClass);
this.beyondMaxLevels = levels - maxLevels;
} else {
this.placeholder.removeClass(o.errorClass);
this.beyondMaxLevels = 0;
}
}
}
}));
$.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
})(jQuery);
+79 -1
View File
@@ -114,7 +114,7 @@ table.editorbar-panel td.selected {
.oe_translate_or {
color: white;
padding: 0 0.2em;
padding: 0 0 0 1em;
}
.oe_translate_examples li {
@@ -142,6 +142,84 @@ table.editorbar-panel td.selected {
background: #ffffb6;
}
div.oe_menu_buttons {
top: -8px;
right: -8px;
}
ul.oe_menu_editor > li:first-child > div > i:before {
content: "\f015";
}
ul.oe_menu_editor, ul.oe_menu_editor ul {
list-style-type: none;
margin: 0;
padding: 0;
}
ul.oe_menu_editor ul {
padding-left: 30px;
}
ul.oe_menu_editor button {
margin-left: 4px;
}
ul.oe_menu_editor li {
margin: 5px 0 0 0;
padding: 0;
}
ul.oe_menu_editor .oe_menu_placeholder {
outline: 1px dashed #4183c4;
}
ul.oe_menu_editor .mjs-nestedSortable-error {
background: #fbe3e4;
border-color: transparent;
}
ul.oe_menu_editor li div {
border: 1px solid #d4d4d4;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
border-color: #d4d4d4 #d4d4d4 #bcbcbc;
padding: 6px;
margin: 0;
cursor: move;
background: #f6f6f6;
background: -moz-linear-gradient(top, white 0%, #f6f6f6 47%, #ededed 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(47%, #f6f6f6), color-stop(100%, #ededed));
background: -webkit-linear-gradient(top, white 0%, #f6f6f6 47%, #ededed 100%);
background: -o-linear-gradient(top, white 0%, #f6f6f6 47%, #ededed 100%);
background: -ms-linear-gradient(top, white 0%, #f6f6f6 47%, #ededed 100%);
background: linear-gradient(to bottom, #ffffff 0%, #f6f6f6 47%, #ededed 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed',GradientType=0 );
}
ul.oe_menu_editor li.mjs-nestedSortable-branch div {
background: -moz-linear-gradient(top, white 0%, #f6f6f6 47%, #f0ece9 100%);
background: -webkit-linear-gradient(top, white 0%, #f6f6f6 47%, #f0ece9 100%);
}
ul.oe_menu_editor li.mjs-nestedSortable-leaf div {
background: -moz-linear-gradient(top, white 0%, #f6f6f6 47%, #bcccbc 100%);
background: -webkit-linear-gradient(top, white 0%, #f6f6f6 47%, #bcccbc 100%);
}
ul.oe_menu_editor li.mjs-nestedSortable-collapsed.mjs-nestedSortable-hovering div {
border-color: #999999;
background: #fafafa;
}
ul.oe_menu_editor .disclose {
cursor: pointer;
width: 10px;
display: none;
}
ul.oe_menu_editor li.mjs-nestedSortable-collapsed > ul {
display: none;
}
ul.oe_menu_editor li.mjs-nestedSortable-branch > div > .disclose {
display: inline-block;
}
ul.oe_menu_editor li.mjs-nestedSortable-collapsed > div > .disclose > span:before {
content: "+ ";
}
ul.oe_menu_editor li.mjs-nestedSortable-expanded > div > .disclose > span:before {
content: "- ";
}
/* ---- RTE ---- */
.oe_editable .btn {
-webkit-user-select: auto;
+79 -1
View File
@@ -108,7 +108,7 @@ table.editorbar-panel
// ---- TRANSLATIONS ---- {{{
.oe_translate_or
color: white
padding: 0 0.2em
padding: 0 0 0 1em
.oe_translate_examples li
margin: 10px
padding: 4px
@@ -124,6 +124,84 @@ table.editorbar-panel
background: rgb(255, 255, 182)
// }}}
// -------- MENU -------- {{{
div.oe_menu_buttons
top: -8px
right: -8px
ul.oe_menu_editor
> li:first-child > div > i:before
content: "\f015"
&, & ul
list-style-type: none
margin: 0
padding: 0
& ul
padding-left: 30px
button
margin-left: 4px
li
margin: 5px 0 0 0
padding: 0
.oe_menu_placeholder
outline: 1px dashed #4183C4
.mjs-nestedSortable-error
background: #fbe3e4
border-color: transparent
// TODO: use compass mixins
li div
border: 1px solid #d4d4d4
-webkit-border-radius: 3px
-moz-border-radius: 3px
border-radius: 3px
border-color: #D4D4D4 #D4D4D4 #BCBCBC
padding: 6px
margin: 0
cursor: move
background: #f6f6f6
background: -moz-linear-gradient(top, #ffffff 0%, #f6f6f6 47%, #ededed 100%)
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(47%,#f6f6f6), color-stop(100%,#ededed))
background: -webkit-linear-gradient(top, #ffffff 0%,#f6f6f6 47%,#ededed 100%)
background: -o-linear-gradient(top, #ffffff 0%,#f6f6f6 47%,#ededed 100%)
background: -ms-linear-gradient(top, #ffffff 0%,#f6f6f6 47%,#ededed 100%)
background: linear-gradient(to bottom, #ffffff 0%,#f6f6f6 47%,#ededed 100%)
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ededed',GradientType=0 )
li.mjs-nestedSortable-branch div
background: -moz-linear-gradient(top, #ffffff 0%, #f6f6f6 47%, #f0ece9 100%)
background: -webkit-linear-gradient(top, #ffffff 0%,#f6f6f6 47%,#f0ece9 100%)
li.mjs-nestedSortable-leaf div
background: -moz-linear-gradient(top, #ffffff 0%, #f6f6f6 47%, #bcccbc 100%)
background: -webkit-linear-gradient(top, #ffffff 0%,#f6f6f6 47%,#bcccbc 100%)
li.mjs-nestedSortable-collapsed.mjs-nestedSortable-hovering div
border-color: #999
background: #fafafa
.disclose
cursor: pointer
width: 10px
display: none
li.mjs-nestedSortable-collapsed > ul
display: none
li.mjs-nestedSortable-branch > div > .disclose
display: inline-block
li.mjs-nestedSortable-collapsed > div > .disclose > span:before
content: '+ '
li.mjs-nestedSortable-expanded > div > .disclose > span:before
content: '- '
// }}}
/* ---- RTE ---- */
// bootstrap makes .btn elements unselectable -> RTE double-click can't know
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+1 -1
View File
@@ -6,7 +6,7 @@
var hash = "#advanced-view-editor";
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.ace.xml');
website.add_template_file('/website/static/src/xml/website.ace.xml');
website.ready().then(function () {
if (window.location.hash.indexOf(hash) >= 0) {
+104 -86
View File
@@ -4,7 +4,7 @@
var website = openerp.website;
// $.fn.data automatically parses value, '0'|'1' -> 0|1
website.templates.push('/website/static/src/xml/website.editor.xml');
website.add_template_file('/website/static/src/xml/website.editor.xml');
website.dom_ready.done(function () {
var is_smartphone = $(document.body)[0].clientWidth < 767;
@@ -14,7 +14,7 @@
});
function link_dialog(editor) {
return new website.editor.LinkDialog(editor).appendTo(document.body);
return new website.editor.RTELinkDialog(editor).appendTo(document.body);
}
function image_dialog(editor) {
return new website.editor.RTEImageDialog(editor).appendTo(document.body);
@@ -805,6 +805,106 @@
this.pages = Object.create(null);
this.text = null;
},
start: function () {
var self = this;
return $.when(
this.fetch_pages().done(this.proxy('fill_pages')),
this._super()
).done(function () {
self.bind_data();
});
},
save: function () {
var self = this, _super = this._super.bind(this);
var $e = this.$('.list-group-item.active .url-source');
var val = $e.val();
if (!val || !$e[0].checkValidity()) {
// FIXME: error message
$e.closest('.form-group').addClass('has-error');
$e.focus();
return;
}
var done = $.when();
if ($e.hasClass('email-address')) {
this.make_link('mailto:' + val, false, val);
} else if ($e.hasClass('existing')) {
self.make_link(val, false, this.pages[val]);
} else if ($e.hasClass('pages')) {
// Create the page, get the URL back
done = $.get(_.str.sprintf(
'/pagenew/%s?noredirect', encodeURI(val)))
.then(function (response) {
self.make_link(response, false, val);
});
} else {
this.make_link(val, this.$('input.window-new').prop('checked'));
}
done.then(_super);
},
make_link: function (url, new_window, label) {
},
bind_data: function (text, href, new_window) {
href = href || this.element && (this.element.data( 'cke-saved-href')
|| this.element.getAttribute('href'));
if (!href) { return; }
if (new_window === undefined) {
new_window = this.element.getAttribute('target') === '_blank';
}
if (text === undefined) {
text = this.element.getText();
}
var match, $control;
if ((match = /mailto:(.+)/.exec(href))) {
$control = this.$('input.email-address').val(match[1]);
} else if (href in this.pages) {
$control = this.$('select.existing').val(href);
} else if ((match = /\/page\/(.+)/.exec(href))) {
var actual_href = '/page/website.' + match[1];
if (actual_href in this.pages) {
$control = this.$('select.existing').val(actual_href);
}
}
if (!$control) {
$control = this.$('input.url').val(href);
}
this.changed($control);
this.$('input#link-text').val(text);
this.$('input.window-new').prop('checked', new_window);
},
changed: function ($e) {
this.$('.url-source').not($e).val('');
$e.closest('.list-group-item')
.addClass('active')
.siblings().removeClass('active')
.addBack().removeClass('has-error');
},
fetch_pages: function () {
return openerp.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'website',
method: 'list_pages',
args: [null],
kwargs: {
context: website.get_context()
},
});
},
fill_pages: function (results) {
var self = this;
var pages = this.$('select.existing')[0];
_(results).each(function (result) {
self.pages[result.url] = result.name;
pages.options[pages.options.length] =
new Option(result.name, result.url);
});
},
});
website.editor.RTELinkDialog = website.editor.LinkDialog.extend({
start: function () {
var element;
if ((element = this.get_selected_link()) && element.hasAttribute('href')) {
@@ -815,10 +915,7 @@
this.add_removal_button();
}
return $.when(
this.fetch_pages().done(this.proxy('fill_pages')),
this._super()
).done(this.proxy('bind_data'));
return this._super();
},
add_removal_button: function () {
this.$('.modal-footer').prepend(
@@ -884,66 +981,6 @@
}, 0);
}
},
save: function () {
var self = this, _super = this._super.bind(this);
var $e = this.$('.list-group-item.active .url-source');
var val = $e.val();
if (!val || !$e[0].checkValidity()) {
// FIXME: error message
$e.closest('.form-group').addClass('has-error');
return;
}
var done = $.when();
if ($e.hasClass('email-address')) {
this.make_link('mailto:' + val, false, val);
} else if ($e.hasClass('existing')) {
self.make_link(val, false, this.pages[val]);
} else if ($e.hasClass('pages')) {
// Create the page, get the URL back
done = $.get(_.str.sprintf(
'/pagenew/%s?noredirect', encodeURI(val)))
.then(function (response) {
self.make_link(response, false, val);
});
} else {
this.make_link(val, this.$('input.window-new').prop('checked'));
}
done.then(_super);
},
bind_data: function () {
var href = this.element && (this.element.data( 'cke-saved-href')
|| this.element.getAttribute('href'));
if (!href) { return; }
var match, $control;
if (match = /mailto:(.+)/.exec(href)) {
$control = this.$('input.email-address').val(match[1]);
} else if (href in this.pages) {
$control = this.$('select.existing').val(href);
} else if (match = /\/page\/(.+)/.exec(href)) {
var actual_href = '/page/website.' + match[1];
if (actual_href in this.pages) {
$control = this.$('select.existing').val(actual_href);
}
}
if (!$control) {
$control = this.$('input.url').val(href);
}
this.changed($control);
this.$('input#link-text').val(this.element.getText());
this.$('input.window-new').prop(
'checked', this.element.getAttribute('target') === '_blank');
},
changed: function ($e) {
this.$('.url-source').not($e).val('');
$e.closest('.list-group-item')
.addClass('active')
.siblings().removeClass('active')
.addBack().removeClass('has-error');
},
/**
* CKEDITOR.plugins.link.getSelectedLink ignores the editor's root,
* if the editor is set directly on a link it will thus not work.
@@ -951,27 +988,8 @@
get_selected_link: function () {
return get_selected_link(this.editor);
},
fetch_pages: function () {
return openerp.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'website',
method: 'list_pages',
args: [null],
kwargs: {
context: website.get_context()
},
});
},
fill_pages: function (results) {
var self = this;
var pages = this.$('select.existing')[0];
_(results).each(function (result) {
self.pages[result.url] = result.name;
pages.options[pages.options.length] =
new Option(result.name, result.url);
});
},
});
/**
* ImageDialog widget. Lets users change an image, including uploading a
* new image in OpenERP or selecting the image style (if supported by
+38 -26
View File
@@ -5,35 +5,30 @@
// The following line can be removed in 2017
openerp.website = website;
var templates = website.templates = [
'/website/static/src/xml/website.xml'
];
website.get_context = function (dict) {
var html = document.documentElement;
return _.extend({
lang: html.getAttribute('lang').replace('-', '_')
lang: html.getAttribute('lang').replace('-', '_'),
website_id: html.getAttribute('data-website-id')|0
}, dict);
};
/* ----- TEMPLATE LOADING ---- */
website.add_template = function(template) {
templates.push(template);
};
website.load_templates = function(templates) {
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();
}
});
var templates_def = $.Deferred().resolve();
website.add_template_file = function(template) {
templates_def = templates_def.then(function() {
var def = $.Deferred();
openerp.qweb.add_template(template, function(err) {
if (err) {
def.reject(err);
} else {
def.resolve();
}
});
return def;
});
return $.when.apply(null, dones);
};
website.add_template_file('/website/static/src/xml/website.xml');
website.reload = function () {
location.hash = "scrollTop=" + window.document.body.scrollTop;
if (location.search.indexOf("enable_editor") > -1) {
@@ -110,20 +105,33 @@
*/
website.ready = function() {
if (!all_ready) {
var tpl = website.load_templates(templates);
all_ready = dom_ready.then(function () {
all_ready = $.when(dom_ready, templates_def).then(function () {
if ($('html').data('editable')) {
website.id = $('html').data('website-id');
website.session = new openerp.Session();
var modules = ['website'];
return openerp._t.database.load_translations(website.session, modules, website.get_context().lang);
}
}).then(tpl).promise();
}).promise();
}
return all_ready;
};
website.error = function(data, url) {
var $error = $(openerp.qweb.render('website.error_dialog', {
'title': data.data ? data.data.arguments[0] : data.statusText,
'message': data.data ? data.data.arguments[1] : "",
'backend_url': url
}));
$error.appendTo("body");
$error.modal('show');
};
dom_ready.then(function () {
/* ----- BOOTSTRAP STUFF ---- */
$('.js_tooltip').bstooltip();
/* ----- PUBLISHING STUFF ---- */
$('[data-publish]:has(.js_publish)').each(function () {
var $pub = $("[data-publish]", this);
@@ -140,11 +148,13 @@
$(document).on('click', '.js_publish', function (e) {
e.preventDefault();
var $data = $(":first", this).parents("[data-publish]");
$data.attr("data-publish", $data.first().attr("data-publish") == 'off' ? 'on' : 'off');
openerp.jsonRpc('/website/publish', 'call', {'id': $(this).data('id'), 'object': $(this).data('object')})
var $a = $(this);
var $data = $a.find(":first").parents("[data-publish]");
openerp.jsonRpc($a.data('controller') || '/website/publish', 'call', {'id': +$a.data('id'), 'object': $a.data('object')})
.then(function (result) {
$data.attr("data-publish", +result ? 'on' : 'off');
}).fail(function (err, data) {
website.error(data, '/web#model='+$a.data('object')+'&id='+$a.data('id'));
});
});
@@ -156,11 +166,13 @@
$data.toggleClass("css_unpublish css_publish");
$btn.removeClass("btn-default btn-success");
openerp.jsonRpc('/website/publish', 'call', {'id': +$data.data('id'), 'object': $data.data('object')})
openerp.jsonRpc($data.data('controller') || '/website/publish', 'call', {'id': +$data.data('id'), 'object': $data.data('object')})
.then(function (result) {
$btn.toggleClass("btn-default", !result).toggleClass("btn-success", result);
$data.toggleClass("css_unpublish", !result).toggleClass("css_publish", result);
$data.parents("[data-publish]").attr("data-publish", +result ? 'on' : 'off');
}).fail(function (err, data) {
website.error(data, '/web#model='+$data.data('object')+'&id='+$data.data('id'));
});
});
@@ -0,0 +1,193 @@
(function () {
'use strict';
var website = openerp.website;
website.menu = {};
website.add_template_file('/website/static/src/xml/website.menu.xml');
website.EditorBar.include({
events: _.extend({}, website.EditorBar.prototype.events, {
'click a[data-action="edit-structure"]': 'editStructure',
}),
editStructure: function () {
var context = website.get_context();
openerp.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'website.menu',
method: 'get_tree',
args: [[context.website_id]],
kwargs: {
context: context
},
}).then(function (menu) {
return new website.menu.EditMenuDialog(menu).appendTo(document.body);
});
},
});
website.menu.EditMenuDialog = website.editor.Dialog.extend({
template: 'website.menu.dialog.edit',
events: _.extend({}, website.editor.Dialog.prototype.events, {
'click button.js_add_menu': 'add_menu',
'click button.js_edit_menu': 'edit_menu',
'click button.js_delete_menu': 'delete_menu',
}),
init: function (menu) {
this.menu = menu;
this.root_menu_id = menu.id;
this.flat = this.flatenize(menu);
this.to_delete = [];
this._super();
},
start: function () {
var r = this._super.apply(this, arguments);
var button = openerp.qweb.render('website.menu.dialog.footer-button');
this.$('.modal-footer').prepend(button);
this.$('.oe_menu_editor').nestedSortable({
listType: 'ul',
handle: 'div',
items: 'li',
maxLevels: 2,
toleranceElement: '> div',
forcePlaceholderSize: true,
opacity: 0.6,
placeholder: 'oe_menu_placeholder',
tolerance: 'pointer',
attribute: 'data-menu-id',
expression: '()(.+)', // nestedSortable takes the second match of an expression (*sigh*)
});
return r;
},
flatenize: function (node, dict) {
dict = dict || {};
var self = this;
dict[node.id] = node;
node.children.forEach(function (child) {
self.flatenize(child, dict);
});
return dict;
},
add_menu: function () {
var self = this;
var dialog = new website.menu.MenuEntryDialog();
dialog.on('add-menu', this, function (link) {
var new_menu = {
id: _.uniqueId('new-'),
name: link[2] || link[0],
url: link[0],
new_window: link[1],
parent_id: false,
sequence: 0,
children: [],
};
self.flat[new_menu.id] = new_menu;
self.$('.oe_menu_editor').append(
openerp.qweb.render(
'website.menu.dialog.submenu', { submenu: new_menu }));
});
dialog.appendTo(document.body);
},
edit_menu: function (ev) {
var self = this;
var menu_id = $(ev.currentTarget).closest('[data-menu-id]').data('menu-id');
var menu = self.flat[menu_id];
if (menu) {
var dialog = new website.menu.MenuEntryDialog(undefined, menu);
dialog.on('update-menu', this, function (link) {
var id = link.shift();
var menu_obj = self.flat[id];
_.extend(menu_obj, {
name: link[2],
url: link[0],
new_window: link[1],
});
var $menu = self.$('[data-menu-id="' + id + '"]');
$menu.find('> div > span').text(menu_obj.name);
});
dialog.appendTo(document.body);
} else {
alert("Could not find menu entry");
}
},
delete_menu: function (ev) {
var self = this;
var $menu = $(ev.currentTarget).closest('[data-menu-id]');
var mid = $menu.data('menu-id')|0;
if (mid) {
this.to_delete.push(mid);
}
$menu.remove();
},
save: function () {
var self = this;
var new_menu = this.$('.oe_menu_editor').nestedSortable('toArray', {startDepthCount: 0});
var levels = [];
var data = [];
var context = website.get_context();
// Resquence, re-tree and remove useless data
new_menu.forEach(function (menu) {
if (menu.item_id) {
levels[menu.depth] = (levels[menu.depth] || 0) + 1;
var mobj = self.flat[menu.item_id];
mobj.sequence = levels[menu.depth];
mobj.parent_id = (menu.parent_id|0) || menu.parent_id || self.root_menu_id;
delete(mobj.children);
delete(mobj.level);
data.push(mobj);
}
});
openerp.jsonRpc('/web/dataset/call_kw', 'call', {
model: 'website.menu',
method: 'save',
args: [[context.website_id], { data: data, to_delete: self.to_delete }],
kwargs: {
context: context
},
}).then(function (menu) {
self.close();
website.reload();
});
},
});
website.menu.MenuEntryDialog = website.editor.LinkDialog.extend({
template: 'website.menu.dialog.add',
init: function (editor, data) {
this.data = data;
this.update_mode = !!this.data;
return this._super.apply(this, arguments);
},
start: function () {
var self = this;
return $.when(this._super.apply(this, arguments)).then(function () {
if (self.data) {
self.bind_data(self.data.name, self.data.url, self.data.new_window);
}
var $link_text = self.$('#link-text').focus();
self.$('#link-existing').change(function () {
if (!$link_text.val()) {
$link_text.val($(this).find('option:selected').text());
$link_text.focus();
}
});
});
},
save: function () {
var $e = this.$('#link-text');
if (!$e.val() || !$e[0].checkValidity()) {
$e.closest('.form-group').addClass('has-error');
$e.focus();
return;
}
return this._super.apply(this, arguments);
},
make_link: function (url, new_window, label) {
var menu_label = this.$('input#link-text').val() || label;
if (this.data) {
this.trigger('update-menu', [this.data.id, url, new_window, menu_label]);
} else {
this.trigger('add-menu', [url, new_window, menu_label]);
}
},
});
})();
+1 -1
View File
@@ -2,7 +2,7 @@
'use strict';
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.seo.xml');
website.add_template_file('/website/static/src/xml/website.seo.xml');
website.EditorBar.include({
events: _.extend({}, website.EditorBar.prototype.events, {
@@ -2,7 +2,7 @@
'use strict';
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.snippets.xml');
website.add_template_file('/website/static/src/xml/website.snippets.xml');
website.EditorBar.include({
start: function () {
@@ -589,7 +589,8 @@
* Displayed into the overlay options on focus
*/
_readXMLData: function() {
this.$el = this.parent.$snippets.siblings("[data-snippet-id='"+this.snippet_id+"']").clone();
var self = this;
this.$el = this.parent.$snippets.filter(function () { return $(this).data("snippet-id") == self.snippet_id; }).clone();
this.$editor = this.$el.find(".oe_snippet_options");
var $options = this.$overlay.find(".oe_overlay_options");
this.$editor.prependTo($options.find(".oe_options ul"));
+1 -1
View File
@@ -2,7 +2,7 @@
'use strict';
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.tour.xml');
website.add_template_file('/website/static/src/xml/website.tour.xml');
website.tour = {
render: function render (template, dict) {
@@ -2,7 +2,7 @@
'use strict';
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.translator.xml');
website.add_template_file('/website/static/src/xml/website.translator.xml');
var nodialog = 'website_translator_nodialog';
website.EditorBar.include({
@@ -17,6 +17,7 @@
.text("Translate")
.after(openerp.qweb.render('website.TranslatorAdditionalButtons'));
self.$('[data-action=snippet]').hide();
self.$('[data-action=edit-structure]').hide();
self.$('#customize-menu-button').hide();
});
},
@@ -39,22 +39,22 @@
<form>
<ul class="list-group">
<li class="list-group-item form-group active">
<h3 class="list-group-item-heading">
<h4 class="list-group-item-heading">
<label for="link-existing" class="control-label">
Existing page
</label>
</h3>
</h4>
<select class="existing form-control url-source"
id="link-existing">
<option/>
</select>
</li>
<li class="list-group-item form-group">
<h3 class="list-group-item-heading">
<h4 class="list-group-item-heading">
<label for="link-new" class="control-label">
New page
</label>
</h3>
</h4>
<input type="text" class="form-control pages url-source"
id="link-new" placeholder="Page Name"/>
</li>
@@ -65,20 +65,20 @@
Open in new window
</label>
</div>
<h3 class="list-group-item-heading">
<h4 class="list-group-item-heading">
<label for="link-external" class="control-label">
External Website
URL
</label>
</h3>
</h4>
<input type="text" class="form-control url url-source"
id="link-external" placeholder="http://openerp.com"/>
</li>
<li class="list-group-item form-group">
<h3 class="list-group-item-heading">
<h4 class="list-group-item-heading">
<label for="link-email" class="control-label">
Email Address
</label>
</h3>
</h4>
<input type="email" class="form-control email-address url-source"
id="link-email" placeholder="you@yourwebsite.com"/>
</li>
@@ -0,0 +1,59 @@
<templates id="template" xml:space="preserve">
<t t-name="website.menu.dialog.submenu">
<li t-att-data-menu-id="submenu.id">
<div>
<i class="icon-reorder"/>
<span><t t-esc="submenu.name"/></span>
<div class="btn-group btn-group-xs pull-right oe_menu_buttons">
<button type="button" class="btn js_edit_menu">
<i class="icon-edit"/>
</button>
<button type="button" class="btn js_delete_menu">
<i class="icon-trash"/>
</button>
</div>
</div>
<t t-set="children" t-value="submenu.children"/>
<ul t-if="children">
<t t-foreach="children" t-as="submenu">
<t t-call="website.menu.dialog.submenu"/>
</t>
</ul>
</li>
</t>
<t t-name="website.menu.dialog.footer-button">
<button type="button" class="btn pull-left js_add_menu btn-success">
<i class="icon-plus-sign"/> Add Menu Entry
</button>
</t>
<t t-name="website.menu.dialog.edit">
<t t-call="website.editor.dialog">
<t t-set="title">Edit Structure</t>
<ul class="oe_menu_editor">
<t t-foreach="widget.menu.children" t-as="submenu">
<t t-call="website.menu.dialog.submenu"/>
</t>
</ul>
</t>
</t>
<t t-name="website.menu.dialog.add" t-extend="website.editor.dialog.link">
<t t-jquery="t[t-set='title']" t-operation="inner">
<t t-if="!widget.update_mode">Add Menu Entry</t>
<t t-if="widget.update_mode">Edit Menu Entry</t>
</t>
<t t-jquery="form > div.form-horizontal" t-operation="replace"/>
<t t-jquery="ul.list-group" t-operation="before">
<div class="list-group">
<div class="form-group list-group-item active">
<h3 class="list-group-item-heading">
<label for="link-new" class="control-label">
Menu Label
</label>
</h3>
<input type="text" class="form-control"
id="link-text" required="required"/>
</div>
</div>
</t>
</t>
</templates>
@@ -32,7 +32,7 @@
<!-- filled in JS -->
</section>
<section>
<h3 class="page-header">2. Reference Your Page <small>using above suggestions</small></h3>
<h3 class="page-header">2. Reference Your Page <small>using above suggested keywords</small></h3>
<div class="form-horizontal mt16" role="form">
<div class="form-group">
<label for="seo_page_title" class="col-lg-2 control-label">Title</label>
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<templates id="template" xml:space="preserve">
<t t-name="website.TranslatorAdditionalButtons">
<strong class="oe_translate_or">or</strong>
<a class="btn btn-default" data-action="edit_master" href="#">Edit Master</a>
<span class="oe_translate_or">or</span>
<a class="btn btn-link" data-action="edit_master" href="#">Edit Master</a>
</t>
<t t-name="website.TranslatorDialog">
<div class="modal fade oe_website_translator" tabindex="-1" role="dialog">
+24
View File
@@ -21,6 +21,7 @@
<ul class="nav navbar-nav navbar-right">
<li><a data-action="show-mobile-preview" href="#"><span title="Mobile preview" class="icon-mobile-phone"/></a></li>
<li class="divider-vertical"></li>
<li><a data-action="edit-structure" href="#"><span title="Edit website structure">Structure</span></a></li>
<li><a data-action="promote-current-page" href="#"><span title="Promote page on the web">Promote</span></a></li>
<li class="dropdown">
<a id="customize-menu-button" class="dropdown-toggle" data-toggle="dropdown" href="#">Customize <span class="caret"></span></a>
@@ -61,4 +62,27 @@
</div>
</t>
<t t-name="website.error_dialog">
<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button title="Close" type="button" class="close" data-dismiss="modal">×</button>
<div class="h2"><t t-esc="title"/></div>
</div>
<div class="modal-body">
<section>
<t t-esc="message"/>
</section>
<section class="mt32">
You have encountered an error. You can edit in the <a t-att-href="backend_url">backend</a> this data.
</section>
</div>
<div class="modal-footer">
<button type="button" data-dismiss="modal" href="#" class="close btn btn-default">Close</button>
</div>
</div>
</div>
</div>
</t>
</templates>
+2 -1
View File
@@ -323,6 +323,7 @@
<div data-snippet-id="well" data-selector-siblings="p, h1, h2, h3, blockquote">
<div class="oe_snippet_thumbnail">
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_well.png"/>
<span class="oe_snippet_thumbnail_title">Well</span>
</div>
<div class="oe_snippet_body well">
@@ -716,7 +717,7 @@
<div data-snippet-id="parallax_quote" data-selector-children=".oe_structure, [data-oe-type=html]">
<div class="oe_snippet_thumbnail">
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_parallax.png"/>
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_quotes_slider.png"/>
<span class="oe_snippet_thumbnail_title">Quotes Slider</span>
</div>
<section class="oe_snippet_body parallax_quote oe_structure">
+65 -33
View File
@@ -10,9 +10,28 @@
<link id="website_css" rel='stylesheet' href='/website/static/src/css/website.css' t-ignore="true"/>
</template>
<template id="layout" name="Main layout">
&lt;!DOCTYPE html&gt;
<template id="website.submenu" name="Submenu">
<t t-set="children" t-value="submenu['children']"/>
<li t-if="not children">
<a t-att-href="url_for(submenu['url'])">
<t t-esc="submenu['name']"/>
</a>
</li>
<li t-if="children" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<t t-esc="submenu['name']"/> <span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu">
<t t-foreach="children" t-as="submenu">
<t t-call="website.submenu"/>
</t>
</ul>
</li>
</template>
<template id="layout" name="Main layout">&lt;!DOCTYPE html&gt;
<html t-att-lang="lang.replace('_', '-')"
t-att-data-website-id="website.id if editable else None"
t-att-data-editable="'1' if editable else None"
t-att-data-translatable="'1' if translatable else None"
t-att-data-view-xmlid="xmlid if editable else None"
@@ -49,6 +68,11 @@
<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">
// Bootstrap and jQuery UI conflicts
$.fn.bstooltip = $.fn.tooltip;
$.fn.bsbutton = $.fn.button;
</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>
@@ -65,11 +89,13 @@
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
<link rel='stylesheet' href="/web/static/lib/jquery.ui/css/smoothness/jquery-ui-1.9.1.custom.css"/>
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
<script type="text/javascript" src="/website/static/lib//jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
<script type="text/javascript" src='/website/static/lib/nearest/jquery.nearest.js'></script>
<script type="text/javascript" src="/website/static/lib/MutationObservers/MutationObserver.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.editor.js"></script>
<script type="text/javascript" src="/website/static/src/js/website.menu.js"></script>
<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.tour.js"></script>
@@ -93,38 +119,28 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" t-href="/page/website.homepage"><em>Your</em><b>Company</b></a>
<a class="navbar-brand" t-href="/"><em>Your</em><b>Company</b></a>
</div>
<div class="collapse navbar-collapse navbar-top-collapse">
<ul class="nav navbar-nav navbar-right" id="top_menu">
<li name="contactus"><a t-href="/page/website.contactus">Contact us</a></li>
<li t-if="user_id.id == website.public_user.id"><a href="/web">Sign in</a></li>
<li t-if="user_id.id != website.public_user.id"><a href="/web"><span t-field="user_id.name"/></a></li>
<li t-if="request.multilang and
(len(website.language_ids) &gt; 1 or editable)" class="dropdown">
<!-- TODO: use flags for language selection -->
<a class="dropdown-toggle js_language_selected" data-toggle="dropdown" href="#">
<t t-esc="lang_selected[0]['name'].split('/').pop()"/> <span class="caret"></span>
<t t-foreach="website.get_menu_tree()['children']" t-as="submenu">
<t t-call="website.submenu"/>
</t>
<li class="active" t-if="user_id.id == website.public_user.id">
<a t-attf-href="/web#redirect=#{ url_for('') }">
Sign in
</a>
<ul class="dropdown-menu js_language_selector" role="menu">
<li t-foreach="website.language_ids" t-as="lg">
<a t-att-href="url_for('', lang=lg.code)" role="menuitem"
t-att-data-default-lang="editable and 'true' if lg.code == website.default_lang_id.code else None">
<strong t-att-class="'icon-circle' if lg.code == lang
else 'icon-circle-blank'"></strong>
<t t-esc="lg.name.split('/').pop()"/>
</a>
</li>
<li t-if="editable" class="divider"/>
<li t-if="editable">
<t t-set="url_return" t-value="request.multilang and url_for(request.httprequest.path, '[lang]') or request.httprequest.path"/>
<t t-if="request.httprequest.query_string">
<t t-set="url_return" t-value="url_return + '?' + request.httprequest.query_string"/>
</t>
<a t-attf-href="/web#action=base.action_view_base_language_install&amp;website_id=#{website.id}&amp;url_return=#{url_return}">
Add a language...
</a>
</li>
</li>
<li class="active dropdown" t-ignore="true" t-if="user_id.id != website.public_user.id">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span t-esc="user_id.name"/>
<span class="caret"></span>
</a>
<ul class="dropdown-menu js_usermenu" role="menu">
<li><a href="/web" role="menuitem">Administration</a></li>
<li class="divider"/>
<li><a t-attf-href="/web/session/logout?redirect=#{ url_for('') }" role="menuitem">Logout</a></li>
</ul>
</li>
</ul>
@@ -174,6 +190,22 @@
Our products are designed for small to medium companies willing to optimize
their performance.
</p>
<ul class="nav nav-pills js_language_selector" t-if="request.multilang and
(len(website.language_ids) &gt; 1 or editable)">
<li t-foreach="website.language_ids" t-as="lg">
<a t-att-href="url_for('', lang=lg.code)"
t-att-data-default-lang="editable and 'true' if lg.code == website.default_lang_id.code else None">
<t t-esc="lg.name.split('/').pop()"/>
</a>
</li>
<li t-if="editable">
<t t-set="url_return" t-value="request.multilang and url_for(request.httprequest.path, '[lang]') or request.httprequest.path"/>
<a t-attf-href="/web#action=base.action_view_base_language_install&amp;website_id=#{website.id}&amp;url_return=#{url_return}">
<i class="icon-plus-sign"/>
Add a language...
</a>
</li>
</ul>
</div>
</div>
</div>
@@ -227,7 +259,7 @@
<template id="publish_management">
<t t-if="editable" t-ignore="true">
<div class="pull-right">
<div t-attf-class="btn-group dropdown js_publish_management #{object.id and object.website_published and 'css_publish' or 'css_unpublish'}" t-att-data-id="object.id" t-att-data-object="object._name">
<div t-attf-class="btn-group dropdown js_publish_management #{object.id and object.website_published and 'css_publish' or 'css_unpublish'}" t-att-data-id="object.id" t-att-data-object="object._name" t-att-data-controller="publish_controller">
<a t-attf-class="btn btn-sm btn-#{object.id and object.website_published and 'success' or 'default'}" t-att-id="'dopprod-%s' % object.id" role="button" data-toggle="dropdown">Options <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu" t-att-aria-labelledby="'dopprod-%s' % object.id">
<t t-raw="0"/>
@@ -439,8 +471,8 @@ Sitemap: <t t-esc="url_root"/>sitemap.xml
<span>&amp;#x2706; <span t-field="res_company.phone"></span></span><br />
<i class="icon-envelope"></i> <span t-field="res_company.email"></span>
</address>
<a t-att-href="res_company.partner_id.google_map_link()" target="_BLANK">
<img class="thumbnail img-responsive" t-att-src="res_company.partner_id.google_map_img()" />
<a t-att-href="res_company.google_map_link()" target="_BLANK">
<img class="thumbnail img-responsive" t-att-src="res_company.google_map_img()" />
</a>
</template>
+8 -16
View File
@@ -181,24 +181,16 @@ class WebsiteBlog(http.Controller):
]
return simplejson.dumps(blog_post_data)
@website.route(['/blog/<int:blog_post_id>/post'], type='http', auth="public")
@website.route(['/blog/<int:blog_post_id>/comment'], type='http', auth="public")
def blog_post_comment(self, blog_post_id=None, **post):
cr, uid, context = request.cr, request.uid, request.context
url = request.httprequest.host_url
request.session.body = post.get('body')
if request.context['is_public_user']: # purpose of this ?
return '%s/web#action=redirect&url=%s/blog/%s/post' % (url, url, blog_post_id)
if request.session.get('body') and blog_post_id:
request.registry['blog.post'].message_post(
cr, uid, blog_post_id,
body=request.session.body,
type='comment',
subtype='mt_comment',
context=dict(context, mail_create_nosubcribe=True))
request.session.body = False
return werkzeug.utils.redirect("/blog/%s/?enable_editor=1" % (blog_post_id))
request.registry['blog.post'].message_post(
cr, uid, blog_post_id,
body=post.get('comment'),
type='comment',
subtype='mt_comment',
context=dict(context, mail_create_nosubcribe=True))
return werkzeug.utils.redirect(request.httprequest.referrer + "#comments")
@website.route(['/blog/<int:category_id>/new'], type='http', auth="public")
def blog_post_create(self, category_id=None, **post):
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<!-- <data noupdate="1"> -->
<data noupdate="1">
<record id="menu_blog" model="website.menu">
<field name="name">News</field>
<field name="url">/blog</field>
<field name="parent_id" ref="website.main_menu"/>
</record>
</data>
<data>
<!-- jump to blog at install -->
@@ -25,16 +25,4 @@ $(document).ready(function () {
}
});
var $form = $('.js_website_blog form#comment');
$form.submit(function (e) {
e.preventDefault();
var error = $form.find("textarea").val().length < 3;
$form.find("textarea").toggleClass("has-error", error);
if (!error) {
$form.css("visibility", "hidden");
$.post(window.location.pathname + '/post', {'body': $form.find("textarea").val()}, function (url) {
window.location.href = url
});
}
});
});
@@ -3,9 +3,6 @@
<data>
<!-- Layout add nav and footer -->
<template id="header_footer_custom" inherit_id="website.layout">
<xpath expr="//header//ul[@id='top_menu']/li[@name='contactus']" position="before">
<li><a t-href="/blog/cat/%(website_blog.blog_category_1)d/">News</a></li>
</xpath>
<xpath expr="//footer//div[@name='info']/ul" position="inside">
<li><a t-href="/blog/cat/%(website_blog.blog_category_1)d/">News</a></li>
</xpath>
@@ -132,17 +129,19 @@
<template id="opt_blog_post_complete_comment" name="Comment Form"
inherit_option_id="website_blog.blog_post_complete" inherit_id="website_blog.blog_post_complete">
<xpath expr="//ul[last()]" position="after">
<section groups="group_website_blog_reply" class="mb32">
<h4>Leave a Comment</h4>
<form id="comment" t-attf-action="/blog/#{blog_post.id}/post#post"
method="POST">
<img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(user_id.partner_id.id)" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="3" class="form-control" placeholder="Write a comment..."></textarea>
<button type="submit" class="btn btn-danger mt8">Post</button>
</div>
</form>
</section>
<t t-if="not is_public_user">
<section groups="group_website_blog_reply" class="mb32">
<h4>Leave a Comment</h4>
<form id="comment" t-attf-action="/blog/#{blog_post.id}/comment"
method="POST">
<img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&amp;field=image_small&amp;id='+str(user_id.partner_id.id)" style="width: 50px; margin-right: 10px;"/>
<div class="pull-left mb32" style="width: 75%%">
<textarea rows="3" name="comment" class="form-control" placeholder="Write a comment..."></textarea>
<button type="submit" class="btn btn-danger mt8">Post</button>
</div>
</form>
</section>
</t>
</xpath>
</template>
+2 -2
View File
@@ -14,7 +14,7 @@ class WebsiteCustomer(http.Controller):
@website.route([
'/customers/', '/customers/page/<int:page>/',
'/customers/country/<int:country_id>', '/customers/country/<int:country_id>/page/<int:page>/'
], type='http', auth="public")
], type='http', auth="public", multilang=True)
def customers(self, country_id=None, page=0, **post):
cr, uid, context = request.cr, request.uid, request.context
partner_obj = request.registry['res.partner']
@@ -70,7 +70,7 @@ class WebsiteCustomer(http.Controller):
}
return request.website.render("website_customer.index", values)
@website.route(['/customers/<int:partner_id>/'], type='http', auth="public")
@website.route(['/customers/<int:partner_id>/'], type='http', auth="public", multilang=True)
def customer(self, partner_id=None, **post):
""" Route for displaying a single partner / customer.
@@ -5,11 +5,11 @@
<!-- Layout add nav and footer -->
<template id="footer_custom" inherit_id="website.layout" name="Custom Footer">
<xpath expr="//footer//div[@name='info']/ul" position="inside">
<li><a href="/customers/">Customer References</a></li>
<li><a t-href="/customers/">Customer References</a></li>
</xpath>
</template>
<!-- Page -->
<!-- Page -->
<template id="layout" name="Customer References Layout">
<t t-call="website.layout">
<t t-set="additional_title">Customer References</t>
@@ -53,7 +53,7 @@
<t t-set="classname" t-value="'pull-left'"/>
</t>
<form action="/customers/" method="get" class="navbar-search pull-right pagination form-inline">
<div class="form-group">
<div class="form-group">
<input type="text" name="search" class="search-query form-control"
placeholder="Search" t-att-value="post.get('search', '')"/>
</div>
@@ -63,11 +63,11 @@
<div>
<div t-foreach="partner_ids" t-as="partner" class="media thumbnail" data-publish="">
<t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
<a class="pull-left" t-attf-href="/customers/#{ partner.id }/">
<a class="pull-left" t-href="/customers/#{ partner.id }/">
<img class="media-object" t-att-src="partner.img('image_small')"/>
</a>
<div class="media-body" style="min-height: 64px;">
<a class="media-heading" t-attf-href="/customers/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a>
<a class="media-heading" t-href="/customers/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a>
<div t-field="partner.website_short_description"/>
</div>
</div>
+1
View File
@@ -15,6 +15,7 @@ Online Events
'data': [
'data/event_data.xml',
'views/website_event.xml',
'views/website_event_sale_backend.xml',
'security/ir.model.access.csv',
'security/website_event.xml',
],
+15
View File
@@ -25,6 +25,9 @@ from openerp.addons.web.http import request
from openerp.tools.translate import _
from openerp.addons import website_sale
from openerp.addons.website.models import website
from openerp.addons.website.controllers.main import Website as controllers
controllers = controllers()
from datetime import datetime
from dateutil.relativedelta import relativedelta
@@ -216,3 +219,15 @@ class website_event(http.Controller):
if not _values:
return request.redirect("/event/%s/" % event_id)
return request.redirect("/shop/checkout")
@website.route(['/event/publish'], type='json', auth="public")
def publish(self, id, object):
# if a user publish an event, he publish all linked res.partner
event = request.registry[object].browse(request.cr, request.uid, int(id))
if not event.website_published:
if event.organizer_id and not event.organizer_id.website_published:
event.organizer_id.write({'website_published': True})
if event.address_id and not event.address_id.website_published:
event.address_id.write({'website_published': True})
return controllers.publish(id, object)
+5
View File
@@ -2,6 +2,11 @@
<openerp>
<data noupdate="1">
<record id="menu_events" model="website.menu">
<field name="name">Events</field>
<field name="url">/event</field>
<field name="parent_id" ref="website.main_menu"/>
</record>
<record id="action_open_website" model="ir.actions.act_url">
<field name="name">Website Home</field>
<field name="target">self</field>
+15
View File
@@ -2,6 +2,9 @@
<openerp>
<data>
<record id="base.res_partner_6" model="res.partner">
<field name="website_published">True</field>
</record>
<record id="event.event_0" model="event.event">
<field name="website_published">True</field>
<field name="twitter_hashtag">openerp</field>
@@ -162,6 +165,9 @@
</div>
]]></field> </record>
<record id="base.res_partner_5" model="res.partner">
<field name="website_published">True</field>
</record>
<record id="event.event_1" model="event.event">
<field name="website_published">True</field>
<field name="twitter_hashtag">openerp</field>
@@ -323,11 +329,20 @@
]]></field>
</record>
<record id="base.res_partner_14" model="res.partner">
<field name="website_published">True</field>
</record>
<record id="event.event_2" model="event.event">
<field name="website_published">True</field>
<field name="twitter_hashtag">openerp</field>
</record>
<record id="base.res_partner_2" model="res.partner">
<field name="website_published">True</field>
</record>
<record id="base.res_partner_address_4" model="res.partner">
<field name="website_published">True</field>
</record>
<record id="event.event_3" model="event.event">
<field name="website_published">True</field>
<field name="twitter_hashtag">openerp</field>
+15
View File
@@ -51,6 +51,21 @@ class event(osv.osv):
'website_published': False,
}
def _check_organizer_id_published(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
if obj.website_published and obj.organizer_id and not obj.organizer_id.website_published:
return False
return True
def _check_address_id_published(self, cr, uid, ids, context=None):
for obj in self.browse(cr, uid, ids, context=context):
if obj.website_published and obj.address_id and not obj.address_id.website_published:
return False
return True
_constraints = [
(_check_organizer_id_published, "This event can't be published if the field Orginizer is not website published.", ['organizer_id','website_published']),
(_check_address_id_published, "This event can't be published if the field Location is not website published.", ['address_id','website_published']),
]
def google_map_img(self, cr, uid, ids, zoom=8, width=298, height=298, context=None):
partner = self.browse(cr, uid, ids[0], context=context)
if partner.address_id:
+14 -6
View File
@@ -4,9 +4,6 @@
<!-- Layout add nav and footer -->
<template id="header_footer_custom" inherit_id="website.layout">
<xpath expr="//header//ul[@id='top_menu']/li[@name='contactus']" position="before">
<li><a t-href="/event">Events</a></li>
</xpath>
<xpath expr="//footer//div[@name='info']/ul" position="inside">
<li><a t-href="/event">Events</a></li>
</xpath>
@@ -48,7 +45,10 @@
</div>
<ul class="media-list">
<li t-foreach="event_ids" t-as="event" class="media" data-publish="">
<t t-call="website.publish_management"><t t-set="object" t-value="event"/></t>
<t t-call="website.publish_management">
<t t-set="object" t-value="event"/>
<t t-set="publish_controller">/event/publish</t>
</t>
<div class="media-body">
<span t-if="not event.event_ticket_ids" class="label label-danger pull-right">Registration Closed</span>
<t t-if="event.event_ticket_ids">
@@ -177,7 +177,11 @@
<ul class="media-list" id="comment">
<li t-foreach="event_id.website_message_ids" t-as="comment" class="media">
<div class="media-body">
<t t-call="website.publish_management"><t t-set="object" t-value="comment"/></t>
<t t-call="website.publish_management">
<t t-set="object" t-value="comment"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="publish_controller">/event/publish</t>
</t>
<t t-raw="comment.body"/>
<small class="pull-right muted text-right">
<div t-field="comment.author_id"/>
@@ -192,7 +196,11 @@
<div class="panel panel-default" t-if="event_id.address_id">
<div class="panel-heading">
<t t-call="website.publish_management"><t t-set="object" t-value="event_id"/></t>
<t t-call="website.publish_management">
<t t-set="object" t-value="event_id"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="publish_controller">/event/publish</t>
</t>
<h4>Where</h4>
</div>
<div class="panel-body">
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="view_event_form">
<field name="name">event.event.website.form</field>
<field name="model">event.event</field>
<field name="inherit_id" ref="event_sale.view_event_form"/>
<field name="arch" type="xml">
<field name="organizer_id" position="after">
<field name="website_published"/>
</field>
</field>
</record>
</data>
</openerp>
@@ -2,6 +2,9 @@
from openerp.addons.web import http
from openerp.addons.web.http import request
from openerp.addons.website.models import website
from openerp.addons.website.controllers.main import Website as controllers
controllers = controllers()
import base64
@@ -48,7 +51,7 @@ class website_hr_recruitment(http.Controller):
return request.website.render("website_hr_recruitment.index", values)
@website.route(['/job/detail/<model("hr.job"):job>'], type='http', auth="public", multilang=True)
def detail(self, job=None):
def detail(self, job=None, **kwargs):
values = {
'job': job,
'vals_date': job.write_date.split(' ')[0],
@@ -68,28 +71,23 @@ class website_hr_recruitment(http.Controller):
'res_id': id
}
request.registry['ir.attachment'].create(request.cr, request.uid, attachment_values)
website = request.registry['website']
values = {
'jobid': post['job_id']
}
return request.website.render("website_hr_recruitment.thankyou", values)
@website.route(['/apply/<int:id>'], type='http', auth="public", multilang=True)
def applyjobpost(self, id=0, **kwargs):
id = id and int(id) or 0
job = request.registry['hr.job'].browse(request.cr, request.uid, id)
values = {
'job': job
}
return request.website.render("website_hr_recruitment.applyjobpost", values)
@website.route(['/apply/<model("hr.job"):job>'], type='http', auth="public", multilang=True)
def applyjobpost(self, job=None, **kwargs):
return request.website.render("website_hr_recruitment.applyjobpost", { 'job': job })
@website.route('/recruitment/published', type='json', auth="admin", multilang=True)
def published (self, id, **post):
hr_job = request.registry['hr.job']
@website.route('/job/publish', type='json', auth="admin", multilang=True)
def publish (self, id, object):
res = controllers.publish(id, object)
hr_job = request.registry[object]
id = int(id)
rec = hr_job.browse(request.cr, request.uid, id)
vals = {}
if rec.website_published:
vals['state'] = 'recruit'
if not rec.no_of_recruitment:
@@ -98,6 +96,5 @@ class website_hr_recruitment(http.Controller):
vals['state'] = 'open'
hr_job.write(request.cr, request.uid, [rec.id], vals, context=request.context)
obj = hr_job.browse(request.cr, request.uid, id, context=request.context)
return { 'count': obj.no_of_recruitment, 'state': obj.state, 'published': obj.website_published }
return res
# vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="menu_jobs" model="website.menu">
<field name="name">Jobs</field>
<field name="url">/jobs</field>
<field name="parent_id" ref="website.main_menu"/>
</record>
<record id="action_open_website" model="ir.actions.act_url">
<field name="name">Website Recruitment Form</field>
<field name="target">self</field>
@@ -1,11 +0,0 @@
$(function () {
$(this).ajaxComplete(function(event, xhr, settings) {
var data = JSON.parse(settings.data).params;
if (settings.url == "/website/publish") {
var $data = $(".oe_website_hr_recruitment .js_publish_management[data-id='" + data.id + "'][data-object='" + data.object + "']");
if ($data.length) {
settings.jsonpCallback = openerp.jsonRpc('/recruitment/published', 'call', data);
}
}
});
});
@@ -8,9 +8,6 @@
</record>
<template id="job_footer_custom" inherit_id="website.layout" name="Custom Footer Job">
<xpath expr="//header//ul[@id='top_menu']/li[@name='contactus']" position="before">
<li><a t-href="/jobs">Jobs</a></li>
</xpath>
<xpath expr="//footer//div[@name='info']/ul" position="inside">
<li><a t-href="/jobs">Jobs</a></li>
</xpath>
@@ -56,10 +53,6 @@
<template id="detail">
<t t-call="website.layout">
<t t-set="head">
<script type="text/javascript" src="/website_hr_recruitment/static/src/js/recruitment.js"></script>
<t t-raw="head or ''"/>
</t>
<t t-set="additional_title">Job Detail</t>
<div id="wrap">
<div class="container oe_website_hr_recruitment">
@@ -73,6 +66,7 @@
<t t-call="website.publish_management">
<t t-set="object" t-value="job"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="publish_controller">/job/publish</t>
</t>
</div>
</div>
-1
View File
@@ -214,7 +214,6 @@ class Ecommerce(http.Controller):
col += 1
line += 1
print bin_packing_list
return bin_packing_list
def get_products(self, product_ids):
@@ -4,6 +4,7 @@ access_product_template_public,product.template.public,product.model_product_tem
access_product_category_,product.category.public,product.model_product_category,base.group_public,1,0,0,0
access_product_category_public,product.category.public,product.model_product_public_category,base.group_public,1,0,0,0
access_product_pricelist_version_public,product.pricelist.version.public,product.model_product_pricelist_version,base.group_public,1,0,0,0
access_product_pricelist_public,product.pricelist.public,product.model_product_pricelist,base.group_public,1,0,0,0
access_product_product_price_type_public,product.price.type.public,product.model_product_price_type,base.group_public,1,0,0,0
access_sale_order_public,sale.order.public,model_sale_order,base.group_public,1,0,0,0
access_sale_order_line_public,sale.order.line.public,model_sale_order_line,base.group_public,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
4 access_product_category_ product.category.public product.model_product_category base.group_public 1 0 0 0
5 access_product_category_public product.category.public product.model_product_public_category base.group_public 1 0 0 0
6 access_product_pricelist_version_public product.pricelist.version.public product.model_product_pricelist_version base.group_public 1 0 0 0
7 access_product_pricelist_public product.pricelist.public product.model_product_pricelist base.group_public 1 0 0 0
8 access_product_product_price_type_public product.price.type.public product.model_product_price_type base.group_public 1 0 0 0
9 access_sale_order_public sale.order.public model_sale_order base.group_public 1 0 0 0
10 access_sale_order_line_public sale.order.line.public model_sale_order_line base.group_public 1 0 0 0
+12 -1
View File
@@ -42,5 +42,16 @@
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
<record id="product_pricelist_public" model="ir.rule">
<field name="name">Public product pricelist</field>
<field name="model_id" ref="product.model_product_pricelist"/>
<field name="domain_force">[('id','=',session.get('ecommerce_pricelist'))]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_unlink" eval="False"/>
</record>
</data>
</openerp>
</openerp>
@@ -6,7 +6,6 @@
<template id="header" inherit_id="website.layout" name="Custom Header">
<xpath expr="//header//ul[@id='top_menu']/li" position="before">
<li><a t-href="/shop/">Shop</a></li>
<li t-att-class="(not website_sale_order or not website_sale_order.get_total_quantity()) and 'hidden' or ''">
<a t-href="/shop/mycart/">
<i class="icon-shopping-cart"></i>
@@ -2,6 +2,11 @@
<openerp>
<data noupdate="1">
<record id="menu_shop" model="website.menu">
<field name="name">Shop</field>
<field name="url">/shop</field>
<field name="parent_id" ref="website.main_menu"/>
</record>
<record id="action_open_website" model="ir.actions.act_url">
<field name="name">Website Shop</field>
<field name="target">self</field>