[MERGE] from trunk
bzr revid: xmo@openerp.com-20131014085459-dhbypq0hg3lzzf3j
This commit is contained in:
commit
2e352ce187
|
@ -0,0 +1,23 @@
|
|||
# Spanish (Argentina) translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:04+0000\n"
|
||||
"PO-Revision-Date: 2013-10-07 21:16+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Spanish (Argentina) <es_AR@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-08 05:42+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: account_accountant
|
||||
#: model:ir.actions.client,name:account_accountant.action_client_account_menu
|
||||
msgid "Open Accounting Menu"
|
||||
msgstr ""
|
|
@ -0,0 +1,23 @@
|
|||
# Estonian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 14:39+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: account_cancel
|
||||
#: view:account.invoice:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
|
@ -1,30 +1,28 @@
|
|||
# Estonian translation for openobject-addons
|
||||
# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2011.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-03 16:03+0000\n"
|
||||
"PO-Revision-Date: 2011-10-10 19:33+0000\n"
|
||||
"Last-Translator: Aare Vesi <Unknown>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 14:40+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-12-04 05:53+0000\n"
|
||||
"X-Generator: Launchpad (build 16335)\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: base_crypt
|
||||
#: model:ir.model,name:base_crypt.model_res_users
|
||||
#. module: auth_crypt
|
||||
#: field:res.users,password_crypt:0
|
||||
msgid "Encrypted Password"
|
||||
msgstr "Krüpteeritud Parool"
|
||||
|
||||
#. module: auth_crypt
|
||||
#: model:ir.model,name:auth_crypt.model_res_users
|
||||
msgid "Users"
|
||||
msgstr ""
|
||||
|
||||
#, python-format
|
||||
#~ msgid "Error"
|
||||
#~ msgstr "Viga"
|
||||
|
||||
#~ msgid "res.users"
|
||||
#~ msgstr "res.users"
|
||||
msgstr "Kasutajad"
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Estonian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 14:34+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: auth_oauth_signup
|
||||
#: model:ir.model,name:auth_oauth_signup.model_res_users
|
||||
msgid "Users"
|
||||
msgstr "Kasutajad"
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013_Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import models
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013_Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
||||
{
|
||||
'name': 'Partners Geo-Localization',
|
||||
'version': '1.0',
|
||||
'category': 'Customer Relationship Management',
|
||||
'description': """
|
||||
Partners geolocalization
|
||||
========================
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['crm'],
|
||||
'demo': [
|
||||
# 'res_partner_demo.xml',
|
||||
],
|
||||
'data': [
|
||||
'views/res_partner_view.xml',
|
||||
],
|
||||
'test': [],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
'images': [],
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1 @@
|
|||
import res_partner
|
|
@ -0,0 +1,88 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2013_Today OpenERP SA (<http://www.openerp.com>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json # noqa
|
||||
import urllib
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp import tools
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
def geo_find(addr):
|
||||
url = 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address='
|
||||
url += urllib.quote(addr.encode('utf8'))
|
||||
|
||||
try:
|
||||
result = json.load(urllib.urlopen(url))
|
||||
except Exception, e:
|
||||
raise osv.except_osv(_('Network error'),
|
||||
_('Cannot contact geolocation servers. Please make sure that your internet connection is up and running (%s).') % e)
|
||||
if result['status'] != 'OK':
|
||||
return None
|
||||
|
||||
try:
|
||||
geo = result['results'][0]['geometry']['location']
|
||||
return float(geo['lat']), float(geo['lng'])
|
||||
except (KeyError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def geo_query_address(street=None, zip=None, city=None, state=None, country=None):
|
||||
if country and ',' in country and (country.endswith(' of') or country.endswith(' of the')):
|
||||
# put country qualifier in front, otherwise GMap gives wrong results,
|
||||
# e.g. 'Congo, Democratic Republic of the' => 'Democratic Republic of the Congo'
|
||||
country = '{1} {0}'.format(*country.split(',', 1))
|
||||
return tools.ustr(', '.join(filter(None, [street,
|
||||
("%s %s" % (zip or '', city or '')).strip(),
|
||||
state,
|
||||
country])))
|
||||
|
||||
|
||||
class res_partner(osv.osv):
|
||||
_inherit = "res.partner"
|
||||
|
||||
_columns = {
|
||||
'partner_latitude': fields.float('Geo Latitude'),
|
||||
'partner_longitude': fields.float('Geo Longitude'),
|
||||
'date_localization': fields.date('Geo Localization Date'),
|
||||
}
|
||||
|
||||
def geo_localize(self, cr, uid, ids, context=None):
|
||||
# Don't pass context to browse()! We need country names in english below
|
||||
for partner in self.browse(cr, uid, ids):
|
||||
if not partner:
|
||||
continue
|
||||
result = geo_find(geo_query_address(street=partner.street,
|
||||
zip=partner.zip,
|
||||
city=partner.city,
|
||||
state=partner.state_id.name,
|
||||
country=partner.country_id.name))
|
||||
if result:
|
||||
self.write(cr, uid, [partner.id], {
|
||||
'partner_latitude': result[0],
|
||||
'partner_longitude': result[1],
|
||||
'date_localization': fields.date.context_today(self, cr, uid, context=context)
|
||||
}, context=context)
|
||||
return True
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_crm_partner_geo_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Geo Localization" name="geo_localization" groups="base.group_no_one">
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Geo Localization" colspan="2"/>
|
||||
<button
|
||||
string="Geo Localize"
|
||||
name="geo_localize"
|
||||
colspan="2"
|
||||
icon="gtk-apply"
|
||||
type="object"/>
|
||||
<field name="partner_latitude"/>
|
||||
<field name="partner_longitude"/>
|
||||
<field name="date_localization"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,185 @@
|
|||
# Hindi translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 05:55+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Hindi <hi@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.model,name:base_report_designer.model_base_report_sxw
|
||||
msgid "base.report.sxw"
|
||||
msgstr "base.report.sxw"
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base_report_designer.installer:0
|
||||
msgid "OpenERP Report Designer Configuration"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base_report_designer.installer:0
|
||||
msgid ""
|
||||
"This plug-in allows you to create/modify OpenERP Reports into OpenOffice "
|
||||
"Writer."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.sxw:0
|
||||
msgid "Upload the modified report"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.file.sxw:0
|
||||
msgid "The .SXW report"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.model,name:base_report_designer.model_base_report_designer_installer
|
||||
msgid "base_report_designer.installer"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.model,name:base_report_designer.model_base_report_rml_save
|
||||
msgid "base.report.rml.save"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base_report_designer.installer:0
|
||||
msgid "Configure"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base_report_designer.installer:0
|
||||
msgid "title"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: field:base.report.file.sxw,report_id:0
|
||||
#: field:base.report.sxw,report_id:0
|
||||
msgid "Report"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.rml.save:0
|
||||
msgid "The RML Report"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.ui.menu,name:base_report_designer.menu_action_report_designer_wizard
|
||||
msgid "Report Designer"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: field:base_report_designer.installer,name:0
|
||||
msgid "File name"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.file.sxw:0
|
||||
#: view:base.report.sxw:0
|
||||
msgid "Get a report"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base_report_designer.installer:0
|
||||
#: model:ir.actions.act_window,name:base_report_designer.action_report_designer_wizard
|
||||
msgid "OpenERP Report Designer"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.sxw:0
|
||||
msgid "Continue"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: field:base.report.rml.save,file_rml:0
|
||||
msgid "Save As"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: help:base_report_designer.installer,plugin_file:0
|
||||
msgid ""
|
||||
"OpenObject Report Designer plug-in file. Save as this file and install this "
|
||||
"plug-in in OpenOffice."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.rml.save:0
|
||||
msgid "Save RML FIle"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: field:base.report.file.sxw,file_sxw:0
|
||||
#: field:base.report.file.sxw,file_sxw_upload:0
|
||||
msgid "Your .SXW file"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base_report_designer.installer:0
|
||||
msgid "Installation and Configuration Steps"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: field:base_report_designer.installer,description:0
|
||||
msgid "Description"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.file.sxw:0
|
||||
msgid ""
|
||||
"This is the template of your requested report.\n"
|
||||
"Save it as a .SXW file and open it with OpenOffice.\n"
|
||||
"Don't forget to install the OpenERP SA OpenOffice package to modify it.\n"
|
||||
"Once it is modified, re-upload it in OpenERP using this wizard."
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.actions.act_window,name:base_report_designer.action_view_base_report_sxw
|
||||
msgid "Base Report sxw"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.model,name:base_report_designer.model_base_report_file_sxw
|
||||
msgid "base.report.file.sxw"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: field:base_report_designer.installer,plugin_file:0
|
||||
msgid "OpenObject Report Designer Plug-in"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.actions.act_window,name:base_report_designer.action_report_designer_installer
|
||||
msgid "OpenERP Report Designer Installation"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.sxw:0
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.sxw:0
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: model:ir.model,name:base_report_designer.model_ir_actions_report_xml
|
||||
msgid "ir.actions.report.xml"
|
||||
msgstr ""
|
||||
|
||||
#. module: base_report_designer
|
||||
#: view:base.report.sxw:0
|
||||
msgid "Select your report"
|
||||
msgstr ""
|
|
@ -0,0 +1,33 @@
|
|||
# Estonian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 14:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: claim_from_delivery
|
||||
#: view:stock.picking.out:0
|
||||
msgid "Claims"
|
||||
msgstr "Nõuded"
|
||||
|
||||
#. module: claim_from_delivery
|
||||
#: model:res.request.link,name:claim_from_delivery.request_link_claim_from_delivery
|
||||
msgid "Delivery Order"
|
||||
msgstr "Tarnetellimus"
|
||||
|
||||
#. module: claim_from_delivery
|
||||
#: model:ir.actions.act_window,name:claim_from_delivery.action_claim_from_delivery
|
||||
msgid "Claim From Delivery"
|
||||
msgstr ""
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
|
||||
{
|
||||
'name': 'Partners Geo-Localization',
|
||||
'name': 'Partner Assignation',
|
||||
'version': '1.0',
|
||||
'category': 'Customer Relationship Management',
|
||||
'description': """
|
||||
|
@ -37,8 +37,11 @@ The most appropriate partner can be assigned.
|
|||
You can also use the geolocalization without using the GPS coordinates.
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['crm', 'account', 'portal'],
|
||||
'demo': ['res_partner_demo.xml', 'crm_lead_demo.xml'],
|
||||
'depends': ['base_geolocalize', 'crm', 'account', 'portal'],
|
||||
'demo': [
|
||||
# 'res_partner_demo.xml',
|
||||
'crm_lead_demo.xml'
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'res_partner_view.xml',
|
||||
|
@ -50,6 +53,7 @@ You can also use the geolocalization without using the GPS coordinates.
|
|||
'portal_data.xml',
|
||||
'report/crm_lead_report_view.xml',
|
||||
'report/crm_partner_report_view.xml',
|
||||
'res_partner_demo.xml',
|
||||
],
|
||||
'js': [
|
||||
'static/src/js/next.js',
|
||||
|
|
|
@ -19,46 +19,12 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import urllib
|
||||
import random
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
except ImportError:
|
||||
import json # noqa
|
||||
|
||||
from openerp.addons.base_geolocalize.models.res_partner import geo_find, geo_query_address
|
||||
from openerp.osv import osv
|
||||
from openerp.osv import fields
|
||||
from openerp.tools.translate import _
|
||||
from openerp import tools
|
||||
|
||||
def geo_find(addr):
|
||||
url = 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false&address='
|
||||
url += urllib.quote(addr.encode('utf8'))
|
||||
|
||||
try:
|
||||
result = json.load(urllib.urlopen(url))
|
||||
except Exception, e:
|
||||
raise osv.except_osv(_('Network error'),
|
||||
_('Cannot contact geolocation servers. Please make sure that your internet connection is up and running (%s).') % e)
|
||||
if result['status'] != 'OK':
|
||||
return None
|
||||
|
||||
try:
|
||||
geo = result['results'][0]['geometry']['location']
|
||||
return float(geo['lat']), float(geo['lng'])
|
||||
except (KeyError, ValueError):
|
||||
return None
|
||||
|
||||
def geo_query_address(street=None, zip=None, city=None, state=None, country=None):
|
||||
if country and ',' in country and (country.endswith(' of') or country.endswith(' of the')):
|
||||
# put country qualifier in front, otherwise GMap gives wrong results,
|
||||
# e.g. 'Congo, Democratic Republic of the' => 'Democratic Republic of the Congo'
|
||||
country = '{1} {0}'.format(*country.split(',',1))
|
||||
return tools.ustr(', '.join(filter(None, [street,
|
||||
("%s %s" % (zip or '', city or '')).strip(),
|
||||
state,
|
||||
country])))
|
||||
|
||||
class res_partner_grade(osv.osv):
|
||||
_order = 'sequence'
|
||||
|
@ -88,9 +54,6 @@ class res_partner_activation(osv.osv):
|
|||
class res_partner(osv.osv):
|
||||
_inherit = "res.partner"
|
||||
_columns = {
|
||||
'partner_latitude': fields.float('Geo Latitude'),
|
||||
'partner_longitude': fields.float('Geo Longitude'),
|
||||
'date_localization': fields.date('Geo Localization Date'),
|
||||
'partner_weight': fields.integer('Grade Weight',
|
||||
help="Gives the probability to assign a lead to this partner. (0 means no assignation.)"),
|
||||
'opportunity_assigned_ids': fields.one2many('crm.lead', 'partner_assigned_id',\
|
||||
|
@ -100,6 +63,14 @@ class res_partner(osv.osv):
|
|||
'date_partnership' : fields.date('Partnership Date'),
|
||||
'date_review' : fields.date('Latest Partner Review'),
|
||||
'date_review_next' : fields.date('Next Partner Review'),
|
||||
# customer implementation
|
||||
'assigned_partner_id': fields.many2one(
|
||||
'res.partner', 'Implementedy by',
|
||||
),
|
||||
'implemented_partner_ids': fields.one2many(
|
||||
'res.partner', 'assigned_partner_id',
|
||||
string='Implementation References',
|
||||
),
|
||||
}
|
||||
_defaults = {
|
||||
'partner_weight': lambda *args: 0
|
||||
|
@ -111,23 +82,7 @@ class res_partner(osv.osv):
|
|||
partner_grade = self.pool.get('res.partner.grade').browse(cr, uid, grade_id)
|
||||
res['value']['partner_weight'] = partner_grade.partner_weight
|
||||
return res
|
||||
def geo_localize(self, cr, uid, ids, context=None):
|
||||
# Don't pass context to browse()! We need country names in english below
|
||||
for partner in self.browse(cr, uid, ids):
|
||||
if not partner:
|
||||
continue
|
||||
result = geo_find(geo_query_address(street=partner.street,
|
||||
zip=partner.zip,
|
||||
city=partner.city,
|
||||
state=partner.state_id.name,
|
||||
country=partner.country_id.name))
|
||||
if result:
|
||||
self.write(cr, uid, [partner.id], {
|
||||
'partner_latitude': result[0],
|
||||
'partner_longitude': result[1],
|
||||
'date_localization': fields.date.context_today(self,cr,uid,context=context)
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
|
||||
class crm_lead(osv.osv):
|
||||
_inherit = "crm.lead"
|
||||
|
|
|
@ -3,25 +3,10 @@
|
|||
<data>
|
||||
|
||||
<!-- Partner and address -->
|
||||
<record id="res_partner_access" model="ir.model.access">
|
||||
<field name="name">openerp.portal.res.partner</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="group_id" ref="portal.group_portal"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
<field name="perm_unlink" eval="0"/>
|
||||
</record>
|
||||
<record id="res_partner_rule" model="ir.rule">
|
||||
<field name="name">openerp.portal.res.partner</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="groups" eval="[(6,0,[ref('portal.group_portal')])]"/>
|
||||
<field name="domain_force">[('id','child_of',user.commercial_partner_id.id)]</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_access" model="ir.model.access">
|
||||
<field name="name">openerp.portal.res.partner.grade</field>
|
||||
<field name="model_id" ref="crm_partner_assign.model_res_partner_grade"/>
|
||||
<field name="group_id" ref="portal.group_portal"/>
|
||||
<field name="group_id" ref="base.group_portal"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
<field name="perm_write" eval="0"/>
|
||||
|
@ -32,13 +17,13 @@
|
|||
<record id="assigned_lead_portal_rule_1" model="ir.rule">
|
||||
<field name="name">openerp.portal.crm.lead</field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<field name="groups" eval="[(6,0,[ref('portal.group_portal')])]"/>
|
||||
<field name="groups" eval="[(6,0,[ref('base.group_portal')])]"/>
|
||||
<field name="domain_force">[('partner_assigned_id','child_of',user.commercial_partner_id.id)]</field>
|
||||
</record>
|
||||
<record id="lead_portal_access" model="ir.model.access">
|
||||
<field name="name">openerp.portal.crm.lead</field>
|
||||
<field name="model_id" ref="crm.model_crm_lead"/>
|
||||
<field name="group_id" ref="portal.group_portal"/>
|
||||
<field name="group_id" ref="base.group_portal"/>
|
||||
<field name="perm_read" eval="1"/>
|
||||
<field name="perm_create" eval="0"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
|
|
|
@ -9,5 +9,9 @@
|
|||
<field name="grade_id" ref="res_partner_grade_first"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record model="res.partner" id="base.res_partner_13">
|
||||
<field name="assigned_partner_id" eval="ref('base.res_partner_15')"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -98,13 +98,14 @@
|
|||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_crm_partner_geo_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.geo.inherit</field>
|
||||
<record id="view_crm_partner_assign_form" model="ir.ui.view">
|
||||
<field name="name">res.partner.assign.inherit</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="inherit_id" ref="base_geolocalize.view_crm_partner_geo_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<page string="Geo Localization">
|
||||
<xpath expr="//page[@name='geo_localization']" position="replace">
|
||||
<!-- <xpath expr="//notebook[last()]" position="inside"> -->
|
||||
<page string="Geo Localization" name="geo_localization">
|
||||
<group>
|
||||
<group>
|
||||
<separator string="Partner Activation" colspan="2"/>
|
||||
|
|
|
@ -5,4 +5,4 @@ access_crm_partner_report,crm.partner.report.assign.all,model_crm_partner_report
|
|||
access_res_partner_grade,res.partner.grade,model_res_partner_grade,base.group_sale_salesman,1,1,1,0
|
||||
access_res_partner_grade_manager,res.partner.grade.manager,model_res_partner_grade,base.group_sale_manager,1,1,1,1
|
||||
"access_partner_activation_manager","res.partner.activation.manager","model_res_partner_activation","base.group_partner_manager",1,1,1,1
|
||||
partner_access_crm_lead,crm.lead,model_crm_lead,portal.group_portal,1,1,0,0
|
||||
partner_access_crm_lead,crm.lead,model_crm_lead,base.group_portal,1,1,0,0
|
|
|
@ -87,7 +87,7 @@ class crm_lead_forward_to_partner(osv.TransientModel):
|
|||
raise osv.except_osv(_('Email Template Error'),
|
||||
_('The Forward Email Template is not in the database'))
|
||||
try:
|
||||
portal_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')[1]
|
||||
portal_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'group_portal')[1]
|
||||
except ValueError:
|
||||
raise osv.except_osv(_('Portal Group Error'),
|
||||
_('The Portal group cannot be found'))
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
# Estonian translation for openobject-addons
|
||||
# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
|
||||
# This file is distributed under the same license as the openobject-addons package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openobject-addons\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-12-21 17:05+0000\n"
|
||||
"PO-Revision-Date: 2013-10-09 15:39+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Estonian <et@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2013-10-10 04:41+0000\n"
|
||||
"X-Generator: Launchpad (build 16799)\n"
|
||||
|
||||
#. module: crm_todo
|
||||
#: model:ir.model,name:crm_todo.model_project_task
|
||||
msgid "Task"
|
||||
msgstr "Ülesanne"
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "Timebox"
|
||||
msgstr "Ajalahter"
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "Lead"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "For cancelling the task"
|
||||
msgstr "Ülesande katkestamiseks"
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "Next"
|
||||
msgstr "Järgmine"
|
||||
|
||||
#. module: crm_todo
|
||||
#: model:ir.actions.act_window,name:crm_todo.crm_todo_action
|
||||
#: model:ir.ui.menu,name:crm_todo.menu_crm_todo
|
||||
msgid "My Tasks"
|
||||
msgstr "Minu ülesanded"
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
#: field:crm.lead,task_ids:0
|
||||
msgid "Tasks"
|
||||
msgstr "Ülesanded"
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "Done"
|
||||
msgstr "Valmis"
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "Cancel"
|
||||
msgstr "Katkesta"
|
||||
|
||||
#. module: crm_todo
|
||||
#: model:ir.model,name:crm_todo.model_crm_lead
|
||||
msgid "Lead/Opportunity"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_todo
|
||||
#: field:project.task,lead_id:0
|
||||
msgid "Lead / Opportunity"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "For changing to done state"
|
||||
msgstr ""
|
||||
|
||||
#. module: crm_todo
|
||||
#: view:crm.lead:0
|
||||
msgid "Previous"
|
||||
msgstr "Eelmine"
|
|
@ -227,7 +227,7 @@
|
|||
</i>
|
||||
</t>
|
||||
</p>
|
||||
<div groups="base.group_user,portal.group_portal">
|
||||
<div groups="base.group_user,base.group_portal">
|
||||
<t t-if="record.register_avail.raw_value gt 0 and record.register_avail.raw_value lt 9999">
|
||||
<t t-if="!record.is_subscribed.raw_value">
|
||||
<input t-att-id="record.id.raw_value" type="text" name="subscribe" class="no_of_seats" value="1" onchange="document.getElementById('btn_sub' +this.id).setAttribute('data-context',JSON.stringify({'ticket':this.value}))"/>
|
||||
|
|
|
@ -133,7 +133,7 @@ class hr_si_project(osv.osv_memory):
|
|||
|
||||
def check_state(self, cr, uid, ids, context=None):
|
||||
obj_model = self.pool.get('ir.model.data')
|
||||
emp_id = self.default_get(cr, uid, context)['emp_id']
|
||||
emp_id = self.default_get(cr, uid, ['emp_id'], context)['emp_id']
|
||||
# get the latest action (sign_in or out) for this employee
|
||||
cr.execute('select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1', (emp_id,))
|
||||
res = (cr.fetchone() or ('sign_out',))[0]
|
||||
|
|
|
@ -2,7 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|||
access_ls_chann1,im_livechat.channel,model_im_livechat_channel,,1,0,0,0
|
||||
access_ls_chann2,im_livechat.channel,model_im_livechat_channel,group_im_livechat,1,1,1,0
|
||||
access_ls_chann3,im_livechat.channel,model_im_livechat_channel,group_im_livechat_manager,1,1,1,1
|
||||
access_ls_message_portal,im_livechat.im.message.portal,im.model_im_message,portal.group_portal,0,0,0,0
|
||||
access_im_user_portal,im_livechat.im.user.portal,im.model_im_user,portal.group_portal,1,0,0,0
|
||||
access_ls_message_portal,im_livechat.im.message.portal,im.model_im_message,base.group_portal,0,0,0,0
|
||||
access_im_user_portal,im_livechat.im.user.portal,im.model_im_user,base.group_portal,1,0,0,0
|
||||
access_ls_message,im_livechat.im.message,im.model_im_message,base.group_public,0,0,0,0
|
||||
access_im_user,im_livechat.im.user,im.model_im_user,base.group_public,1,0,0,0
|
|
|
@ -34,15 +34,23 @@
|
|||
<field name="image">/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCACAAIADASIAAhEBAxEB/8QAHAAAAgIDAQEAAAAAAAAAAAAAAAcFBgECBAMI/8QATRAAAQIEAQQLDAUKBwEAAAAAAQIDAAQFEQYHEiExExdBU1VxkpOU0dIUFRYiMlFUVmGBkbE2QlKjwSMkRXSDobKzwsMIJTNGc4KE4f/EABoBAAIDAQEAAAAAAAAAAAAAAAAEAQIDBQb/xAAxEQABAwICCQMDBAMAAAAAAAABAAIDBBESUgUTFCExQVGRoVNh0RUisQYjceGB8PH/2gAMAwEAAhEDEQA/APsuCCCBCIIIIEIggggQiCCCBCIIIIEIggggQiCCCBCIIIIEIggggQuJ53PmVS6VlOagLXbQTckDTueSYyGmNWwt8kRytrJqU8o/VWhscQQFfNZik5XcR1mgil96Zwy2zl0ufk0Lzs3Mt5QNvKOqMZJRG0vdySVVUtp4zI/gOn82TCDTO8tcgRuGmN5a5Ij592xcZ8Mq6O12INsbGfDKujtdiE/qUPQ+PlcsfqGmyu7D5X0HsDG8t8kRjYWb/wCk3yRHz7ti4z4ZPR2uxDByN4jrVfVVe+06ZkMbEW/yaE5udn38kC/kjXGkNbFI8MaDcpml0zT1MoiYDc9R7X6phbCxvSOSINhZ3lvkiF5ldrNSpk/Tm5GedlkONuKXsarXIKQPnFI8KsQcOTfLi8lS1ji2ydkqmRuLSE+thY3pvkiMFljeW+SIQ3hTX+G5vnIPCmv8NzfORntrcqz21nRPctM7y1yBGqmmd5a5IhFeFNf4bm+ci/5KqtPVORnxPTa5pTLyQhThuQCm9r8YjSOpbI7CArR1TZHYQFclKEvmKSqzZWlCkbnjGwt5tJEdx1REVdZTTX1jW2nZBxpIUPlEwNUMtTTCiCCCLK6g2V50zPODUqZI5KEJ+aTC3y8G6KJxv/24YMorxHiEgXmH9AvuOqF9PFC7y6G7VEPtmP7cIVZ/Zd/vNcTS5vSSf4/IS9osmmfqjEotZQhavGI12AJNvbohkNUmhIlNhFMlVJta6k3Vytf74WtJmhJVBmZKSoIJuBrsQQfnDBMxmtlSlgIAuVE6APPHMpmAgrhaKazA64BN/ComIZRqRrMxLMm7SVBSPYFAKA917X9kMj/D4bd/T7GP7kLKrzYnqi9NJSUpWRYHXYAAfKGTkCNkV3/z/wBcTR22kW9/wVTRVvqALeFzbsUxa3XKRSlNJqcy20XAS2FNqWSBr1A2iP8ADLCJ/SLPR19mIDKlhep4lVJGn7EAwlQWVrA1nRrik7VuJPtSvOJ646Ms0zXkNZcL1Ms8rXkNZcJqHGWEuEWejr7MaHGOE+EWOjr7MK7atxJ9qV5xPXGNq3Ef25XnE9cZbRPk8LPaJ/TTROMMK8JMdHX2Y7aRW6VVFOppky28WgC4EtqTa+rWBfVCgOS/EQ1rlecT1xcMmmGanhuZnFTymSh5sBOYsE3uNwewGLxzylwDm2CtHPKXWcywV2qN3KdNNg6VMLSOMpMTEs6Hpdt1PkuICh7xeIfOzvF+1ojuw+oLoUgoWsZZv+EQ8w707EbkrviLz1zSAtRIQoXSm+ix1X8+iOmsuFqkTjovdEutQt7EmMMtJQlLYGhIAtxRLt+5MBcbcjKoSEplmkpGoBAAEaTdEpE6UmcpclMlOhJdYSu3FcQsa7lOr8jW56SZlKYW5eZcaQVNrKilKiBeyteiOPbZxJ6FSuZc7cImqgBsfwuLJpmjuWu/CaowvhvgCl9Fb6o6+89KtbvbJ2/4U9UKDbaxH6HSuZc7cG23iT0Sl80524BWUw/4qDTNA3gPCawwthvgCl9FR1R0SVEpEiVGSpclLFehRaYSjO47DTGcPTjtQw/IT7oQl2Ylm3VBF80KUkE2vuaYSj+O8Zd0OhFeCEhxQCe5GTYAkfZjWaWKEAlvHoAnZZ4IA12DjwsAnn3JLbw3yYwZSW3hHJhFeHeNPWEdDa7MHh3jP1gHQ2uzGG3xZT4+Vn9ThyHx8p5qlJfeG/hGhlJfeUcmEd4dYz9YB0NrswLx3jJKSrv8k2F7dxtdmI26LKfHyj6pDkPj5TtXJs/VQEnzp0GIRdTS3iFdEdYmA8GQ8h7Mu2tJztFx5KhmnQbX02vZVrKwQ6w27o8dAVo1aReKfiChleUinYgEyECXpr0uWcy+yZyhpvfRbihqQYQC1OzgYQ4KYSuyhxxIYZSpNGZSrNJSVpGaoEWC1AavZubmqIgm0SWEnM6RmGt7m3hylFf9UWiP3LKA/cuuvqIpLyQbFea3ylBP4x7Dy/fHNXyO5GkG91zTIHucSr8I90nxhxxqTYptfNWL/pbV/wBee/mKiWwPQJKpNOTdQznG0r2NLQUUgmwJJI07o1RE4v8ApZWf197+YqLDgWfb7hVJgJS62oqsNagTr/D4R50AGY3Xh9Hwxy17myb+Nh7ruxJhajJpT70gwqVeZbU4CHFLCs0XIIUTrA3N2F3DKxDVEyNNccWlLilgoShWpRI3fZC1is4AIsr6dhhilaGAA2328L6ZwR9DaL+os/wJiJEzk6SSlb+F0qBNwVMaDuxK4LI8DKOLgXkGf4EwgZvA+J1Tby04eeUFOKIOYnSCT7Y7M8xjY2zb7vhejkmdHGyzb7vhOruzJt6RhflsRgzmTf0jC3LYhJeA2KvVt/kJ64PAXFPq4/yE9cK7U/0/Cw2x/peE7TOZN/SMLc4xGDN5OCDeYwtbd8diEn4C4p9XH+Qnrg8BcU+rj/IT1wbU/wBPwp2x/p+F9JsracYQtlSVNKSChSSCkptoItuWiHr+ipSavtNuJ/hMYwYzNSeEaTKTbRafZlG0ONn6pCQLRzYzn5SmokZ2eeDLIeLZWQTpUk2Gjih577x3PsulIbxXKwYkcKOJPfFoICVImRnEX8a7TZufjbR5op8zjDD7aAUTyHFEhIHkC51XUuyUj2k2EWLJoJp+hLqs63sT1QeL4b+wiwSge5IAiITidcJenOJ1wpevE7LTk7ipvT7m3D8wI9G3rrSLayI5a+r/ADWmt31B5z4JCf64GXQlxCjewNzFnus9OpMVPDUzU8R1WbU+hllyefzdGco2dUNW5pB3Yl6Jh5imZ6mlOOOLFipXm9gEMBqh0htbqg5NHZHlum5TrWsrNtGq6jHQKVSR9aY+I6oUFO29+aUptH08LtYG/dzPueKX9VozFRZDcyi+bfMIJGaSLX+R9wipVbCU1KsuPy7yX0oSVKSU5qrDzbhh296qUd2Y+IjyeodIdQpBXNAKBBspO77oh1K1/FFXo+nqt727+vNemEVE4TooG7IMfyxFUmsr2DZeZel1vT6ltOKbUUySiLg2NvhFzkGWZGRlJJgrU1LMoaRnkZ1kiwJtovYQk5/JBiN+fmZhuo0oIdeWtOc44DYqJF/E9sXme9oAYFWZ00TGiMXPNXXbkwXvtS6EqDbjwXv1S6EqKHtN4m4SpHOOdiMbTmJuEqRzjnYhfWz9EvtFZk8f2r5tx4K36pdCVBtxYL36pdCVFD2nMTcJUjnHOxGNp3EvCVI5xzsQa2fojaKzJ4/tOzD1bka9R2KtTXFrlX75hWgpVoJBBB1aQYiMo9ARiihS9JcmnpULnWjsrSrKTrH4xrk7os3hzCcvSJ59h59pxxRUySU2UokAXAO75olqm4EsNLJICJlhZ4g6i/7rw2xxIGJdJhLoxj423qoYcyJ0Snz7c3UqhO1PYlZyG3nCpIPn0w02kIaaS22kJQkAJA1ARvBfRDoAG4K4AG4KvV1d8QyyLD8nJunlLb7MaBUReUSo94ajTqy8kmRUlUrMlI0oBIKVe4i3vMeTWI6C4gLFXkwDpAU6En4HTCUxwvN1Uva02JU2DHhMz7EsCXL6NBsL6YjxiGhD9MyHPp645puqYZmQUu1qSsrSSJhIt7dcZYxyKqZW8nBe7uKqY2ohSZg2OmyBr+MeBxtR0mxE0P2Y64i3ZXBr689dZlk5wOdaaFgfjHE5SsCKsXK7LpJBKvz1Og+bXACeqyxuHBwVkRjOjK+u+ONH/wBj1Ti2jq1OPciKomlZPk/p+W1enJ1+bXHu3Tsn41V2VOj00a/jBiPUIEjswVo8KKVm32Rzkx5HFlIvbZHeRECqTwBm27+So/8AaOuPLuDJ5e/f6V6cmDF7qdY7MFZ0YmpS9Trg/wCsavYmpbetTxv5kCK83K4ATpTXJM6N2dHXGzrOBFAjv9JDRo/PE9cAPuoxuzBWGWxBTpkgNl0E6PGTHpWZhKqHNuINwhlTnJ8b8IrUsnBEsrOar8mTrF5xOv4x3TNXozqW6ZIzzEy5NkN2Q4FeKdf7tHvESDv4q7ZORKZcEEEdNbrgrlLk6zS3qdPtBxh5NlJMJ6fyHzomFClYrfl5W/iNuJzikebSDDwjU8cUcxr9zhdVcxrhZwukSch9f3cZHmh2YE5D67f6Yk/sh2Ye8EV1EeULPZ48oSMTkSrYFjjBXNDsxovIbWlafC37odmHqIzBqY8oRqI8o7JC7RFYv9LPuR2Y3TkJqwH0s+5HVD4tBaDUx5R2RqI8o7JDKyE1g/7sHMjsxptEVj1sHMjsw/LQWg1MeUdkaiPKOyQ4yE1YD6WfcjqjRWQmr+tg5kdmH0IDxwaiPKEaiPKOyQqcg9XvpxZ9yOqLrk7yZS+GZvu+eqTlSmk6G85ICU+21oYpjU+6JETAbgBSImNNwAt4III0Wq//2Q==</field>
|
||||
</record>
|
||||
|
||||
<!-- Join Memberships -->
|
||||
<!-- Join Memberships -->
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_2'), ref('membership_0'), {'amount':180})"/>
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_10'), ref('membership_0'), {'amount':180})"/>
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_12'), ref('membership_0'), {'amount':180})"/>
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_13'), ref('membership_0'), {'amount':180})"/>
|
||||
|
||||
<!-- Demo data for free member -->
|
||||
<record id="base.res_partner_12" model="res.partner">
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_18'), ref('membership_1'), {'amount':180})"/>
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_21'), ref('membership_1'), {'amount':180})"/>
|
||||
|
||||
<function model="res.partner" name="create_membership_invoice" eval="(ref('base.res_partner_9'), ref('membership_2'), {'amount':180})"/>
|
||||
|
||||
<!-- Demo data for free member -->
|
||||
<record id="base.res_partner_18" model="res.partner">
|
||||
<field name="free_member">True</field>
|
||||
</record>
|
||||
|
||||
<!-- Demo data for associate member -->
|
||||
<!-- Demo data for associate member -->
|
||||
<record id="base.res_partner_9" model="res.partner">
|
||||
<field name="associate_member" ref="base.res_partner_2"/>
|
||||
</record>
|
||||
|
|
|
@ -143,7 +143,7 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa
|
|||
var self = this;
|
||||
this._super();
|
||||
this.$el.click(function(){
|
||||
self.order.selectLine(this.model);
|
||||
self.order.selectLine(self.model);
|
||||
self.trigger('order_line_selected');
|
||||
});
|
||||
if(this.model.is_selected()){
|
||||
|
|
|
@ -49,7 +49,6 @@ very handy when used in combination with the module 'share'.
|
|||
'wizard/share_wizard_view.xml',
|
||||
'acquirer_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/portal_security.xml',
|
||||
],
|
||||
'demo': ['portal_demo.xml'],
|
||||
'css': ['static/src/css/portal.css'],
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<data noupdate="1">
|
||||
|
||||
<!-- The portal group -->
|
||||
<record id="group_portal" model="res.groups">
|
||||
<record id="base.group_portal" model="res.groups">
|
||||
<field name="name">Portal</field>
|
||||
<field name="comment">Portal members have specific access rights (such as record rules and restricted menus).
|
||||
They usually do not belong to the usual OpenERP groups.</field>
|
||||
|
|
|
@ -22,7 +22,7 @@ Mr Demo Portal</field>
|
|||
</record>
|
||||
|
||||
<!-- Add the demo user to the portal (and therefore to the portal member group) -->
|
||||
<record id="group_portal" model="res.groups">
|
||||
<record id="base.group_portal" model="res.groups">
|
||||
<field name="users" eval="[(4,ref('demo_user0'))]"/>
|
||||
</record>
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
<!-- Top menu item -->
|
||||
<menuitem name="Portal"
|
||||
id="portal_menu"
|
||||
groups="portal.group_portal"
|
||||
groups="base.group_portal"
|
||||
sequence="15"/>
|
||||
|
||||
<menuitem name="Messaging" id="portal_messages" parent="portal_menu" sequence="10" groups="portal.group_portal"/>
|
||||
<menuitem name="Messaging" id="portal_messages" parent="portal_menu" sequence="10" groups="base.group_portal"/>
|
||||
|
||||
<record id="action_mail_inbox_feeds_portal" model="ir.actions.client">
|
||||
<field name="name">Inbox</field>
|
||||
|
@ -99,9 +99,9 @@
|
|||
</record>
|
||||
|
||||
<menuitem name="Inbox" id="portal_inbox" parent="portal_messages"
|
||||
action="action_mail_inbox_feeds_portal" sequence="10" groups="portal.group_portal"/>
|
||||
action="action_mail_inbox_feeds_portal" sequence="10" groups="base.group_portal"/>
|
||||
<menuitem name="Archives" id="portal_mail_archivesfeeds" parent="portal_messages"
|
||||
action="action_mail_archives_feeds_portal" sequence="30" groups="portal.group_portal"/>
|
||||
action="action_mail_archives_feeds_portal" sequence="30" groups="base.group_portal"/>
|
||||
|
||||
<!--
|
||||
Create menu items that we'll leave empty for now - they'll be
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_mail_message_portal,mail.message.portal,mail.model_mail_message,group_portal,1,1,1,1
|
||||
access_mail_mail_portal,mail.mail.portal,mail.model_mail_mail,group_portal,1,1,1,0
|
||||
access_mail_notification_portal,mail.notification.portal,mail.model_mail_notification,group_portal,1,1,1,0
|
||||
access_mail_followers_portal,mail.followers.portal,mail.model_mail_followers,group_portal,1,1,0,0
|
||||
access_res_partner_portal,res.partner.portal,base.model_res_partner,portal.group_portal,1,0,0,0
|
||||
access_mail_message_portal,mail.message.portal,mail.model_mail_message,base.group_portal,1,1,1,1
|
||||
access_mail_mail_portal,mail.mail.portal,mail.model_mail_mail,base.group_portal,1,1,1,0
|
||||
access_mail_notification_portal,mail.notification.portal,mail.model_mail_notification,base.group_portal,1,1,1,0
|
||||
access_mail_followers_portal,mail.followers.portal,mail.model_mail_followers,base.group_portal,1,1,0,0
|
||||
access_acquirer,portal.payment.acquirer,portal.model_portal_payment_acquirer,,1,0,0,0
|
||||
access_acquirer_all,portal.payment.acquirer,portal.model_portal_payment_acquirer,base.group_system,1,1,1,1
|
||||
access_ir_attachment_group_portal,ir.attachment group_portal,base.model_ir_attachment,portal.group_portal,1,0,1,0
|
||||
access_ir_attachment_group_portal,ir.attachment group_portal,base.model_ir_attachment,base.group_portal,1,0,1,0
|
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="portal_read_own_res_partner" model="ir.rule">
|
||||
<field name="name">res_partner: read access on my partner</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="domain_force">[('id', 'child_of', user.commercial_partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('group_portal')), (4, ref('base.group_public'))]"/>
|
||||
<field name="perm_create" eval="False"/>
|
||||
<field name="perm_unlink" eval="False"/>
|
||||
<field name="perm_write" eval="False"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -31,7 +31,7 @@ class test_portal(TestMail):
|
|||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Find Portal group
|
||||
group_portal = self.registry('ir.model.data').get_object(cr, uid, 'portal', 'group_portal')
|
||||
group_portal = self.registry('ir.model.data').get_object(cr, uid, 'base', 'group_portal')
|
||||
self.group_portal_id = group_portal.id
|
||||
|
||||
# Create Chell (portal user)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_crm_claim,crm.claim,crm_claim.model_crm_claim,portal.group_portal,1,0,1,0
|
||||
access_crm_claim_stage,crm.claim.stage,crm_claim.model_crm_claim_stage,portal.group_portal,1,0,0,0
|
||||
access_crm_claim,crm.claim,crm_claim.model_crm_claim,base.group_portal,1,0,1,0
|
||||
access_crm_claim_stage,crm.claim.stage,crm_claim.model_crm_claim_stage,base.group_portal,1,0,0,0
|
||||
|
|
|
|
@ -6,7 +6,7 @@
|
|||
<field name="name">Portal Personal Claims</field>
|
||||
<field ref="crm_claim.model_crm_claim" name="model_id"/>
|
||||
<field name="domain_force">[('message_follower_ids','in', [user.partner_id.id])]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_event,event,event.model_event_event,portal.group_portal,1,0,0,0
|
||||
access_registration,registration,event.model_event_registration,portal.group_portal,1,1,1,1
|
||||
access_event,event,event.model_event_event,base.group_portal,1,0,0,0
|
||||
access_registration,registration,event.model_event_registration,base.group_portal,1,1,1,1
|
||||
access_event,event,event.model_event_event,base.group_public,1,0,0,0
|
||||
access_registration,registration,event.model_event_registration,base.group_public,1,1,1,1
|
||||
|
|
|
|
@ -10,14 +10,14 @@
|
|||
('message_follower_ids', 'in', [user.partner_id.id])
|
||||
]
|
||||
</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal')), (4, ref('base.group_public'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="event_registration_website_rule">
|
||||
<field name="name">Event/Registration: portal and public users: personal only</field>
|
||||
<field name="model_id" ref="event.model_event_registration"/>
|
||||
<field name="domain_force">[('user_id', '=', user.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal')), (4, ref('base.group_public'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_public'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_hr_employee_portal,hr.employee user,hr.model_hr_employee,portal.group_portal,1,0,0,0
|
||||
access_hr_employee_portal,hr.employee user,hr.model_hr_employee,base.group_portal,1,0,0,0
|
||||
access_hr_employee_public,hr.employee user,hr.model_hr_employee,base.group_public,1,0,0,0
|
||||
|
|
|
|
@ -1,10 +1,10 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_project,project,project.model_project_project,portal.group_portal,1,0,0,0
|
||||
access_task,task,project.model_project_task,portal.group_portal,1,0,0,0
|
||||
access_task_type,task_type,project.model_project_task_type,portal.group_portal,1,0,0,0
|
||||
access_task_work,task_work,project.model_project_task_work,portal.group_portal,1,0,0,0
|
||||
access_project_category,project_category,project.model_project_category,portal.group_portal,1,0,0,0
|
||||
access_account_analytic_account,account_analytic_account,analytic.model_account_analytic_account,portal.group_portal,1,0,0,0
|
||||
access_project,project,project.model_project_project,base.group_portal,1,0,0,0
|
||||
access_task,task,project.model_project_task,base.group_portal,1,0,0,0
|
||||
access_task_type,task_type,project.model_project_task_type,base.group_portal,1,0,0,0
|
||||
access_task_work,task_work,project.model_project_task_work,base.group_portal,1,0,0,0
|
||||
access_project_category,project_category,project.model_project_category,base.group_portal,1,0,0,0
|
||||
access_account_analytic_account,account_analytic_account,analytic.model_account_analytic_account,base.group_portal,1,0,0,0
|
||||
access_project_public,project,project.model_project_project,base.group_public,1,0,0,0
|
||||
access_task_public,task,project.model_project_task,base.group_public,1,0,0,0
|
||||
access_task_type_public,task_type,project.model_project_task_type,base.group_public,1,0,0,0
|
||||
|
|
|
|
@ -22,7 +22,7 @@
|
|||
('privacy_visibility', '=', 'followers'),
|
||||
('message_follower_ids', 'in', [user.partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_public_rule">
|
||||
|
@ -54,7 +54,7 @@
|
|||
('project_id.privacy_visibility', '=', 'followers'),
|
||||
('message_follower_ids', 'in', [user.partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="task_public_rule">
|
||||
|
|
|
@ -31,7 +31,7 @@ class TestPortalProjectBase(TestProjectBase):
|
|||
cr, uid = self.cr, self.uid
|
||||
|
||||
# Find Portal group
|
||||
group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal')
|
||||
group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_portal')
|
||||
self.group_portal_id = group_portal_ref and group_portal_ref[1] or False
|
||||
|
||||
# Find Public group
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_issues,project_issue,project_issue.model_project_issue,portal.group_portal,1,0,0,0
|
||||
access_case_section,crm_case_section,crm.model_crm_case_section,portal.group_portal,1,0,0,0
|
||||
access_issues,project_issue,project_issue.model_project_issue,base.group_portal,1,0,0,0
|
||||
access_case_section,crm_case_section,crm.model_crm_case_section,base.group_portal,1,0,0,0
|
||||
access_issues_public,project_issue,project_issue.model_project_issue,base.group_public,1,0,0,0
|
|
|
@ -14,7 +14,7 @@
|
|||
('project_id.privacy_visibility', '=', 'followers'),
|
||||
('message_follower_ids', 'in', [user.partner_id.id]),
|
||||
]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_issue.issue_user_rule">
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_issues,project_phase,project_long_term.model_project_phase,portal.group_portal,1,0,0,0
|
||||
access_issues,project_phase,project_long_term.model_project_phase,base.group_portal,1,0,0,0
|
||||
access_issues_public,project_phase_public,project_long_term.model_project_phase,base.group_public,1,0,0,0
|
||||
|
|
|
|
@ -6,7 +6,7 @@
|
|||
<field name="name">Project/Phase: portal users: public or (portal and colleagues following) or (followers and following)</field>
|
||||
<field name="model_id" ref="project_long_term.model_project_phase"/>
|
||||
<field name="domain_force">[('project_id.privacy_visibility', 'in', ['public', 'portal'])]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="project_phase_public_rule">
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_sale_order,sale.order,sale.model_sale_order,portal.group_portal,1,0,0,0
|
||||
access_sale_order_line,sale.order.line,sale.model_sale_order_line,portal.group_portal,1,0,0,0
|
||||
access_account_invoice,account.invoice,account.model_account_invoice,portal.group_portal,1,0,0,0
|
||||
access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,portal.group_portal,1,0,0,0
|
||||
access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,portal.group_portal,1,0,0,0
|
||||
access_account_journal,account.journal,account.model_account_journal,portal.group_portal,1,0,0,0
|
||||
access_account_voucher,account.voucher,account_voucher.model_account_voucher,portal.group_portal,1,0,0,0
|
||||
access_account_voucher_line,account.voucher.line,account_voucher.model_account_voucher_line,portal.group_portal,1,0,0,0
|
||||
access_account_move,account.move,account.model_account_move,portal.group_portal,1,0,0,0
|
||||
access_account_move_line,account.move.line,account.model_account_move_line,portal.group_portal,1,0,0,0
|
||||
access_account_move_reconcile,account.move.reconcile,account.model_account_move_reconcile,portal.group_portal,1,0,0,0
|
||||
access_account_fiscalyear,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,portal.group_portal,1,0,0,0
|
||||
access_product_list,product.pricelist,product.model_product_pricelist,portal.group_portal,1,0,0,0
|
||||
access_res_partner,res.partner,base.model_res_partner,portal.group_portal,1,0,0,0
|
||||
access_account_tax,account.tax,account.model_account_tax,portal.group_portal,1,0,0,0
|
||||
access_account_fiscalyear,account.fiscalyear,account.model_account_fiscalyear,portal.group_portal,1,0,0,0
|
||||
access_res_partner_category,res.partner.category,base.model_res_partner_category,portal.group_portal,1,0,0,0
|
||||
access_account_period,account.period,account.model_account_period,portal.group_portal,1,0,0,0
|
||||
access_account_account,account.account,account.model_account_account,portal.group_portal,1,0,0,0
|
||||
access_sale_order,sale.order,sale.model_sale_order,base.group_portal,1,0,0,0
|
||||
access_sale_order_line,sale.order.line,sale.model_sale_order_line,base.group_portal,1,0,0,0
|
||||
access_account_invoice,account.invoice,account.model_account_invoice,base.group_portal,1,0,0,0
|
||||
access_account_invoice_tax,account.invoice.tax,account.model_account_invoice_tax,base.group_portal,1,0,0,0
|
||||
access_account_invoice_line,account.invoice.line,account.model_account_invoice_line,base.group_portal,1,0,0,0
|
||||
access_account_journal,account.journal,account.model_account_journal,base.group_portal,1,0,0,0
|
||||
access_account_voucher,account.voucher,account_voucher.model_account_voucher,base.group_portal,1,0,0,0
|
||||
access_account_voucher_line,account.voucher.line,account_voucher.model_account_voucher_line,base.group_portal,1,0,0,0
|
||||
access_account_move,account.move,account.model_account_move,base.group_portal,1,0,0,0
|
||||
access_account_move_line,account.move.line,account.model_account_move_line,base.group_portal,1,0,0,0
|
||||
access_account_move_reconcile,account.move.reconcile,account.model_account_move_reconcile,base.group_portal,1,0,0,0
|
||||
access_account_fiscalyear,account.sequence.fiscalyear,account.model_account_sequence_fiscalyear,base.group_portal,1,0,0,0
|
||||
access_product_list,product.pricelist,product.model_product_pricelist,base.group_portal,1,0,0,0
|
||||
access_res_partner,res.partner,base.model_res_partner,base.group_portal,1,0,0,0
|
||||
access_account_tax,account.tax,account.model_account_tax,base.group_portal,1,0,0,0
|
||||
access_account_fiscalyear,account.fiscalyear,account.model_account_fiscalyear,base.group_portal,1,0,0,0
|
||||
access_res_partner_category,res.partner.category,base.model_res_partner_category,base.group_portal,1,0,0,0
|
||||
access_account_period,account.period,account.model_account_period,base.group_portal,1,0,0,0
|
||||
access_account_account,account.account,account.model_account_account,base.group_portal,1,0,0,0
|
||||
|
|
|
|
@ -10,7 +10,7 @@ on Sale Orders and Customer Invoices. These options are meant for customers who
|
|||
their documents through the portal.</field>
|
||||
</record>
|
||||
<!-- Make the payment_options group implied for all portal users -->
|
||||
<record id="portal.group_portal" model="res.groups">
|
||||
<record id="base.group_portal" model="res.groups">
|
||||
<field name="implied_ids" eval="[(4,ref('group_payment_options'))]"/>
|
||||
</record>
|
||||
|
||||
|
@ -19,7 +19,7 @@ their documents through the portal.</field>
|
|||
<field name="name">Portal Personal Quotations/Sales Orders</field>
|
||||
<field name="model_id" ref="sale.model_sale_order"/>
|
||||
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
<field eval="1" name="perm_unlink"/>
|
||||
<field eval="1" name="perm_write"/>
|
||||
<field eval="1" name="perm_read"/>
|
||||
|
@ -30,7 +30,7 @@ their documents through the portal.</field>
|
|||
<field name="name">Portal Personal Account Invoices</field>
|
||||
<field name="model_id" ref="account.model_account_invoice"/>
|
||||
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="portal_personal_contact" model="ir.rule">
|
||||
|
@ -38,7 +38,7 @@ their documents through the portal.</field>
|
|||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
|
||||
<field eval="0" name="perm_read"/>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_picking,stock.picking,stock.model_stock_picking,portal.group_portal,1,0,0,0
|
||||
access_stock_picking.out,stock.picking.out,stock.model_stock_picking_out,portal.group_portal,1,0,0,0
|
||||
access_stock_move,stock.move,stock.model_stock_move,portal.group_portal,1,0,0,0
|
||||
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,procurement.model_stock_warehouse_orderpoint,portal.group_portal,1,0,0,0
|
||||
access_stock_picking,stock.picking,stock.model_stock_picking,base.group_portal,1,0,0,0
|
||||
access_stock_picking.out,stock.picking.out,stock.model_stock_picking_out,base.group_portal,1,0,0,0
|
||||
access_stock_move,stock.move,stock.model_stock_move,base.group_portal,1,0,0,0
|
||||
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,procurement.model_stock_warehouse_orderpoint,base.group_portal,1,0,0,0
|
||||
|
|
|
|
@ -7,14 +7,14 @@
|
|||
<field name="name">Portal Personal Pickings</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
||||
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="portal_stock_picking_out_user_rule" model="ir.rule">
|
||||
<field name="name">Portal Personal Out Pickings</field>
|
||||
<field name="model_id" ref="stock.model_stock_picking_out"/>
|
||||
<field name="domain_force">[('message_follower_ids','in',[user.partner_id.id])]</field>
|
||||
<field name="groups" eval="[(4, ref('portal.group_portal'))]"/>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
|
|
@ -93,8 +93,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="oe_right oe_button_box" name="buttons" groups="base.group_user">
|
||||
<button name="%(act_project_project_2_project_task_all)d" string="Tasks"
|
||||
type="action" attrs="{'invisible':[('use_tasks','=', 0)]}"/>
|
||||
<field name="tasks" widget="x2many_counter" string="Tasks" attrs="{'invisible':[('use_tasks','=', False)]}" options='{"views": [[false, "kanban"], [false, "tree"], [false, "form"], [false, "calendar"], [false, "gantt"], [false, "graph"]]}'/>
|
||||
<button name="attachment_tree_view" string="Documents" type="object"/>
|
||||
</div>
|
||||
<group>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,14 +12,14 @@ OpenERP Website CMS
|
|||
'depends': ['web', 'share'],
|
||||
'installable': True,
|
||||
'data': [
|
||||
'views/views.xml',
|
||||
'data/website_data.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/website_templates.xml',
|
||||
'views/website_views.xml',
|
||||
'views/snippets.xml',
|
||||
'views/themes.xml',
|
||||
'website_data.xml',
|
||||
'website_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': [
|
||||
'website_demo.xml',
|
||||
'data/website_demo.xml',
|
||||
]
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import json
|
|||
import logging
|
||||
import os
|
||||
import datetime
|
||||
import re
|
||||
|
||||
from sys import maxint
|
||||
|
||||
|
@ -17,7 +18,16 @@ import werkzeug.utils
|
|||
import werkzeug.wrappers
|
||||
from PIL import Image
|
||||
|
||||
try:
|
||||
from slugify import slugify
|
||||
except ImportError:
|
||||
def slugify(s, max_length=None):
|
||||
spaceless = re.sub(r'\s+', '-', s)
|
||||
specialless = re.sub(r'[^-_a-z0-9]', '', spaceless)
|
||||
return specialless[:max_length]
|
||||
|
||||
import openerp
|
||||
from openerp.osv import fields
|
||||
from openerp.addons.website.models import website
|
||||
from openerp.addons.web import http
|
||||
from openerp.addons.web.http import request
|
||||
|
@ -48,12 +58,9 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
# FIXME: auth, if /pagenew known anybody can create new empty page
|
||||
@website.route('/pagenew/<path:path>', type='http', auth="admin")
|
||||
def pagenew(self, path, noredirect=NOPE):
|
||||
if '.' in path:
|
||||
module, idname = path.split('.', 1)
|
||||
else:
|
||||
module = 'website'
|
||||
idname = path
|
||||
xid = "%s.%s" % (module, idname)
|
||||
module = 'website'
|
||||
# completely arbitrary max_length
|
||||
idname = slugify(path, max_length=50)
|
||||
|
||||
request.cr.execute('SAVEPOINT pagenew')
|
||||
imd = request.registry['ir.model.data']
|
||||
|
@ -65,8 +72,9 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
newview = view.browse(
|
||||
request.cr, request.uid, newview_id, context=request.context)
|
||||
newview.write({
|
||||
'arch': newview.arch.replace("website.default_page", xid),
|
||||
'name': "page/%s" % path,
|
||||
'arch': newview.arch.replace("website.default_page",
|
||||
"%s.%s" % (module, idname)),
|
||||
'name': path,
|
||||
'page': True,
|
||||
})
|
||||
# Fuck it, we're doing it live
|
||||
|
@ -79,10 +87,13 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
'noupdate': True
|
||||
}, context=request.context)
|
||||
except psycopg2.IntegrityError:
|
||||
logger.exception('Unable to create ir_model_data for page %s', path)
|
||||
request.cr.execute('ROLLBACK TO SAVEPOINT pagenew')
|
||||
return werkzeug.exceptions.InternalServerError()
|
||||
else:
|
||||
request.cr.execute('RELEASE SAVEPOINT pagenew')
|
||||
url = "/page/%s" % path
|
||||
|
||||
url = "/page/%s" % idname
|
||||
if noredirect is not NOPE:
|
||||
return werkzeug.wrappers.Response(url, mimetype='text/plain')
|
||||
return werkzeug.utils.redirect(url)
|
||||
|
@ -240,11 +251,16 @@ class Website(openerp.addons.web.controllers.main.Home):
|
|||
def publish(self, id, object):
|
||||
_id = int(id)
|
||||
_object = request.registry[object]
|
||||
|
||||
obj = _object.browse(request.cr, request.uid, _id)
|
||||
|
||||
values = {}
|
||||
if 'website_published' in _object._all_columns:
|
||||
values['website_published'] = not obj.website_published
|
||||
if 'website_published_datetime' in _object._all_columns and values.get('website_published'):
|
||||
values['website_published_datetime'] = fields.datetime.now()
|
||||
_object.write(request.cr, request.uid, [_id],
|
||||
{'website_published': not obj.website_published},
|
||||
context=request.context)
|
||||
values, context=request.context)
|
||||
|
||||
obj = _object.browse(request.cr, request.uid, _id)
|
||||
return obj.website_published and True or False
|
||||
|
||||
|
|
|
@ -39,14 +39,19 @@
|
|||
<field name="url">/</field>
|
||||
<field name="target">self</field>
|
||||
</record>
|
||||
<record id="action_website_tutorial" model="ir.actions.act_url">
|
||||
<field name="name">Website With Tutorial</field>
|
||||
<field name="url">/?tutorial=true</field>
|
||||
<field name="target">self</field>
|
||||
</record>
|
||||
|
||||
<record id="menu_website" model="ir.ui.menu">
|
||||
<field name="name">Website</field>
|
||||
<field name="sequence" eval="510"/>
|
||||
<field name="action" ref="action_website"/>
|
||||
</record>
|
||||
|
||||
<record id="base.open_menu" model="ir.actions.todo">
|
||||
<field name="action_id" ref="action_website"/>
|
||||
<field name="action_id" ref="action_website_tutorial"/>
|
||||
<field name="state">open</field>
|
||||
</record>
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import view
|
||||
import ir_fields
|
||||
import ir_ui_view
|
||||
import website
|
||||
import ir_rule
|
||||
import ir_qweb
|
||||
|
||||
import test_models
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import osv
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.tools.misc import unquote as unquote
|
||||
|
||||
|
||||
class ir_rule(osv.osv):
|
||||
_inherit = 'ir.rule'
|
||||
|
||||
def _eval_context_for_combinations(self):
|
||||
"""Returns a dictionary to use as evaluation context for
|
||||
ir.rule domains, when the goal is to obtain python lists
|
||||
that are easier to parse and combine, but not to
|
||||
actually execute them."""
|
||||
res = super(ir_rule, self)._eval_context_for_combinations()
|
||||
res.update(session=unquote('session'))
|
||||
return res
|
||||
|
||||
def _eval_context(self, cr, uid):
|
||||
"""Returns a dictionary to use as evaluation context for
|
||||
ir.rule domains."""
|
||||
res = super(ir_rule, self)._eval_context(cr, uid)
|
||||
res.update(session=request and request.httprequest and request.httprequest.session)
|
||||
return res
|
|
@ -66,10 +66,12 @@ def url_for(path, lang=None):
|
|||
def urlplus(url, params):
|
||||
if not params:
|
||||
return url
|
||||
url += "?"
|
||||
for k,v in params.items():
|
||||
url += "%s=%s&" % (k, urllib.quote_plus(str(v)))
|
||||
return url
|
||||
|
||||
# can't use urlencode because it encodes to (ascii, replace) in p2
|
||||
return "%s?%s" % (url, '&'.join(
|
||||
k + '=' + urllib.quote_plus(v.encode('utf-8') if isinstance(v, unicode) else str(v))
|
||||
for k, v in params.iteritems()
|
||||
))
|
||||
|
||||
class website(osv.osv):
|
||||
_name = "website" # Avoid website.website convention for conciseness (for new api). Got a special authorization from xmo and rco
|
||||
|
@ -118,6 +120,7 @@ class website(osv.osv):
|
|||
is_master_lang = lang == request.website.default_lang_id.code
|
||||
request.context.update({
|
||||
'lang': lang,
|
||||
'lang_selected': [lg for lg in request.website.language_ids if lg.code == lang],
|
||||
'langs': [lg.code for lg in request.website.language_ids],
|
||||
'multilang': request.multilang,
|
||||
'is_public_user': is_public_user,
|
||||
|
@ -141,13 +144,12 @@ class website(osv.osv):
|
|||
qweb_context.update(values)
|
||||
|
||||
qweb_context.update(
|
||||
request=request,
|
||||
registry=request.registry,
|
||||
request=request, # TODO maybe rename to _request to mark this attribute as unsafe
|
||||
json=simplejson,
|
||||
website=request.website,
|
||||
url_for=url_for,
|
||||
res_company=request.website.company_id,
|
||||
user_id=user.browse(cr, openerp.SUPERUSER_ID, uid),
|
||||
user_id=user.browse(cr, uid, uid),
|
||||
)
|
||||
|
||||
context = request.context.copy()
|
||||
|
@ -347,3 +349,28 @@ class res_partner(osv.osv):
|
|||
'q': '%s, %s %s, %s' % (partner.street, partner.city, partner.zip, partner.country_id and partner.country_id.name_get()[0][1] or ''),
|
||||
}
|
||||
return urlplus('https://maps.google.be/maps' , params)
|
||||
|
||||
class base_language_install(osv.osv):
|
||||
_inherit = "base.language.install"
|
||||
_columns = {
|
||||
'website_ids': fields.many2many('website', string='Websites to translate'),
|
||||
}
|
||||
|
||||
def lang_install(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
action = super(base_language_install, self).lang_install(cr, uid, ids, context)
|
||||
language_obj = self.browse(cr, uid, ids)[0]
|
||||
website_ids = [website.id for website in language_obj['website_ids']]
|
||||
lang_id = self.pool['res.lang'].search(cr, uid, [('code', '=', language_obj['lang'])])
|
||||
if website_ids and lang_id:
|
||||
data = {'language_ids': [(4, lang_id[0])]}
|
||||
self.pool['website'].write(cr, uid, website_ids, data)
|
||||
params = context.get('params', {})
|
||||
if 'url_return' in params:
|
||||
return {
|
||||
'url': params['url_return'].replace('[lang]', language_obj['lang']),
|
||||
'type': 'ir.actions.act_url',
|
||||
'target': 'self'
|
||||
}
|
||||
return action
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
.tour-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1009;
|
||||
background-color: #000;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.tour-step-backdrop {
|
||||
position: relative;
|
||||
z-index: 1011;
|
||||
}
|
||||
.tour-step-background {
|
||||
position: absolute;
|
||||
z-index: 1010;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.popover[class*="tour-"] .popover-navigation {
|
||||
padding: 9px 14px;
|
||||
}
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=end] {
|
||||
float: right;
|
||||
}
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=prev],
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=next],
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=end] {
|
||||
cursor: pointer;
|
||||
}
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=prev].disabled,
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=next].disabled,
|
||||
.popover[class*="tour-"] .popover-navigation *[data-role=end].disabled {
|
||||
cursor: default;
|
||||
}
|
||||
.popover[class*="tour-"].orphan {
|
||||
position: fixed;
|
||||
margin-top: 0;
|
||||
}
|
||||
.popover[class*="tour-"].orphan .arrow {
|
||||
display: none;
|
||||
}
|
|
@ -0,0 +1,559 @@
|
|||
/* ===========================================================
|
||||
# bootstrap-tour - v0.6.1
|
||||
# http://bootstraptour.com
|
||||
# ==============================================================
|
||||
# Copyright 2012-2013 Ulrich Sossou
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
(function($, window) {
|
||||
var Tour, document;
|
||||
document = window.document;
|
||||
Tour = (function() {
|
||||
function Tour(options) {
|
||||
this._options = $.extend({
|
||||
name: "tour",
|
||||
container: "body",
|
||||
keyboard: true,
|
||||
storage: window.localStorage,
|
||||
debug: false,
|
||||
backdrop: false,
|
||||
redirect: true,
|
||||
orphan: false,
|
||||
basePath: "",
|
||||
template: "<div class='popover'> <div class='arrow'></div> <h3 class='popover-title'></h3> <div class='popover-content'></div> <nav class='popover-navigation'> <div class='btn-group'> <button class='btn btn-sm btn-default' data-role='prev'>« Prev</button> <button class='btn btn-sm btn-default' data-role='next'>Next »</button> </div> <button class='btn btn-sm btn-default' data-role='end'>End tour</button> </nav> </div>",
|
||||
afterSetState: function(key, value) {},
|
||||
afterGetState: function(key, value) {},
|
||||
afterRemoveState: function(key) {},
|
||||
onStart: function(tour) {},
|
||||
onEnd: function(tour) {},
|
||||
onShow: function(tour) {},
|
||||
onShown: function(tour) {},
|
||||
onHide: function(tour) {},
|
||||
onHidden: function(tour) {},
|
||||
onNext: function(tour) {},
|
||||
onPrev: function(tour) {}
|
||||
}, options);
|
||||
this._steps = [];
|
||||
this.setCurrentStep();
|
||||
this.backdrop = {
|
||||
overlay: null,
|
||||
$element: null,
|
||||
$background: null
|
||||
};
|
||||
}
|
||||
|
||||
Tour.prototype.setState = function(key, value) {
|
||||
var keyName;
|
||||
if (this._options.storage) {
|
||||
keyName = "" + this._options.name + "_" + key;
|
||||
this._options.storage.setItem(keyName, value);
|
||||
return this._options.afterSetState(keyName, value);
|
||||
} else {
|
||||
if (this._state == null) {
|
||||
this._state = {};
|
||||
}
|
||||
return this._state[key] = value;
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype.removeState = function(key) {
|
||||
var keyName;
|
||||
if (this._options.storage) {
|
||||
keyName = "" + this._options.name + "_" + key;
|
||||
this._options.storage.removeItem(keyName);
|
||||
return this._options.afterRemoveState(keyName);
|
||||
} else {
|
||||
if (this._state != null) {
|
||||
return delete this._state[key];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype.getState = function(key) {
|
||||
var keyName, value;
|
||||
if (this._options.storage) {
|
||||
keyName = "" + this._options.name + "_" + key;
|
||||
value = this._options.storage.getItem(keyName);
|
||||
} else {
|
||||
if (this._state != null) {
|
||||
value = this._state[key];
|
||||
}
|
||||
}
|
||||
if (value === void 0 || value === "null") {
|
||||
value = null;
|
||||
}
|
||||
this._options.afterGetState(key, value);
|
||||
return value;
|
||||
};
|
||||
|
||||
Tour.prototype.addSteps = function(steps) {
|
||||
var step, _i, _len, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = steps.length; _i < _len; _i++) {
|
||||
step = steps[_i];
|
||||
_results.push(this.addStep(step));
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
Tour.prototype.addStep = function(step) {
|
||||
return this._steps.push(step);
|
||||
};
|
||||
|
||||
Tour.prototype.getStep = function(i) {
|
||||
if (this._steps[i] != null) {
|
||||
return $.extend({
|
||||
id: "step-" + i,
|
||||
path: "",
|
||||
placement: "right",
|
||||
title: "",
|
||||
content: "<p></p>",
|
||||
next: i === this._steps.length - 1 ? -1 : i + 1,
|
||||
prev: i - 1,
|
||||
animation: true,
|
||||
container: this._options.container,
|
||||
backdrop: this._options.backdrop,
|
||||
redirect: this._options.redirect,
|
||||
orphan: this._options.orphan,
|
||||
template: this._options.template,
|
||||
onShow: this._options.onShow,
|
||||
onShown: this._options.onShown,
|
||||
onHide: this._options.onHide,
|
||||
onHidden: this._options.onHidden,
|
||||
onNext: this._options.onNext,
|
||||
onPrev: this._options.onPrev
|
||||
}, this._steps[i]);
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype.start = function(force) {
|
||||
var promise,
|
||||
_this = this;
|
||||
if (force == null) {
|
||||
force = false;
|
||||
}
|
||||
if (this.ended() && !force) {
|
||||
return this._debug("Tour ended, start prevented.");
|
||||
}
|
||||
$(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]:not(.disabled)", function(e) {
|
||||
e.preventDefault();
|
||||
return _this.next();
|
||||
});
|
||||
$(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]:not(.disabled)", function(e) {
|
||||
e.preventDefault();
|
||||
return _this.prev();
|
||||
});
|
||||
$(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]", function(e) {
|
||||
e.preventDefault();
|
||||
return _this.end();
|
||||
});
|
||||
this._onResize(function() {
|
||||
return _this.showStep(_this._current);
|
||||
});
|
||||
this._setupKeyboardNavigation();
|
||||
promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
|
||||
return this._callOnPromiseDone(promise, this.showStep, this._current);
|
||||
};
|
||||
|
||||
Tour.prototype.next = function() {
|
||||
var promise;
|
||||
if (this.ended()) {
|
||||
return this._debug("Tour ended, next prevented.");
|
||||
}
|
||||
promise = this.hideStep(this._current);
|
||||
return this._callOnPromiseDone(promise, this._showNextStep);
|
||||
};
|
||||
|
||||
Tour.prototype.prev = function() {
|
||||
var promise;
|
||||
if (this.ended()) {
|
||||
return this._debug("Tour ended, prev prevented.");
|
||||
}
|
||||
promise = this.hideStep(this._current);
|
||||
return this._callOnPromiseDone(promise, this._showPrevStep);
|
||||
};
|
||||
|
||||
Tour.prototype.goto = function(i) {
|
||||
var promise;
|
||||
if (this.ended()) {
|
||||
return this._debug("Tour ended, goto prevented.");
|
||||
}
|
||||
promise = this.hideStep(this._current);
|
||||
return this._callOnPromiseDone(promise, this.showStep, i);
|
||||
};
|
||||
|
||||
Tour.prototype.end = function() {
|
||||
var endHelper, hidePromise,
|
||||
_this = this;
|
||||
endHelper = function(e) {
|
||||
$(document).off("click.tour-" + _this._options.name);
|
||||
$(document).off("keyup.tour-" + _this._options.name);
|
||||
$(window).off("resize.tour-" + _this._options.name);
|
||||
_this.setState("end", "yes");
|
||||
if (_this._options.onEnd != null) {
|
||||
return _this._options.onEnd(_this);
|
||||
}
|
||||
};
|
||||
hidePromise = this.hideStep(this._current);
|
||||
return this._callOnPromiseDone(hidePromise, endHelper);
|
||||
};
|
||||
|
||||
Tour.prototype.ended = function() {
|
||||
return !!this.getState("end");
|
||||
};
|
||||
|
||||
Tour.prototype.restart = function() {
|
||||
this.removeState("current_step");
|
||||
this.removeState("end");
|
||||
this.setCurrentStep(0);
|
||||
return this.start();
|
||||
};
|
||||
|
||||
Tour.prototype.hideStep = function(i) {
|
||||
var hideStepHelper, promise, step,
|
||||
_this = this;
|
||||
step = this.getStep(i);
|
||||
promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
|
||||
hideStepHelper = function(e) {
|
||||
var $element;
|
||||
$element = _this._isOrphan(step) ? $("body") : $(step.element);
|
||||
$element.popover("destroy");
|
||||
if (step.reflex) {
|
||||
$element.css("cursor", "").off("click.tour-" + _this._options.name);
|
||||
}
|
||||
if (step.backdrop) {
|
||||
_this._hideBackdrop();
|
||||
}
|
||||
if (step.onHidden != null) {
|
||||
return step.onHidden(_this);
|
||||
}
|
||||
};
|
||||
this._callOnPromiseDone(promise, hideStepHelper);
|
||||
return promise;
|
||||
};
|
||||
|
||||
Tour.prototype.showStep = function(i) {
|
||||
var promise, showStepHelper, skipToPrevious, step,
|
||||
_this = this;
|
||||
step = this.getStep(i);
|
||||
if (!step) {
|
||||
return;
|
||||
}
|
||||
skipToPrevious = i < this._current;
|
||||
promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
|
||||
showStepHelper = function(e) {
|
||||
var current_path, path;
|
||||
_this.setCurrentStep(i);
|
||||
path = $.isFunction(step.path) ? step.path.call() : _this._options.basePath + step.path;
|
||||
current_path = [document.location.pathname, document.location.hash].join("");
|
||||
if (_this._isRedirect(path, current_path)) {
|
||||
_this._redirect(step, path);
|
||||
return;
|
||||
}
|
||||
if (_this._isOrphan(step)) {
|
||||
if (!step.orphan) {
|
||||
_this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
|
||||
if (skipToPrevious) {
|
||||
_this._showPrevStep();
|
||||
} else {
|
||||
_this._showNextStep();
|
||||
}
|
||||
return;
|
||||
}
|
||||
_this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
|
||||
}
|
||||
if (step.backdrop) {
|
||||
_this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
|
||||
}
|
||||
_this._showPopover(step, i);
|
||||
if (step.onShown != null) {
|
||||
step.onShown(_this);
|
||||
}
|
||||
return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length);
|
||||
};
|
||||
return this._callOnPromiseDone(promise, showStepHelper);
|
||||
};
|
||||
|
||||
Tour.prototype.setCurrentStep = function(value) {
|
||||
if (value != null) {
|
||||
this._current = value;
|
||||
return this.setState("current_step", value);
|
||||
} else {
|
||||
this._current = this.getState("current_step");
|
||||
return this._current = this._current === null ? 0 : parseInt(this._current, 10);
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._showNextStep = function() {
|
||||
var promise, showNextStepHelper, step,
|
||||
_this = this;
|
||||
step = this.getStep(this._current);
|
||||
showNextStepHelper = function(e) {
|
||||
return _this.showStep(step.next);
|
||||
};
|
||||
promise = this._makePromise((step.onNext != null ? step.onNext(this) : void 0));
|
||||
return this._callOnPromiseDone(promise, showNextStepHelper);
|
||||
};
|
||||
|
||||
Tour.prototype._showPrevStep = function() {
|
||||
var promise, showPrevStepHelper, step,
|
||||
_this = this;
|
||||
step = this.getStep(this._current);
|
||||
showPrevStepHelper = function(e) {
|
||||
return _this.showStep(step.prev);
|
||||
};
|
||||
promise = this._makePromise((step.onPrev != null ? step.onPrev(this) : void 0));
|
||||
return this._callOnPromiseDone(promise, showPrevStepHelper);
|
||||
};
|
||||
|
||||
Tour.prototype._debug = function(text) {
|
||||
if (this._options.debug) {
|
||||
return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._isRedirect = function(path, currentPath) {
|
||||
return (path != null) && path !== "" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, "");
|
||||
};
|
||||
|
||||
Tour.prototype._redirect = function(step, path) {
|
||||
if ($.isFunction(step.redirect)) {
|
||||
return step.redirect.call(this, path);
|
||||
} else if (step.redirect === true) {
|
||||
this._debug("Redirect to " + path);
|
||||
return document.location.href = path;
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._isOrphan = function(step) {
|
||||
return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden");
|
||||
};
|
||||
|
||||
Tour.prototype._showPopover = function(step, i) {
|
||||
var $element, $navigation, $template, $tip, isOrphan, options,
|
||||
_this = this;
|
||||
options = $.extend({}, this._options);
|
||||
$template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
|
||||
$navigation = $template.find(".popover-navigation");
|
||||
isOrphan = this._isOrphan(step);
|
||||
if (isOrphan) {
|
||||
step.element = "body";
|
||||
step.placement = "top";
|
||||
$template = $template.addClass("orphan");
|
||||
}
|
||||
$element = $(step.element);
|
||||
$template.addClass("tour-" + this._options.name);
|
||||
if (step.options) {
|
||||
$.extend(options, step.options);
|
||||
}
|
||||
if (step.reflex) {
|
||||
$element.css("cursor", "pointer").on("click.tour-" + this._options.name, function(e) {
|
||||
if (_this._current < _this._steps.length - 1) {
|
||||
return _this.next();
|
||||
} else {
|
||||
return _this.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (step.prev < 0) {
|
||||
$navigation.find("*[data-role=prev]").addClass("disabled");
|
||||
}
|
||||
if (step.next < 0) {
|
||||
$navigation.find("*[data-role=next]").addClass("disabled");
|
||||
}
|
||||
step.template = $template.clone().wrap("<div>").parent().html();
|
||||
$element.popover({
|
||||
placement: step.placement,
|
||||
trigger: "manual",
|
||||
title: step.title,
|
||||
content: step.content,
|
||||
html: true,
|
||||
animation: step.animation,
|
||||
container: step.container,
|
||||
template: step.template,
|
||||
selector: step.element
|
||||
}).popover("show");
|
||||
$tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
|
||||
$tip.attr("id", step.id);
|
||||
this._scrollIntoView($tip);
|
||||
this._reposition($tip, step);
|
||||
if (isOrphan) {
|
||||
return this._center($tip);
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._reposition = function($tip, step) {
|
||||
var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
|
||||
offsetWidth = $tip[0].offsetWidth;
|
||||
offsetHeight = $tip[0].offsetHeight;
|
||||
tipOffset = $tip.offset();
|
||||
originalLeft = tipOffset.left;
|
||||
originalTop = tipOffset.top;
|
||||
offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
|
||||
if (offsetBottom < 0) {
|
||||
tipOffset.top = tipOffset.top + offsetBottom;
|
||||
}
|
||||
offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
|
||||
if (offsetRight < 0) {
|
||||
tipOffset.left = tipOffset.left + offsetRight;
|
||||
}
|
||||
if (tipOffset.top < 0) {
|
||||
tipOffset.top = 0;
|
||||
}
|
||||
if (tipOffset.left < 0) {
|
||||
tipOffset.left = 0;
|
||||
}
|
||||
$tip.offset(tipOffset);
|
||||
if (step.placement === "bottom" || step.placement === "top") {
|
||||
if (originalLeft !== tipOffset.left) {
|
||||
return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
|
||||
}
|
||||
} else {
|
||||
if (originalTop !== tipOffset.top) {
|
||||
return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._center = function($tip) {
|
||||
return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
|
||||
};
|
||||
|
||||
Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
|
||||
return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
|
||||
};
|
||||
|
||||
Tour.prototype._scrollIntoView = function(tip) {
|
||||
return $("html, body").stop().animate({
|
||||
scrollTop: Math.ceil(tip.offset().top - ($(window).height() / 2))
|
||||
});
|
||||
};
|
||||
|
||||
Tour.prototype._onResize = function(callback, timeout) {
|
||||
return $(window).on("resize.tour-" + this._options.name, function() {
|
||||
clearTimeout(timeout);
|
||||
return timeout = setTimeout(callback, 100);
|
||||
});
|
||||
};
|
||||
|
||||
Tour.prototype._setupKeyboardNavigation = function() {
|
||||
var _this = this;
|
||||
if (this._options.keyboard) {
|
||||
return $(document).on("keyup.tour-" + this._options.name, function(e) {
|
||||
if (!e.which) {
|
||||
return;
|
||||
}
|
||||
switch (e.which) {
|
||||
case 39:
|
||||
e.preventDefault();
|
||||
if (_this._current < _this._steps.length - 1) {
|
||||
return _this.next();
|
||||
} else {
|
||||
return _this.end();
|
||||
}
|
||||
break;
|
||||
case 37:
|
||||
e.preventDefault();
|
||||
if (_this._current > 0) {
|
||||
return _this.prev();
|
||||
}
|
||||
break;
|
||||
case 27:
|
||||
e.preventDefault();
|
||||
return _this.end();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._makePromise = function(result) {
|
||||
if (result && $.isFunction(result.then)) {
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
|
||||
var _this = this;
|
||||
if (promise) {
|
||||
return promise.then(function(e) {
|
||||
return cb.call(_this, arg);
|
||||
});
|
||||
} else {
|
||||
return cb.call(this, arg);
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._showBackdrop = function(element) {
|
||||
if (this.backdrop.overlay !== null) {
|
||||
return;
|
||||
}
|
||||
this._showOverlay();
|
||||
if (element != null) {
|
||||
return this._showOverlayElement(element);
|
||||
}
|
||||
};
|
||||
|
||||
Tour.prototype._hideBackdrop = function() {
|
||||
if (this.backdrop.overlay === null) {
|
||||
return;
|
||||
}
|
||||
if (this.backdrop.$element) {
|
||||
this._hideOverlayElement();
|
||||
}
|
||||
return this._hideOverlay();
|
||||
};
|
||||
|
||||
Tour.prototype._showOverlay = function() {
|
||||
this.backdrop = $("<div/>", {
|
||||
"class": "tour-backdrop"
|
||||
});
|
||||
return $("body").append(this.backdrop);
|
||||
};
|
||||
|
||||
Tour.prototype._hideOverlay = function() {
|
||||
this.backdrop.remove();
|
||||
return this.backdrop.overlay = null;
|
||||
};
|
||||
|
||||
Tour.prototype._showOverlayElement = function(element) {
|
||||
var $background, $element, offset;
|
||||
$element = $(element);
|
||||
$background = $("<div/>");
|
||||
offset = $element.offset();
|
||||
offset.top = offset.top;
|
||||
offset.left = offset.left;
|
||||
$background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
|
||||
$element.addClass("tour-step-backdrop");
|
||||
$("body").append($background);
|
||||
this.backdrop.$element = $element;
|
||||
return this.backdrop.$background = $background;
|
||||
};
|
||||
|
||||
Tour.prototype._hideOverlayElement = function() {
|
||||
this.backdrop.$element.removeClass("tour-step-backdrop");
|
||||
this.backdrop.$background.remove();
|
||||
this.backdrop.$element = null;
|
||||
return this.backdrop.$background = null;
|
||||
};
|
||||
|
||||
return Tour;
|
||||
|
||||
})();
|
||||
return window.Tour = Tour;
|
||||
})(jQuery, window);
|
||||
|
||||
}).call(this);
|
|
@ -0,0 +1,22 @@
|
|||
jQuery Nearest Element plugin
|
||||
======
|
||||
|
||||
**Full documentation is at <http://gilmoreorless.github.io/jquery-nearest/>**
|
||||
|
||||
**Demo:** <http://gilmoreorless.github.io/jquery-nearest/demo.html>
|
||||
|
||||
Method signatures:
|
||||
|
||||
* `$.nearest({x, y}, selector)` - find `$(selector)` closest to x/y point on screen
|
||||
* `$(elem).nearest(selector)` - find `$(selector)` closest to elem
|
||||
* `$(elemSet).nearest({x, y})` - filter `$(elemSet)` and return closest to x/y point on screen
|
||||
|
||||
Reverse logic:
|
||||
|
||||
* `$.furthest()`
|
||||
* `$(elem).furthest()`
|
||||
|
||||
Intersecting/touching:
|
||||
|
||||
* `$.touching()`
|
||||
* `$(elem).touching()`
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "jquery-nearest",
|
||||
"version": "1.2.1",
|
||||
"main": "jquery.nearest.js",
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"test"
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">=1.4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*!
|
||||
* jQuery Nearest plugin v1.2.1
|
||||
*
|
||||
* Finds elements closest to a single point based on screen location and pixel dimensions
|
||||
* http://gilmoreorless.github.com/jquery-nearest/
|
||||
* Open source under the MIT licence: http://gilmoreorless.mit-license.org/2011/
|
||||
*
|
||||
* Requires jQuery 1.4 or above
|
||||
* Also supports Ben Alman's "each2" plugin for faster looping (if available)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Method signatures:
|
||||
*
|
||||
* $.nearest({x, y}, selector) - find $(selector) closest to point
|
||||
* $(elem).nearest(selector) - find $(selector) closest to elem
|
||||
* $(elemSet).nearest({x, y}) - filter $(elemSet) and return closest to point
|
||||
*
|
||||
* Also:
|
||||
* $.furthest()
|
||||
* $(elem).furthest()
|
||||
*
|
||||
* $.touching()
|
||||
* $(elem).touching()
|
||||
*/
|
||||
;(function ($, undefined) {
|
||||
|
||||
/**
|
||||
* Internal method that does the grunt work
|
||||
*
|
||||
* @param mixed selector Any valid jQuery selector providing elements to filter
|
||||
* @param hash options Key/value list of options for matching elements
|
||||
* @param mixed thisObj (optional) Any valid jQuery selector that represents self
|
||||
* for the "includeSelf" option
|
||||
* @return array List of matching elements, can be zero length
|
||||
*/
|
||||
var rPerc = /^([\d.]+)%$/;
|
||||
function nearest(selector, options, thisObj) {
|
||||
// Normalise selector and dimensions
|
||||
selector || (selector = 'div'); // I STRONGLY recommend passing in a selector
|
||||
var $container = $(options.container),
|
||||
containerOffset = $container.offset() || {left: 0, top: 0},
|
||||
containerDims = [
|
||||
containerOffset.left + $container.width(),
|
||||
containerOffset.top + $container.height()
|
||||
],
|
||||
percProps = {x: 0, y: 1, w: 0, h: 1},
|
||||
prop, match;
|
||||
for (prop in percProps) if (percProps.hasOwnProperty(prop)) {
|
||||
match = rPerc.exec(options[prop]);
|
||||
if (match) {
|
||||
options[prop] = containerDims[percProps[prop]] * match[1] / 100;
|
||||
}
|
||||
}
|
||||
|
||||
// Get elements and work out x/y points
|
||||
var $all = $(selector),
|
||||
cache = [],
|
||||
furthest = !!options.furthest,
|
||||
checkX = !!options.checkHoriz,
|
||||
checkY = !!options.checkVert,
|
||||
compDist = furthest ? 0 : Infinity,
|
||||
point1x = parseFloat(options.x) || 0,
|
||||
point1y = parseFloat(options.y) || 0,
|
||||
point2x = parseFloat(point1x + options.w) || point1x,
|
||||
point2y = parseFloat(point1y + options.h) || point1y,
|
||||
tolerance = options.tolerance || 0,
|
||||
hasEach2 = !!$.fn.each2,
|
||||
// Shortcuts to help with compression
|
||||
min = Math.min,
|
||||
max = Math.max;
|
||||
|
||||
// Normalise the remaining options
|
||||
if (!options.includeSelf && thisObj) {
|
||||
$all = $all.not(thisObj);
|
||||
}
|
||||
if (tolerance < 0) {
|
||||
tolerance = 0;
|
||||
}
|
||||
// Loop through all elements and check their positions
|
||||
$all[hasEach2 ? 'each2' : 'each'](function (i, elem) {
|
||||
var $this = hasEach2 ? elem : $(this),
|
||||
off = $this.offset(),
|
||||
x = off.left,
|
||||
y = off.top,
|
||||
w = $this.outerWidth(),
|
||||
h = $this.outerHeight(),
|
||||
x2 = x + w,
|
||||
y2 = y + h,
|
||||
maxX1 = max(x, point1x),
|
||||
minX2 = min(x2, point2x),
|
||||
maxY1 = max(y, point1y),
|
||||
minY2 = min(y2, point2y),
|
||||
intersectX = minX2 >= maxX1,
|
||||
intersectY = minY2 >= maxY1,
|
||||
distX, distY, distT, isValid;
|
||||
if (
|
||||
// .nearest() / .furthest()
|
||||
(checkX && checkY) ||
|
||||
// .touching()
|
||||
(!checkX && !checkY && intersectX && intersectY) ||
|
||||
// .nearest({checkVert: false})
|
||||
(checkX && intersectY) ||
|
||||
// .nearest({checkHoriz: false})
|
||||
(checkY && intersectX)
|
||||
) {
|
||||
distX = intersectX ? 0 : maxX1 - minX2;
|
||||
distY = intersectY ? 0 : maxY1 - minY2;
|
||||
distT = intersectX || intersectY ?
|
||||
max(distX, distY) :
|
||||
Math.sqrt(distX * distX + distY * distY);
|
||||
isValid = furthest ?
|
||||
distT >= compDist - tolerance :
|
||||
distT <= compDist + tolerance;
|
||||
if (isValid) {
|
||||
compDist = furthest ?
|
||||
max(compDist, distT) :
|
||||
min(compDist, distT);
|
||||
cache.push({
|
||||
node: this,
|
||||
dist: distT
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// Make sure all cached items are within tolerance range
|
||||
var len = cache.length,
|
||||
filtered = [],
|
||||
compMin, compMax,
|
||||
i, item;
|
||||
if (len) {
|
||||
if (furthest) {
|
||||
compMin = compDist - tolerance;
|
||||
compMax = compDist;
|
||||
} else {
|
||||
compMin = compDist;
|
||||
compMax = compDist + tolerance;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
item = cache[i];
|
||||
if (item.dist >= compMin && item.dist <= compMax) {
|
||||
filtered.push(item.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
$.each(['nearest', 'furthest', 'touching'], function (i, name) {
|
||||
|
||||
// Internal default options
|
||||
// Not exposed publicly because they're method-dependent and easily overwritten anyway
|
||||
var defaults = {
|
||||
x: 0, // X position of top left corner of point/region
|
||||
y: 0, // Y position of top left corner of point/region
|
||||
w: 0, // Width of region
|
||||
h: 0, // Height of region
|
||||
tolerance: 1, // Distance tolerance in pixels, mainly to handle fractional pixel rounding bugs
|
||||
container: document, // Container of objects for calculating %-based dimensions
|
||||
furthest: name == 'furthest', // Find max distance (true) or min distance (false)
|
||||
includeSelf: false, // Include 'this' in search results (t/f) - only applies to $(elem).func(selector) syntax
|
||||
checkHoriz: name != 'touching', // Check variations in X axis (t/f)
|
||||
checkVert: name != 'touching' // Check variations in Y axis (t/f)
|
||||
};
|
||||
|
||||
/**
|
||||
* $.nearest() / $.furthest() / $.touching()
|
||||
*
|
||||
* Utility functions for finding elements near a specific point or region on screen
|
||||
*
|
||||
* @param hash point Co-ordinates for the point or region to measure from
|
||||
* "x" and "y" keys are required, "w" and "h" keys are optional
|
||||
* @param mixed selector Any valid jQuery selector that provides elements to filter
|
||||
* @param hash options (optional) Extra filtering options
|
||||
* Not technically needed as the options could go on the point object,
|
||||
* but it's good to have a consistent API
|
||||
* @return jQuery object containing matching elements in selector
|
||||
*/
|
||||
$[name] = function (point, selector, options) {
|
||||
if (!point || point.x === undefined || point.y === undefined) {
|
||||
return $([]);
|
||||
}
|
||||
var opts = $.extend({}, defaults, point, options || {});
|
||||
return $(nearest(selector, opts));
|
||||
};
|
||||
|
||||
/**
|
||||
* SIGNATURE 1:
|
||||
* $(elem).nearest(selector) / $(elem).furthest(selector) / $(elem).touching(selector)
|
||||
*
|
||||
* Finds all elements in selector that are nearest to/furthest from elem
|
||||
*
|
||||
* @param mixed selector Any valid jQuery selector that provides elements to filter
|
||||
* @param hash options (optional) Extra filtering options
|
||||
* @return jQuery object containing matching elements in selector
|
||||
*
|
||||
* SIGNATURE 2:
|
||||
* $(elemSet).nearest(point) / $(elemSet).furthest(point) / $(elemSet).touching(point)
|
||||
*
|
||||
* Filters elemSet to return only the elements nearest to/furthest from point
|
||||
* Effectively a wrapper for $.nearest(point, elemSet) but with the benefits of method chaining
|
||||
*
|
||||
* @param hash point Co-ordinates for the point or region to measure from
|
||||
* @return jQuery object containing matching elements in elemSet
|
||||
*/
|
||||
$.fn[name] = function (selector, options) {
|
||||
var opts;
|
||||
if (selector && $.isPlainObject(selector)) {
|
||||
opts = $.extend({}, defaults, selector, options || {});
|
||||
return this.pushStack(nearest(this, opts));
|
||||
}
|
||||
var offset = this.offset(),
|
||||
dimensions = {
|
||||
x: offset.left,
|
||||
y: offset.top,
|
||||
w: this.outerWidth(),
|
||||
h: this.outerHeight()
|
||||
};
|
||||
opts = $.extend({}, defaults, dimensions, options || {});
|
||||
return this.pushStack(nearest(selector, opts, this));
|
||||
};
|
||||
});
|
||||
})(jQuery);
|
|
@ -0,0 +1,11 @@
|
|||
/*!
|
||||
* jQuery Nearest plugin v1.2.1
|
||||
*
|
||||
* Finds elements closest to a single point based on screen location and pixel dimensions
|
||||
* http://gilmoreorless.github.com/jquery-nearest/
|
||||
* Open source under the MIT licence: http://gilmoreorless.mit-license.org/2011/
|
||||
*
|
||||
* Requires jQuery 1.4 or above
|
||||
* Also supports Ben Alman's "each2" plugin for faster looping (if available)
|
||||
*/
|
||||
;(function(e,t){function r(t,r,i){t||(t="div");var s=e(r.container),o=s.offset()||{left:0,top:0},u=[o.left+s.width(),o.top+s.height()],a={x:0,y:1,w:0,h:1},f,l;for(f in a)a.hasOwnProperty(f)&&(l=n.exec(r[f]),l&&(r[f]=u[a[f]]*l[1]/100));var c=e(t),h=[],p=!!r.furthest,d=!!r.checkHoriz,v=!!r.checkVert,m=p?0:Infinity,g=parseFloat(r.x)||0,y=parseFloat(r.y)||0,b=parseFloat(g+r.w)||g,w=parseFloat(y+r.h)||y,E=r.tolerance||0,S=!!e.fn.each2,x=Math.min,T=Math.max;!r.includeSelf&&i&&(c=c.not(i)),E<0&&(E=0),c[S?"each2":"each"](function(t,n){var r=S?n:e(this),i=r.offset(),s=i.left,o=i.top,u=r.outerWidth(),a=r.outerHeight(),f=s+u,l=o+a,c=T(s,g),N=x(f,b),C=T(o,y),k=x(l,w),L=N>=c,A=k>=C,O,M,_,D;if(d&&v||!d&&!v&&L&&A||d&&A||v&&L)O=L?0:c-N,M=A?0:C-k,_=L||A?T(O,M):Math.sqrt(O*O+M*M),D=p?_>=m-E:_<=m+E,D&&(m=p?T(m,_):x(m,_),h.push({node:this,dist:_}))});var N=h.length,C=[],k,L,A,O;if(N){p?(k=m-E,L=m):(k=m,L=m+E);for(A=0;A<N;A++)O=h[A],O.dist>=k&&O.dist<=L&&C.push(O.node)}return C}var n=/^([\d.]+)%$/;e.each(["nearest","furthest","touching"],function(n,i){var s={x:0,y:0,w:0,h:0,tolerance:1,container:document,furthest:i=="furthest",includeSelf:!1,checkHoriz:i!="touching",checkVert:i!="touching"};e[i]=function(n,i,o){if(!n||n.x===t||n.y===t)return e([]);var u=e.extend({},s,n,o||{});return e(r(i,u))},e.fn[i]=function(t,n){var i;if(t&&e.isPlainObject(t))return i=e.extend({},s,t,n||{}),this.pushStack(r(this,i));var o=this.offset(),u={x:o.left,y:o.top,w:this.outerWidth(),h:this.outerHeight()};return i=e.extend({},s,u,n||{}),this.pushStack(r(t,i,this))}})})(jQuery);
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "nearest",
|
||||
"title": "jQuery Nearest Element",
|
||||
"description": "Find the elements in a page that are closest to (or furthest away from) a particular point or element, based on pixel dimensions",
|
||||
"version": "1.2.1",
|
||||
"keywords": ["nearest", "furthest", "touching", "pixel", "distance"],
|
||||
"homepage": "http://gilmoreorless.github.io/jquery-nearest/",
|
||||
"docs": "http://gilmoreorless.github.io/jquery-nearest/",
|
||||
"demo": "http://gilmoreorless.github.io/jquery-nearest/demo.html",
|
||||
"bugs": "https://github.com/gilmoreorless/jquery-nearest/issues",
|
||||
"author": {
|
||||
"name": "Gilmore Davidson",
|
||||
"url": "http://shoehornwithteeth.com/"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "http://gilmoreorless.mit-license.org/2011/"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"jquery": ">=1.4"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
@charset "utf-8";
|
||||
/* ---- CKEditor Minimal Reset ---- */
|
||||
.navbar.navbar-inverse .cke_chrome {
|
||||
border: none;
|
||||
|
@ -169,7 +168,7 @@ table.editorbar-panel td.selected {
|
|||
position: fixed;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 50px;
|
||||
top: 51px;
|
||||
background: #282828;
|
||||
-webkit-box-shadow: 0px 10px 10px -10px black inset;
|
||||
-moz-box-shadow: 0px 10px 10px -10px black inset;
|
||||
|
@ -182,17 +181,21 @@ table.editorbar-panel td.selected {
|
|||
}
|
||||
#oe_snippets .scroll {
|
||||
white-space: nowrap;
|
||||
overflow-y: auto;
|
||||
overflow-y: none;
|
||||
}
|
||||
#oe_snippets .nav {
|
||||
position: fixed;
|
||||
display: inline-block;
|
||||
border-bottom: none !important;
|
||||
vertical-align: middle;
|
||||
min-width: 120px;
|
||||
z-index: 1;
|
||||
border: 0;
|
||||
}
|
||||
#oe_snippets .nav > li {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
float: none;
|
||||
font-size: 13px;
|
||||
}
|
||||
#oe_snippets .nav > li.active {
|
||||
background: black !important;
|
||||
}
|
||||
#oe_snippets .nav > li > a {
|
||||
padding: 2px 10px !important;
|
||||
|
@ -200,18 +203,19 @@ table.editorbar-panel td.selected {
|
|||
display: block;
|
||||
border: 0;
|
||||
}
|
||||
#oe_snippets .pill-content {
|
||||
border: 0;
|
||||
}
|
||||
#oe_snippets .tab-content {
|
||||
margin-top: 24px;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
background: black;
|
||||
}
|
||||
#oe_snippets .tab-content > div {
|
||||
background: black;
|
||||
padding: 5px;
|
||||
}
|
||||
#oe_snippets .tab-content > div label {
|
||||
width: 44px;
|
||||
height: 100%;
|
||||
color: white;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
@ -231,11 +235,10 @@ table.editorbar-panel td.selected {
|
|||
}
|
||||
|
||||
.oe_snippet {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
vertical-align: top;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 1px;
|
||||
width: 93px;
|
||||
margin-left: 1px;
|
||||
margin-top: 0px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
@ -253,14 +256,32 @@ table.editorbar-panel td.selected {
|
|||
color: white;
|
||||
position: relative;
|
||||
}
|
||||
.oe_snippet .oe_snippet_thumbnail:hover .oe_snippet_thumbnail_img {
|
||||
-webkit-transform: scale(0.95, 0.95);
|
||||
-moz-transform: scale(0.95, 0.95);
|
||||
-ms-transform: scale(0.95, 0.95);
|
||||
-o-transform: scale(0.95, 0.95);
|
||||
transform: scale(0.95, 0.95);
|
||||
}
|
||||
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title {
|
||||
font-size: 12px;
|
||||
display: block;
|
||||
text-shadow: 0 0 2px black;
|
||||
}
|
||||
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img {
|
||||
height: 74px;
|
||||
-webkit-transition: all 150ms linear;
|
||||
-moz-transition: all 150ms linear;
|
||||
-o-transition: all 150ms linear;
|
||||
transition: all 150ms linear;
|
||||
-webkit-box-shadow: inset 0px 0px 0px 3px #333333;
|
||||
-moz-box-shadow: inset 0px 0px 0px 3px #333333;
|
||||
box-shadow: inset 0px 0px 0px 3px #333333;
|
||||
-webkit-transform: scale(1, 1);
|
||||
-moz-transform: scale(1, 1);
|
||||
-ms-transform: scale(1, 1);
|
||||
-o-transform: scale(1, 1);
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
.oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div {
|
||||
line-height: 18px;
|
||||
|
@ -309,20 +330,21 @@ table.editorbar-panel td.selected {
|
|||
margin: 0px -24px !important;
|
||||
}
|
||||
.oe_drop_zone.oe_insert.oe_overlay {
|
||||
background: rgba(153, 0, 255, 0.17);
|
||||
border-radius: 3px;
|
||||
background: rgba(153, 0, 255, 0.5);
|
||||
}
|
||||
|
||||
.oe_drop_zone, .oe_drop_zone_style {
|
||||
background: rgba(153, 0, 255, 0.17);
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
-ms-border-radius: 3px;
|
||||
-o-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
border: none;
|
||||
background: rgba(153, 0, 255, 0.3);
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
-ms-border-radius: 4px;
|
||||
-o-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.oe_drop_zone.oe_hover, .oe_drop_zone_style.oe_hover {
|
||||
background: rgba(0, 255, 133, 0.22);
|
||||
background: rgba(0, 255, 133, 0.3);
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
|
@ -359,7 +381,7 @@ table.editorbar-panel td.selected {
|
|||
-webkit-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
|
||||
-moz-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
|
||||
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
|
||||
border-color: rgba(153, 0, 255, 0.5);
|
||||
border-color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.oe_overlay.oe_active .oe_handle {
|
||||
display: block !important;
|
||||
|
@ -371,39 +393,43 @@ table.editorbar-panel td.selected {
|
|||
left: 50%;
|
||||
display: block;
|
||||
background: white;
|
||||
border: solid 1px #9900ff;
|
||||
-webkit-border-radius: 8px;
|
||||
-moz-border-radius: 8px;
|
||||
-ms-border-radius: 8px;
|
||||
-o-border-radius: 8px;
|
||||
border-radius: 8px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -8px;
|
||||
border: solid 1px rgba(0, 0, 0, 0.2);
|
||||
-webkit-border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-ms-border-radius: 5px;
|
||||
-o-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: -9px;
|
||||
padding-left: 1px;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: #9900ff;
|
||||
font-family: FontAwesome;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
-webkit-transition: background 100ms linear;
|
||||
-moz-transition: background 100ms linear;
|
||||
-o-transition: background 100ms linear;
|
||||
transition: background 100ms linear;
|
||||
}
|
||||
.oe_overlay.oe_active .oe_handle:hover:before {
|
||||
background: #9900ff;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
-webkit-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
|
||||
-moz-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
|
||||
box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
.oe_overlay.oe_active .oe_handle.e:before {
|
||||
content: "⇨";
|
||||
content: "\F061";
|
||||
}
|
||||
.oe_overlay.oe_active .oe_handle.s:before {
|
||||
content: "⇩";
|
||||
content: "\F063";
|
||||
}
|
||||
.oe_overlay.oe_active .oe_handle.w:before {
|
||||
content: "⇦";
|
||||
content: "\F060";
|
||||
}
|
||||
.oe_overlay.oe_active .oe_handle.n:before {
|
||||
content: "⇧";
|
||||
content: "\F062";
|
||||
}
|
||||
.oe_overlay .icon.btn {
|
||||
display: inline-block;
|
||||
|
@ -568,18 +594,6 @@ table.editorbar-panel td.selected {
|
|||
-o-border-radius: 0.4em;
|
||||
border-radius: 0.4em;
|
||||
}
|
||||
.oe_seo_configuration .keyword-in-title {
|
||||
background-color: #5cb85cpointer;
|
||||
color: white;
|
||||
}
|
||||
.oe_seo_configuration .keyword-in-description {
|
||||
background-color: #428bca;
|
||||
color: white;
|
||||
}
|
||||
.oe_seo_configuration .keyword-in-body {
|
||||
background-color: #5bc0de;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* ---- ACE EDITOR ---- */
|
||||
.oe_ace_view_editor {
|
||||
|
@ -636,3 +650,12 @@ table.editorbar-panel td.selected {
|
|||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* ---- EDITOR TOUR ---- */
|
||||
div.tour-backdrop {
|
||||
z-index: 2009;
|
||||
}
|
||||
|
||||
.popover.tour {
|
||||
z-index: 2010;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,17 @@
|
|||
@import "compass/css3/user-interface"
|
||||
@import "compass/css3/transition"
|
||||
|
||||
//smartphones, iPhone, portrait 480x320 phones
|
||||
$smart_phone: 320px
|
||||
//portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide.*/
|
||||
$small-tablet: 481px
|
||||
//portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones
|
||||
$portrait-tablet: 641px
|
||||
//tablet, landscape iPad, lo-res laptops ands desktops
|
||||
$tablet: 961px
|
||||
//big landscape tablets, laptops, and desktops
|
||||
$desktop: 1025px
|
||||
|
||||
/* ---- CKEditor Minimal Reset ---- */
|
||||
|
||||
.navbar.navbar-inverse .cke_chrome
|
||||
|
@ -141,7 +152,7 @@ table.editorbar-panel
|
|||
position: fixed
|
||||
left: 0px
|
||||
right: 0px
|
||||
top: 50px
|
||||
top: 51px
|
||||
background: rgb(40,40,40)
|
||||
+box-shadow(0px 10px 10px -10px black inset)
|
||||
z-index: 1010
|
||||
|
@ -150,44 +161,47 @@ table.editorbar-panel
|
|||
height: auto
|
||||
.scroll
|
||||
white-space: nowrap
|
||||
overflow-y: auto
|
||||
overflow-y: none
|
||||
.nav
|
||||
display: inline-block
|
||||
border-bottom: none !important
|
||||
vertical-align: middle
|
||||
min-width: 120px
|
||||
> li
|
||||
display: inline-block
|
||||
display: block
|
||||
float: none
|
||||
font-size: 13px
|
||||
&.active
|
||||
background: black !important
|
||||
> a
|
||||
padding: 2px 10px !important
|
||||
width: 100%
|
||||
width: 100%
|
||||
display: block
|
||||
border: 0
|
||||
position: fixed
|
||||
z-index: 1
|
||||
.pill-content
|
||||
border: 0
|
||||
.tab-content
|
||||
margin-top: 24px
|
||||
display: inline-block
|
||||
white-space: nowrap
|
||||
> div
|
||||
background: black
|
||||
> div
|
||||
background: rgb(0,0,0)
|
||||
padding: 5px
|
||||
label
|
||||
width: 44px
|
||||
height: 100%
|
||||
color: #fff
|
||||
padding-left: 10px
|
||||
|
||||
div
|
||||
width: 100px
|
||||
text-align: center
|
||||
@include transform( translate(-39px, 44px) , rotate(-90deg) )
|
||||
@include transform( translate(-39px, 44px) , rotate(-90deg) )
|
||||
@include transform-origin(50% 50%)
|
||||
|
||||
.oe_snippet
|
||||
display: inline-block
|
||||
float: left
|
||||
vertical-align: top
|
||||
width: 100px
|
||||
height: 100px
|
||||
margin: 1px
|
||||
width: 93px
|
||||
margin-left: 1px
|
||||
margin-top: 0px
|
||||
position: relative
|
||||
overflow: hidden
|
||||
|
@ -201,11 +215,18 @@ table.editorbar-panel
|
|||
background: transparent
|
||||
color: white
|
||||
position: relative
|
||||
&:hover
|
||||
.oe_snippet_thumbnail_img
|
||||
@include transform( scale(.95,.95))
|
||||
.oe_snippet_thumbnail_title
|
||||
font-size: 12px
|
||||
display: block
|
||||
+text-shadow(0 0 2px rgb(0,0,0))
|
||||
.oe_snippet_thumbnail_img
|
||||
height: 74px
|
||||
@include transition(all 150ms linear)
|
||||
+box-shadow(inset 0px 0px 0px 3px #333333)
|
||||
@include transform( scale(1,1))
|
||||
span, div
|
||||
line-height: 18px
|
||||
& > :not(.oe_snippet_thumbnail)
|
||||
|
@ -240,14 +261,19 @@ table.editorbar-panel
|
|||
position: relative
|
||||
margin: 0px -24px !important
|
||||
&.oe_overlay
|
||||
background: rgba(153, 0, 255, 0.17)
|
||||
border-radius: 3px
|
||||
|
||||
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
|
||||
//background-size: 100px 100px
|
||||
background: rgba(153, 0, 255,.5)
|
||||
|
||||
.oe_drop_zone, .oe_drop_zone_style
|
||||
background: rgba(153, 0, 255, 0.17)
|
||||
+border-radius(3px)
|
||||
border: none
|
||||
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
|
||||
//background-size: 100px 100px
|
||||
background: rgba(153, 0, 255, .3)
|
||||
+border-radius(4px)
|
||||
&.oe_hover
|
||||
background: rgba(0, 255, 133, 0.22)
|
||||
background: rgba(0, 255, 133, .3)
|
||||
z-index: 1001
|
||||
|
||||
.oe_drop_zone_style
|
||||
|
@ -262,6 +288,7 @@ table.editorbar-panel
|
|||
display: none
|
||||
position: absolute
|
||||
background: transparent
|
||||
//@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.02) ,rgba(255,255,255,.02) 35px, rgba(0,0,0,.02) 35px, rgba(0,0,0,.02) 75px))
|
||||
+border-radius(3px)
|
||||
@include transition(opacity 100ms linear)
|
||||
+box-sizing(border-box)
|
||||
|
@ -271,7 +298,7 @@ table.editorbar-panel
|
|||
border-style: dashed
|
||||
border-width: 1px
|
||||
+box-shadow(0px 0px 0px 1px rgba(255,255,255,0.3), 0px 0px 0px 1px rgba(255,255,255,0.3) inset)
|
||||
border-color: rgba(153, 0, 255, 0.5)
|
||||
border-color: rgba(0, 0, 0, 0.5)
|
||||
.oe_handle
|
||||
display: block !important
|
||||
pointer-events: auto
|
||||
|
@ -281,27 +308,29 @@ table.editorbar-panel
|
|||
left: 50%
|
||||
display: block
|
||||
background: rgba(255, 255, 255, 1)
|
||||
border: solid 1px rgba(153, 0, 255, 1)
|
||||
+border-radius(8px)
|
||||
width: 16px
|
||||
height: 16px
|
||||
margin: -8px
|
||||
border: solid 1px rgba(0, 0, 0, .2)
|
||||
+border-radius(5px)
|
||||
width: 18px
|
||||
height: 18px
|
||||
margin: -9px
|
||||
padding-left: 1px
|
||||
font-size: 14px
|
||||
line-height: 14px
|
||||
color: rgba(153, 0, 255, 1)
|
||||
font-family: FontAwesome
|
||||
color: rgba(0,0,0,.5)
|
||||
@include transition(background 100ms linear)
|
||||
&:hover:before
|
||||
background: rgba(153, 0, 255, 1)
|
||||
background: rgba(0, 0, 0, .5)
|
||||
color: #fff
|
||||
+box-shadow(0 0 5px 3px rgba(255,255,255,.7))
|
||||
.oe_handle.e:before
|
||||
content: "⇨"
|
||||
content: "\F061"
|
||||
.oe_handle.s:before
|
||||
content: "⇩"
|
||||
content: "\F063"
|
||||
.oe_handle.w:before
|
||||
content: "⇦"
|
||||
content: "\F060"
|
||||
.oe_handle.n:before
|
||||
content: "⇧"
|
||||
content: "\F062"
|
||||
|
||||
.icon.btn
|
||||
display: inline-block
|
||||
|
@ -436,10 +465,6 @@ $ace_width: 720px
|
|||
$editorbar_height: 40px
|
||||
// TODO Fix => might break with themes
|
||||
$navbar_height: 51px
|
||||
@mixin pointer-events($type: none)
|
||||
$type: unquote($type)
|
||||
@include experimental(pointer-events, $type,-moz, -webkit, not -o, not -ms, -khtml, official)
|
||||
|
||||
|
||||
@mixin editor-font
|
||||
font-size: 14px
|
||||
|
@ -481,4 +506,10 @@ $navbar_height: 51px
|
|||
&.oe_ace_closed
|
||||
width: 0
|
||||
+opacity(0)
|
||||
|
||||
/* ---- EDITOR TOUR ---- */
|
||||
div.tour-backdrop
|
||||
z-index: 2009
|
||||
.popover.tour
|
||||
z-index: 2010
|
||||
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
|
||||
|
|
|
@ -223,11 +223,15 @@ footer {
|
|||
}
|
||||
|
||||
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
|
||||
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
|
||||
.oe_structure.oe_editable.oe_empty:empty, .oe_editable[data-oe-type=html]:empty, .oe_structure.oe_editable.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
|
||||
background-image: url("/website/static/src/img/drag_here.png");
|
||||
}
|
||||
|
||||
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
|
||||
background-image: url("/website/static/src/img/edit_here.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center top;
|
||||
height: 200px !important;
|
||||
background-position: center;
|
||||
height: 220px !important;
|
||||
}
|
||||
|
||||
.oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
|
||||
|
@ -238,8 +242,8 @@ footer {
|
|||
content: "Click Edit To Create Content";
|
||||
text-align: center;
|
||||
display: block;
|
||||
padding-top: 100px;
|
||||
padding-bottom: 50px;
|
||||
padding-top: 160px;
|
||||
padding-bottom: 30px;
|
||||
color: grey;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
@ -345,6 +349,17 @@ footer {
|
|||
}
|
||||
|
||||
/* Parallax Theme */
|
||||
.parallax_quote {
|
||||
background: url("/website/static/src/img/parallax/quote.png") center center no-repeat fixed;
|
||||
background-size: contain;
|
||||
}
|
||||
.parallax_quote .carousel-indicators li {
|
||||
border: 1px solid grey;
|
||||
}
|
||||
.parallax_quote .carousel-indicators .active {
|
||||
background-color: grey;
|
||||
}
|
||||
|
||||
.parallax_full {
|
||||
background: #eeeeee bottom center repeat fixed;
|
||||
min-height: 650px;
|
||||
|
|
|
@ -151,11 +151,14 @@ footer
|
|||
|
||||
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
|
||||
|
||||
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
|
||||
.oe_structure.oe_editable.oe_empty:empty, .oe_editable[data-oe-type=html]:empty, .oe_structure.oe_editable.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
|
||||
background-image: url('/website/static/src/img/drag_here.png')
|
||||
|
||||
.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
|
||||
background-image: url('/website/static/src/img/edit_here.png')
|
||||
background-repeat: no-repeat
|
||||
background-position: center top
|
||||
height: 200px !important
|
||||
background-position: center
|
||||
height: 220px !important
|
||||
|
||||
.oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
|
||||
position: static
|
||||
|
@ -164,8 +167,8 @@ footer
|
|||
content: 'Click Edit To Create Content'
|
||||
text-align: center
|
||||
display: block
|
||||
padding-top: 100px
|
||||
padding-bottom: 50px
|
||||
padding-top: 160px
|
||||
padding-bottom: 30px
|
||||
color: grey
|
||||
font-size: 24px
|
||||
|
||||
|
@ -263,6 +266,15 @@ footer
|
|||
|
||||
/* Parallax Theme */
|
||||
|
||||
.parallax_quote
|
||||
background: url('/website/static/src/img/parallax/quote.png') center center no-repeat fixed
|
||||
background-size: contain
|
||||
.carousel-indicators
|
||||
li
|
||||
border: 1px solid grey
|
||||
.active
|
||||
background-color: grey
|
||||
|
||||
.parallax_full
|
||||
background: #eee bottom center repeat fixed
|
||||
min-height: 650px
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 124 KiB After Width: | Height: | Size: 628 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
|
@ -3,13 +3,12 @@
|
|||
|
||||
var website = openerp.website;
|
||||
// $.fn.data automatically parses value, '0'|'1' -> 0|1
|
||||
website.is_editable = $(document.documentElement).data('editable');
|
||||
|
||||
website.templates.push('/website/static/src/xml/website.editor.xml');
|
||||
website.dom_ready.done(function () {
|
||||
var is_smartphone = $(document.body)[0].clientWidth < 767;
|
||||
|
||||
if (website.is_editable && !is_smartphone) {
|
||||
if (!is_smartphone) {
|
||||
website.ready().then(website.init_editor);
|
||||
}
|
||||
});
|
||||
|
@ -21,16 +20,15 @@
|
|||
return new website.editor.RTEImageDialog(editor).appendTo(document.body);
|
||||
}
|
||||
|
||||
if (website.is_editable) {
|
||||
// only enable editors manually
|
||||
CKEDITOR.disableAutoInline = true;
|
||||
// EDIT ALL THE THINGS
|
||||
CKEDITOR.dtd.$editable = $.extend(
|
||||
{}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
|
||||
// Disable removal of empty elements on CKEDITOR activation. Empty
|
||||
// elements are used for e.g. support of FontAwesome icons
|
||||
CKEDITOR.dtd.$removeEmpty = {};
|
||||
}
|
||||
// only enable editors manually
|
||||
CKEDITOR.disableAutoInline = true;
|
||||
// EDIT ALL THE THINGS
|
||||
CKEDITOR.dtd.$editable = $.extend(
|
||||
{}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
|
||||
// Disable removal of empty elements on CKEDITOR activation. Empty
|
||||
// elements are used for e.g. support of FontAwesome icons
|
||||
CKEDITOR.dtd.$removeEmpty = {};
|
||||
|
||||
website.init_editor = function () {
|
||||
CKEDITOR.plugins.add('customdialogs', {
|
||||
// requires: 'link,image',
|
||||
|
@ -211,8 +209,9 @@
|
|||
}
|
||||
});
|
||||
// Adding Static Menus
|
||||
menu.append('<li class="divider"></li><li><a href="/page/website.themes">Change Theme</a></li>');
|
||||
menu.append('<li class="divider"></li><li class="js_change_theme"><a href="/page/website.themes">Change Theme</a></li>');
|
||||
menu.append('<li class="divider"></li><li><a data-action="ace" href="#">Advanced view editor</a></li>');
|
||||
self.trigger('rte:customize_menu_ready');
|
||||
}
|
||||
);
|
||||
});
|
||||
|
@ -616,7 +615,7 @@
|
|||
} else if ($e.hasClass('pages')) {
|
||||
// Create the page, get the URL back
|
||||
done = $.get(_.str.sprintf(
|
||||
'/pagenew/%s?noredirect', encodeURIComponent(val)))
|
||||
'/pagenew/%s?noredirect', encodeURI(val)))
|
||||
.then(function (response) {
|
||||
self.make_link(response, false, val);
|
||||
});
|
||||
|
@ -813,6 +812,7 @@
|
|||
var element, editor = this.editor;
|
||||
if (!(element = this.element)) {
|
||||
element = editor.document.createElement('img');
|
||||
element.addClass('img');
|
||||
// focus event handler interactions between bootstrap (modal)
|
||||
// and ckeditor (RTE) lead to blowing the stack in Safari and
|
||||
// Chrome (but not FF) when this is done synchronously =>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
var website = openerp.website;
|
||||
website.templates.push('/website/static/src/xml/website.seo.xml');
|
||||
|
||||
|
|
|
@ -243,12 +243,10 @@
|
|||
// activate drag and drop for the snippets in the snippet toolbar
|
||||
make_snippet_draggable: function($snippets){
|
||||
var self = this;
|
||||
var $toInsert = false;
|
||||
var $tumb = $snippets.find(".oe_snippet_thumbnail:first");
|
||||
var left = $tumb.outerWidth()/2;
|
||||
var top = $tumb.outerHeight()/2;
|
||||
var dropped = false;
|
||||
var $snippet = false;
|
||||
var $toInsert, dropped, $snippet, action, snipped_id;
|
||||
|
||||
$snippets.draggable({
|
||||
greedy: true,
|
||||
|
@ -265,8 +263,8 @@
|
|||
self.hide();
|
||||
dropped = false;
|
||||
$snippet = $(this);
|
||||
var snipped_id = $snippet.data('snippet-id');
|
||||
var action = $snippet.find('.oe_snippet_body').size() ? 'insert' : 'mutate';
|
||||
snipped_id = $snippet.data('snippet-id');
|
||||
action = $snippet.find('.oe_snippet_body').size() ? 'insert' : 'mutate';
|
||||
if( action === 'insert'){
|
||||
if (!$snippet.data('selector-siblings') && !$snippet.data('selector-children') && !$snippet.data('selector-vertical-children')) {
|
||||
console.debug($snippet.data("snippet-id") + " have oe_snippet_body class and have not for insert action"+
|
||||
|
@ -312,38 +310,46 @@
|
|||
},
|
||||
drop: function(){
|
||||
dropped = true;
|
||||
|
||||
var $target = false;
|
||||
if(action === 'insert'){
|
||||
$target = $toInsert;
|
||||
|
||||
if (website.snippet.animationRegistry[snipped_id]) {
|
||||
new website.snippet.animationRegistry[snipped_id]($target);
|
||||
}
|
||||
|
||||
self.create_overlay($target);
|
||||
$target.data("snippet-editor").build_snippet($target);
|
||||
|
||||
} else {
|
||||
$target = $(this).data('target');
|
||||
|
||||
self.create_overlay($target);
|
||||
if (website.snippet.editorRegistry[snipped_id]) {
|
||||
var snippet = new website.snippet.editorRegistry[snipped_id](self, $target);
|
||||
snippet.build_snippet($target);
|
||||
}
|
||||
}
|
||||
|
||||
$('.oe_drop_zone').remove();
|
||||
|
||||
setTimeout(function () {self.make_active($target);},0);
|
||||
},
|
||||
});
|
||||
},
|
||||
stop: function(){
|
||||
stop: function(ev, ui){
|
||||
if (action === 'insert' && ! dropped) {
|
||||
var el = $('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first()
|
||||
if (el) {
|
||||
el.after($toInsert)
|
||||
dropped = true;
|
||||
}
|
||||
}
|
||||
|
||||
$('.oe_drop_zone').droppable('destroy').remove();
|
||||
if (!dropped && self.$modal.find('input:not(:checked)').length) {
|
||||
self.$modal.modal('toggle');
|
||||
if (dropped) {
|
||||
var $target = false;
|
||||
if(action === 'insert'){
|
||||
$target = $toInsert;
|
||||
|
||||
if (website.snippet.animationRegistry[snipped_id]) {
|
||||
new website.snippet.animationRegistry[snipped_id]($target);
|
||||
}
|
||||
|
||||
self.create_overlay($target);
|
||||
$target.data("snippet-editor").build_snippet($target);
|
||||
|
||||
} else {
|
||||
$target = $(this).data('target');
|
||||
|
||||
self.create_overlay($target);
|
||||
if (website.snippet.editorRegistry[snipped_id]) {
|
||||
var snippet = new website.snippet.editorRegistry[snipped_id](self, $target);
|
||||
snippet.build_snippet($target);
|
||||
}
|
||||
}
|
||||
setTimeout(function () {self.make_active($target);},0);
|
||||
} else {
|
||||
$toInsert.remove();
|
||||
if (self.$modal.find('input:not(:checked)').length) {
|
||||
self.$modal.modal('toggle');
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -488,7 +494,6 @@
|
|||
$zone.appendTo('#oe_manipulators');
|
||||
$zone.data('target',$target);
|
||||
$target.data('overlay',$zone);
|
||||
console.log($target[0], $zone);
|
||||
|
||||
$target.on("DOMNodeInserted DOMNodeRemoved DOMSubtreeModified", function () {
|
||||
self.cover_target($zone, $target);
|
||||
|
@ -746,16 +751,8 @@
|
|||
|
||||
change_background: function (bg, ul_options) {
|
||||
var self = this;
|
||||
this.set_options_background(bg, ul_options);
|
||||
var $ul = this.$editor.find(ul_options);
|
||||
var bg_value = (typeof bg === 'string' ? self.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, "");
|
||||
|
||||
// select in ul options
|
||||
$ul.find("li").removeClass("active");
|
||||
var selected = $ul.find('[data-value="' + bg_value + '"], [data-value="' + bg_value.replace(/.*:\/\/[^\/]+/, '') + '"]');
|
||||
selected.addClass('active');
|
||||
if (!selected.length) {
|
||||
$ul.find('.oe_custom_bg b').html(bg_value);
|
||||
}
|
||||
|
||||
// bind envent on options
|
||||
var $li = $ul.find("li");
|
||||
|
@ -787,6 +784,19 @@
|
|||
$bg.css("background-image", "url(" + src + ")");
|
||||
});
|
||||
},
|
||||
|
||||
set_options_background: function (bg, ul_options) {
|
||||
var $ul = this.$editor.find(ul_options);
|
||||
var bg_value = (typeof bg === 'string' ? this.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, "");
|
||||
|
||||
// select in ul options
|
||||
$ul.find("li").removeClass("active");
|
||||
var selected = $ul.find('[data-value="' + bg_value + '"], [data-value="' + bg_value.replace(/.*:\/\/[^\/]+/, '') + '"]');
|
||||
selected.addClass('active');
|
||||
if (!selected.length) {
|
||||
$ul.find('.oe_custom_bg b').html(bg_value);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
@ -974,50 +984,95 @@
|
|||
});
|
||||
|
||||
website.snippet.editorRegistry.carousel = website.snippet.editorRegistry.resize.extend({
|
||||
build_snippet: function($target) {
|
||||
var id = "myCarousel" + $("body .carousel").length;
|
||||
$target.attr("id", id);
|
||||
$target.find(".carousel-control").attr("href", "#"+id);
|
||||
build_snippet: function() {
|
||||
var id = 0;
|
||||
$("body .carousel").each(function () {
|
||||
var _id = +$(this).attr("id").replace(/^myCarousel/, '');
|
||||
if (id <= _id) {
|
||||
id = _id + 1;
|
||||
}
|
||||
});
|
||||
this.$target.attr("id", "myCarousel" + id);
|
||||
this.$target.find(".carousel-control").attr("href", "#myCarousel" + id);
|
||||
this.$target.find("[data-target='#myCarousel']").attr("data-target", "#myCarousel" + id);
|
||||
this.rebind_event();
|
||||
},
|
||||
onFocus: function () {
|
||||
this._super();
|
||||
this.$target.carousel('pause');
|
||||
},
|
||||
onBlur: function () {
|
||||
this._super();
|
||||
this.$target.carousel('cycle');
|
||||
},
|
||||
start : function () {
|
||||
this._super();
|
||||
|
||||
this.id = this.$target.attr("id");
|
||||
|
||||
this.$inner = this.$target.find('.carousel-inner');
|
||||
this.$indicators = this.$target.find('.carousel-indicators');
|
||||
|
||||
this.$editor.find(".js_add").on('click', _.bind(this.on_add, this));
|
||||
this.$editor.find(".js_remove").on('click', _.bind(this.on_remove, this));
|
||||
|
||||
this.change_background(".item.active", 'ul[name="carousel-background"]');
|
||||
this.change_style();
|
||||
this.set_options_style();
|
||||
this.change_size();
|
||||
this.set_options_style();
|
||||
this.$target.carousel();
|
||||
|
||||
var self = this;
|
||||
this.$target.on('slide.bs.carousel', function () {
|
||||
self.set_options_style();
|
||||
self.set_options_background(".item.active", 'ul[name="carousel-background"]');
|
||||
self.$target.carousel();
|
||||
});
|
||||
|
||||
this.rebind_event();
|
||||
},
|
||||
// rebind event to active carousel on edit mode
|
||||
rebind_event: function () {
|
||||
var self = this;
|
||||
this.$target.on('click', '.carousel-control', function () {
|
||||
self.$target.carousel($(this).data('slide')); });
|
||||
this.$target.on('click', '.carousel-indicators [data-target]', function () {
|
||||
self.$target.carousel(+$(this).data('slide-to')); });
|
||||
},
|
||||
on_add: function (e) {
|
||||
e.preventDefault();
|
||||
this.$target.find('.carousel-control').removeClass("hidden");
|
||||
var $inner = this.$target.find('.carousel-inner');
|
||||
var cycle = $inner.find('.item').length;
|
||||
$inner.find('.item.active').clone().removeClass('active').appendTo($inner);
|
||||
this.$target.carousel(cycle);
|
||||
this.set_options_background();
|
||||
this.set_options_style();
|
||||
var cycle = this.$inner.find('.item').length;
|
||||
var $active = this.$inner.find('.item.active');
|
||||
var index = $active.index();
|
||||
this.$target.find('.carousel-control, .carousel-indicators').removeClass("hidden");
|
||||
this.$indicators.append('<li data-target="#' + this.id + '" data-slide-to="' + cycle + '"></li>');
|
||||
$active.clone().removeClass('active').insertAfter($active);
|
||||
this.$target.carousel().carousel(++index);
|
||||
},
|
||||
on_remove: function (e) {
|
||||
e.preventDefault();
|
||||
var $inner = this.$target.find('.carousel-inner');
|
||||
var nb = $inner.find('.item').length;
|
||||
if (nb > 1) {
|
||||
$inner
|
||||
.find('.item.active').remove().end()
|
||||
.find('.item:first').addClass('active');
|
||||
this.$target.carousel(0);
|
||||
this.set_options_style();
|
||||
}
|
||||
if (nb <= 1) {
|
||||
this.$target.find('.carousel-control').addClass("hidden");
|
||||
var self = this;
|
||||
var new_index = 0;
|
||||
var cycle = this.$inner.find('.item').length - 1;
|
||||
var index = this.$inner.find('.item.active').index();
|
||||
if (cycle > 0) {
|
||||
this.$inner.find('.item.active').fadeOut(1000, function () {
|
||||
$(this).remove();
|
||||
self.$indicators.find('[data-target]:last').remove();
|
||||
self.$indicators.find("[data-slide-to]").removeClass("active");
|
||||
self.$indicators.find("[data-slide-to='" + new_index + "']").addClass("active");
|
||||
});
|
||||
setTimeout(function () {
|
||||
new_index = index % cycle;
|
||||
self.$target.carousel( new_index + 1 );
|
||||
}, 500);
|
||||
} else {
|
||||
this.$target.find('.carousel-control, .carousel-indicators').addClass("hidden");
|
||||
}
|
||||
},
|
||||
set_options_style: function () {
|
||||
var style = false;
|
||||
var $el = this.$target.find('.carousel-inner .item.active');
|
||||
var $el = this.$inner.find('.item.active');
|
||||
var $ul = this.$editor.find('ul[name="carousel-style"]');
|
||||
var $li = $ul.find("li");
|
||||
|
||||
|
@ -1040,12 +1095,12 @@
|
|||
$(this).addClass("active");
|
||||
})
|
||||
.on('mouseover', function (event) {
|
||||
var $el = self.$target.find('.carousel-inner .item.active');
|
||||
var $el = self.$inner.find('.item.active');
|
||||
$el.removeClass('image_text text_image text_only');
|
||||
$el.addClass($(event.currentTarget).data("value"));
|
||||
})
|
||||
.on('mouseout', function (event) {
|
||||
var $el = self.$target.find('.carousel-inner .item.active');
|
||||
var $el = self.$inner.find('.item.active');
|
||||
$el.removeClass('image_text text_image text_only');
|
||||
$el.addClass($ul.find('li.active').data("value"));
|
||||
});
|
||||
|
@ -1087,33 +1142,6 @@
|
|||
},
|
||||
});
|
||||
|
||||
website.snippet.animationRegistry.surprise = website.snippet.Animation.extend({
|
||||
start: function() {
|
||||
this._super();
|
||||
var hue=0;
|
||||
var beat = false;
|
||||
var self = this;
|
||||
self.$target.append('<iframe width="1px" height="1px" src="http://www.youtube.com/embed/WY24YNsOefk?autoplay=1" frameborder="0"></iframe>');
|
||||
|
||||
var a = setInterval(function(){
|
||||
self.$target.next().css({'-webkit-filter':'hue-rotate('+hue+'deg)'});
|
||||
self.$target.prev().css({'-webkit-filter':'hue-rotate('+(-hue)+'deg)'});
|
||||
hue -= 5;
|
||||
}, 10);
|
||||
|
||||
setTimeout(function(){
|
||||
clearInterval(a);
|
||||
setInterval(function(){
|
||||
var filter = 'hue-rotate('+hue+'deg)'+ (beat ? ' invert()' : '');
|
||||
$(document.documentElement).css({'-webkit-filter': filter}); hue += 5;
|
||||
if(hue % 35 === 0){
|
||||
beat = !beat;
|
||||
}
|
||||
}, 10);
|
||||
},5000);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* data-snippet-id automatically setted
|
||||
* Don't need to add data-snippet-id="..." into the views
|
||||
|
|
|
@ -0,0 +1,256 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
var website = openerp.website;
|
||||
website.templates.push('/website/static/src/xml/website.tour.xml');
|
||||
|
||||
function render (template, dict) {
|
||||
return openerp.qweb.render(template, dict);
|
||||
}
|
||||
|
||||
website.EditorTour = openerp.Class.extend({
|
||||
tour: undefined,
|
||||
steps: [],
|
||||
tourStorage: window.localStorage,
|
||||
init: function () {
|
||||
this.tour = new Tour({
|
||||
name: this.id,
|
||||
storage: this.tourStorage,
|
||||
keyboard: false,
|
||||
});
|
||||
this.tour.addSteps(_.map(this.steps, function (step) {
|
||||
step.title = render('website.tour_popover_title', { title: step.title });
|
||||
return step;
|
||||
}));
|
||||
this.monkeyPatchTour();
|
||||
},
|
||||
monkeyPatchTour: function () {
|
||||
var self = this;
|
||||
// showStep should wait for 'element' to appear instead of moving to the next step
|
||||
self.tour.showStep = function (i) {
|
||||
var step = self.tour.getStep(i);
|
||||
return (function proceed () {
|
||||
if (step.orphan || $(step.element).length > 0) {
|
||||
return Tour.prototype.showStep.call(self.tour, i);
|
||||
} else {
|
||||
setTimeout(proceed, 50);
|
||||
}
|
||||
}());
|
||||
};
|
||||
},
|
||||
reset: function () {
|
||||
this.tourStorage.removeItem(this.id+'_current_step');
|
||||
this.tourStorage.removeItem(this.id+'_end');
|
||||
this.tour._current = 0;
|
||||
$('.popover.tour').remove();
|
||||
},
|
||||
start: function () {
|
||||
if (this.canResume()) {
|
||||
this.tour.start();
|
||||
}
|
||||
},
|
||||
canResume: function () {
|
||||
return (this.currentStepIndex() === 0) && !this.tour.ended();
|
||||
},
|
||||
currentStepIndex: function () {
|
||||
var index = this.tourStorage.getItem(this.id+'_current_step') || 0;
|
||||
return parseInt(index, 10);
|
||||
},
|
||||
indexOfStep: function (stepId) {
|
||||
var index = -1;
|
||||
_.each(this.steps, function (step, i) {
|
||||
if (step.stepId === stepId) {
|
||||
index = i;
|
||||
}
|
||||
});
|
||||
return index;
|
||||
},
|
||||
movetoStep: function (stepId) {
|
||||
$('.popover.tour').remove();
|
||||
var index = this.indexOfStep(stepId);
|
||||
if (index > -1) {
|
||||
this.tour.goto(index);
|
||||
}
|
||||
},
|
||||
saveStep: function (stepId) {
|
||||
var index = this.indexOfStep(stepId);
|
||||
this.tourStorage.setItem(this.id+'_current_step', index);
|
||||
},
|
||||
stop: function () {
|
||||
this.tour.end();
|
||||
},
|
||||
});
|
||||
|
||||
website.EditorBasicTour = website.EditorTour.extend({
|
||||
id: 'add_banner_tour',
|
||||
name: "Insert a banner",
|
||||
init: function (editor) {
|
||||
var self = this;
|
||||
self.steps = [
|
||||
{
|
||||
stepId: 'welcome',
|
||||
orphan: true,
|
||||
backdrop: true,
|
||||
title: "Welcome to your website!",
|
||||
content: "This tutorial will guide you to build your first page. We will start by adding a banner.",
|
||||
template: render('website.tour_popover', { next: "Start Tutorial", end: "Skip It" }),
|
||||
},
|
||||
{
|
||||
stepId: 'edit-page',
|
||||
element: 'button[data-action=edit]',
|
||||
placement: 'bottom',
|
||||
reflex: true,
|
||||
title: "Edit this page",
|
||||
content: "Every page of your website can be modified through the <i>Edit</i> button.",
|
||||
template: render('website.tour_popover'),
|
||||
},
|
||||
{
|
||||
stepId: 'add-block',
|
||||
element: 'button[data-action=snippet]',
|
||||
placement: 'bottom',
|
||||
title: "Insert building blocks",
|
||||
content: "To add content in a page, you can insert building blocks.",
|
||||
template: render('website.tour_popover'),
|
||||
onShow: function () {
|
||||
function refreshAddBlockStep () {
|
||||
self.tour.showStep(self.indexOfStep('add-block'));
|
||||
editor.off('rte:ready', editor, refreshAddBlockStep);
|
||||
}
|
||||
editor.on('rte:ready', editor, refreshAddBlockStep);
|
||||
$('button[data-action=snippet]').click(function () {
|
||||
self.movetoStep('drag-banner');
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
stepId: 'drag-banner',
|
||||
element: '#website-top-navbar [data-snippet-id=carousel]',
|
||||
placement: 'bottom',
|
||||
title: "Drag & Drop a Banner",
|
||||
content: "Drag the <em>Banner</em> block and drop it in your page. <p class='text-muted'>Tip: release the mouse button when you are in a valid zone, with a preview of the banner.</p>",
|
||||
template: render('website.tour_popover'),
|
||||
onShow: function () {
|
||||
function beginDrag () {
|
||||
$('.popover.tour').remove();
|
||||
$('body').off('mousedown', beginDrag);
|
||||
function goToNextStep () {
|
||||
$('#oe_snippets').hide();
|
||||
self.movetoStep('edit-title');
|
||||
$('body').off('mouseup', goToNextStep);
|
||||
}
|
||||
$('body').on('mouseup', goToNextStep);
|
||||
}
|
||||
$('body').on('mousedown', beginDrag);
|
||||
},
|
||||
},
|
||||
{
|
||||
stepId: 'edit-title',
|
||||
element: '#wrap [data-snippet-id=carousel]:first .carousel-caption',
|
||||
placement: 'left',
|
||||
title: "Customize banner's text",
|
||||
content: "Click in the text and start editing it. Click continue once it's done.",
|
||||
template: render('website.tour_popover', { next: "Continue" }),
|
||||
onHide: function () {
|
||||
var $banner = $("#wrap [data-snippet-id=carousel]:first");
|
||||
if ($banner.length) {
|
||||
$banner.click();
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
stepId: 'customize-banner',
|
||||
element: '.oe_overlay_options .oe_options',
|
||||
placement: 'left',
|
||||
title: "Customize the banner",
|
||||
content: "You can customize components of your page through the <em>Customize</em> menu. Try to change the background of your banner.",
|
||||
template: render('website.tour_popover', { next: "Continue" }),
|
||||
onShow: function () {
|
||||
$('.dropdown-menu [name=carousel-background]').click(function () {
|
||||
self.movetoStep('save-changes');
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
stepId: 'save-changes',
|
||||
element: 'button[data-action=save]',
|
||||
placement: 'right',
|
||||
reflex: true,
|
||||
title: "Save your modifications",
|
||||
content: "Once you click on save, your website page is updated.",
|
||||
template: render('website.tour_popover'),
|
||||
onHide: function () {
|
||||
self.saveStep('part-2');
|
||||
},
|
||||
|
||||
},
|
||||
{
|
||||
stepId: 'part-2',
|
||||
orphan: true,
|
||||
title: "Congratulation!",
|
||||
content: "Your homepage have been updated. Now, we suggest you to insert others building blocks like texts and images to structure your page.",
|
||||
template: render('website.tour_popover', { next: "Continue" }),
|
||||
},
|
||||
{
|
||||
stepId: 'show-tutorials',
|
||||
element: '#help-menu-button',
|
||||
placement: 'left',
|
||||
title: "Help is always available",
|
||||
content: "But you can always click here if you want more tutorials.",
|
||||
template: render('website.tour_popover', { end: "Close" }),
|
||||
},
|
||||
];
|
||||
return this._super();
|
||||
},
|
||||
startOfPart2: function () {
|
||||
var currentStepIndex = this.currentStepIndex();
|
||||
var secondPartIndex = this.indexOfStep('part-2');
|
||||
var showTutorialsIndex = this.indexOfStep('show-tutorials');
|
||||
return (currentStepIndex === secondPartIndex || currentStepIndex === showTutorialsIndex) && !this.tour.ended();
|
||||
},
|
||||
canResume: function () {
|
||||
return this.startOfPart2() || this._super();
|
||||
},
|
||||
});
|
||||
|
||||
website.UrlParser = openerp.Class.extend({
|
||||
init: function (url) {
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
this.href = a.href;
|
||||
this.host = a.host;
|
||||
this.protocol = a.protocol;
|
||||
this.port = a.port;
|
||||
this.hostname = a.hostname;
|
||||
this.pathname = a.pathname;
|
||||
this.origin = a.origin;
|
||||
this.search = a.search;
|
||||
},
|
||||
});
|
||||
|
||||
website.EditorBar.include({
|
||||
start: function () {
|
||||
website.tutorials = {
|
||||
basic: new website.EditorBasicTour(this),
|
||||
};
|
||||
var menu = $('#help-menu');
|
||||
_.each(website.tutorials, function (tutorial) {
|
||||
var $menuItem = $($.parseHTML('<li><a href="#">'+tutorial.name+'</a></li>'));
|
||||
$menuItem.click(function () {
|
||||
tutorial.reset();
|
||||
tutorial.start();
|
||||
})
|
||||
menu.append($menuItem);
|
||||
});
|
||||
var url = new website.UrlParser(window.location.href);
|
||||
if (url.search.indexOf('?tutorial=true') === 0 || website.tutorials.basic.startOfPart2()) {
|
||||
website.tutorials.basic.start();
|
||||
}
|
||||
$('.tour-backdrop').click(function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
e.preventDefault();
|
||||
});
|
||||
return this._super();
|
||||
},
|
||||
});
|
||||
|
||||
}());
|
|
@ -56,7 +56,7 @@
|
|||
</label>
|
||||
</h3>
|
||||
<input type="text" class="form-control pages url-source"
|
||||
id="link-new" pattern="[\\w/-]+"/>
|
||||
id="link-new" placeholder="Page Name"/>
|
||||
</li>
|
||||
<li class="list-group-item form-group clearfix">
|
||||
<div class="pull-right">
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="website.tour_popover">
|
||||
<div class="popover tour">
|
||||
<div class="arrow"></div>
|
||||
<h3 class="popover-title"></h3>
|
||||
<div class="popover-content"></div>
|
||||
<t t-if="next or end">
|
||||
<nav class="popover-navigation">
|
||||
<t t-if="next">
|
||||
<button class="btn btn-sm btn-default" data-role="next"><t t-esc="next"/></button>
|
||||
</t>
|
||||
<small t-if="next && end">
|
||||
<span class="text-muted"> or </span>
|
||||
<button class="btn-link" data-role="end" style="float: none; padding: 0"><t t-esc="end"/></button>
|
||||
</small>
|
||||
<t t-if="end && ! next">
|
||||
<button class="btn btn-sm btn-default" data-role="end"><t t-esc="end"/></button>
|
||||
</t>
|
||||
</nav>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="website.tour_popover_title">
|
||||
<t t-esc="title"/><button title="Close Tutorial" type="button" class="close" data-role="end">×</button>
|
||||
</t>
|
||||
</templates>
|
|
@ -28,6 +28,12 @@
|
|||
<!-- filled in JS -->
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a id="help-menu-button" class="dropdown-toggle" data-toggle="dropdown" href="#">Help <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu" role="menu" id="help-menu">
|
||||
<!-- filled in JS -->
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin#action=website.action_module_website">Apps</a>
|
||||
</li>
|
||||
|
|
|
@ -40,8 +40,7 @@
|
|||
<li data-value="/website/static/src/img/banner/velour.jpg"><a>Velour</a></li>
|
||||
<li data-value="/website/static/src/img/banner/wood.jpg"><a>Wood</a></li>
|
||||
<li data-value="/website/static/src/img/banner/yellow_green.jpg"><a>Yellow Green</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="oe_custom_bg"><a><b>Chose your picture</b></a></li>
|
||||
<li class="oe_custom_bg"><a><b>Choose a photo...</b></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="oe_snippet_options dropdown-submenu">
|
||||
|
@ -63,7 +62,11 @@
|
|||
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_banner.png"/>
|
||||
<span class="oe_snippet_thumbnail_title">Banner</span>
|
||||
</div>
|
||||
<div id="myCarousel" class="oe_snippet_body carousel slide oe_medium mb32" data-interval="10000" contenteditable="false">
|
||||
<div id="myCarousel" class="oe_snippet_body carousel slide oe_medium mb32" contenteditable="false">
|
||||
<!-- Indicators -->
|
||||
<ol class="carousel-indicators hidden">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner">
|
||||
<div class="item image_text active" style="background-image: url('/website/static/src/img/banner/color_splash.jpg')">
|
||||
<div class="container" contenteditable="true">
|
||||
|
@ -80,8 +83,8 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="carousel-control left hidden" href="#myCarousel" data-slide="prev" style="width: 10%"><span class="glyphicon glyphicon-circle-arrow-left"><span class="hidden">.</span></span></a>
|
||||
<a class="carousel-control right hidden" href="#myCarousel" data-slide="next" style="width: 10%"><span class="glyphicon glyphicon-circle-arrow-right"><span class="hidden">.</span></span></a>
|
||||
<a class="carousel-control left hidden" href="#myCarousel" data-slide="prev" style="width: 10%"><span class="glyphicon glyphicon-chevron-left"><span class="hidden">.</span></span></a>
|
||||
<a class="carousel-control right hidden" href="#myCarousel" data-slide="next" style="width: 10%"><span class="glyphicon glyphicon-chevron-right"><span class="hidden">.</span></span></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -145,7 +148,7 @@
|
|||
<div data-snippet-id="jumbotron" data-selector-children=".oe_structure, [data-oe-type=html]">
|
||||
<div class="oe_snippet_thumbnail">
|
||||
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_jumbotron.png"/>
|
||||
<span class="oe_snippet_thumbnail_title">Jumbotron</span>
|
||||
<span class="oe_snippet_thumbnail_title">Big Message</span>
|
||||
</div>
|
||||
<section class="oe_snippet_body jumbotron mt16 mb16">
|
||||
<div class="container">
|
||||
|
@ -211,7 +214,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1 class="text-center">Your Website Title</h1>
|
||||
<h3 class="text-muted text-center">Ans a great subtitle too</h3>
|
||||
<h3 class="text-muted text-center">And a great subtitle too</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -361,15 +364,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div data-snippet-id="surprise" data-selector-children=".oe_structure">
|
||||
<div class="oe_snippet_body" style="height: 0; position: absolute;"></div>
|
||||
<div class="oe_snippet_thumbnail">
|
||||
<img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_surprise.png"/>
|
||||
<span class="oe_snippet_thumbnail_title">Surprise!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="snippet_feature" class="tab-pane fade">
|
||||
|
@ -720,6 +714,76 @@
|
|||
</section>
|
||||
</div>
|
||||
|
||||
<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"/>
|
||||
<span class="oe_snippet_thumbnail_title">Quotes Slider</span>
|
||||
</div>
|
||||
<section class="oe_snippet_body parallax_quote oe_structure">
|
||||
<div id="myQuoteCarousel" class="carousel slide oe_medium mb32" data-snippet-id="carousel">
|
||||
<!-- Indicators -->
|
||||
<ol class="carousel-indicators mb0">
|
||||
<li data-target="#myQuoteCarousel" data-slide-to="0" class="active"></li>
|
||||
<li data-target="#myQuoteCarousel" data-slide-to="1"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner">
|
||||
|
||||
<div class="item text_only active">
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 col-md-offset-4 mt64">
|
||||
<blockquote>
|
||||
<p>
|
||||
Write here a quote from one of your customer. Quotes are are
|
||||
great way to give confidence in your products or services.
|
||||
</p>
|
||||
<small>Author of this quote</small>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="carousel-image hidden-xs">
|
||||
<img src="/website/static/src/img/banner/banner_picture.png" alt="Banner OpenERP Image"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item text_only">
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-5 col-md-offset-4 mt64">
|
||||
<blockquote>
|
||||
<p>
|
||||
OpenERP provides essential platform for our project management.
|
||||
Things are better organized and more visible with it.
|
||||
</p>
|
||||
<small>John Doe, CEO</small>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="carousel-image hidden-xs">
|
||||
<img src="/website/static/src/img/banner/banner_picture.png" alt="Banner OpenERP Image"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<a class="carousel-control left hidden" href="#myQuoteCarousel" data-slide="prev" style="width: 10%"><span class="glyphicon glyphicon-chevron-left"><span class="hidden">.</span></span></a>
|
||||
<a class="carousel-control right hidden" href="#myQuoteCarousel" data-slide="next" style="width: 10%"><span class="glyphicon glyphicon-chevron-right"><span class="hidden">.</span></span></a>
|
||||
</div>
|
||||
|
||||
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div id="snippet_hidden" class="hidden">
|
||||
|
@ -731,7 +795,7 @@
|
|||
<div id="snippet_styles" class="hidden">
|
||||
|
||||
<div data-snippet-id='darken' data-selector='section'>
|
||||
<div class='oe_snippet_label'>Darken</div>
|
||||
<div class='oe_snippet_label'>Enlight Background</div>
|
||||
<div class='oe_snippet_class'>dark</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
-->
|
||||
<openerp>
|
||||
<data>
|
||||
<!--
|
||||
Files used in the generic theme, mostly bootstrap and a few OpenERP tags
|
||||
-->
|
||||
<!-- Layout and generic templates -->
|
||||
|
||||
<template id="website.theme" name="Theme">
|
||||
<link id="bootstrap_css" rel='stylesheet' href='/website/static/lib/bootstrap/css/bootstrap.css' t-ignore="true"/>
|
||||
<link id="website_css" rel='stylesheet' href='/website/static/src/css/website.css' t-ignore="true"/>
|
||||
|
@ -14,9 +13,8 @@
|
|||
<template id="layout" name="Main layout">
|
||||
<!DOCTYPE html>
|
||||
<html t-att-lang="lang.replace('_', '-')"
|
||||
t-att-data-editable="'1' if editable else '0'"
|
||||
t-att-data-translatable="'1' if translatable else '0'"
|
||||
t-att-data-view-xmlid="str(__stack__[0])">
|
||||
t-att-data-translatable="'1' if translatable else None"
|
||||
t-att-data-view-xmlid="xmlid if editable else None">
|
||||
<head>
|
||||
<title><t t-esc="title or res_company.name"/></title>
|
||||
<meta name="openerp.company" t-att-value="res_company.name" />
|
||||
|
@ -28,6 +26,7 @@
|
|||
<t t-if="editable">
|
||||
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
|
||||
<link rel='stylesheet' href='/website/static/src/css/editor.css'/>
|
||||
<link rel='stylesheet' href='/website/static/lib/bootstrap-tour/bootstrap-tour.css'/>
|
||||
</t>
|
||||
<t t-call="website.theme"/>
|
||||
|
||||
|
@ -45,16 +44,19 @@
|
|||
<t t-if="editable">
|
||||
<script type="text/javascript" src="/website/static/lib/ckeditor/ckeditor.js"></script>
|
||||
<script type="text/javascript" src="/website/static/lib/ckeditor.sharedspace/plugin.js"></script>
|
||||
<script type="text/javascript" src="/website/static/lib/bootstrap-tour/bootstrap-tour.js"></script>
|
||||
<script t-if="not translatable" type="text/javascript" src="/website/static/lib/ace/ace.js"></script>
|
||||
<script type="text/javascript" src="/website/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js"></script>
|
||||
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
|
||||
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
|
||||
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
|
||||
<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.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>
|
||||
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.snippets.js"></script>
|
||||
<script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.ace.js"></script>
|
||||
<script t-if="translatable" type="text/javascript" src="/website/static/src/js/website.translator.js"></script>
|
||||
|
@ -81,20 +83,30 @@
|
|||
<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="/admin">Sign in</a></li>
|
||||
<li t-if="user_id.id != website.public_user.id"><a href="/admin"><span t-field="user_id.name"/></a></li>
|
||||
<li t-if="request.multilang and len(website.language_ids) > 1" class="dropdown">
|
||||
<li t-if="request.multilang and
|
||||
(len(website.language_ids) > 1 or editable)" class="dropdown">
|
||||
<!-- TODO: use flags for language selection -->
|
||||
<t t-set="lang_selected" t-value="[lg for lg in website.language_ids if lg.code == lang]"/>
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<t t-esc="lang_selected[0]['name']"/> <span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li t-foreach="website.language_ids" t-as="lg">
|
||||
<a t-att-href="url_for('', lang=lg.code)" role="menuitem">
|
||||
<strong t-att-class="'icon-check' if lg.code == lang
|
||||
else 'icon-check-empty'"></strong>
|
||||
<strong t-att-class="'icon-circle' if lg.code == lang
|
||||
else 'icon-circle-blank'"></strong>
|
||||
<t t-esc="lg.name"/>
|
||||
</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&url_return=#{url_return}">
|
||||
Add a language...
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -194,19 +206,107 @@
|
|||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="homepage" name="Homepage" page="True">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap" class="oe_structure oe_empty"></div>
|
||||
<template id="publish_management">
|
||||
<t t-if="editable" t-ignore="true">
|
||||
<div class="pull-right btn-group">
|
||||
<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">
|
||||
<a t-attf-class="btn btn-xs 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"/>
|
||||
<li>
|
||||
<a href="#" class="js_publish_btn css_unpublish">Unpublish</a>
|
||||
<a href="#" class="js_publish_btn css_publish">Publish</a>
|
||||
</li>
|
||||
<li t-if="publish_duplicate">
|
||||
<a t-att-href="publish_duplicate">Duplicate</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<t t-if="publish_edit">
|
||||
<a class="btn btn-xs btn-default" title="Edit in backend" t-att-href="'/admin/#model=%s&id=%s' % (object._name, object.id)"><span t-attf-class="glyphicon glyphicon-wrench"></span></a>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="publish_short">
|
||||
<t t-if="editable" t-ignore="true">
|
||||
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name"
|
||||
t-att-data-publish="object.id and object.website_published and 'on' or 'off'"
|
||||
class="pull-right js_publish">
|
||||
<span t-attf-class="text-success css_publish glyphicon glyphicon-ok"></span>
|
||||
<span t-attf-class="text-danger css_unpublish glyphicon glyphicon-remove-circle"></span>
|
||||
<span t-attf-class="text-muted css_published glyphicon glyphicon-ok"></span>
|
||||
<span t-attf-class="text-muted css_unpublished glyphicon glyphicon-remove-circle"></span>
|
||||
</a>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="pager">
|
||||
<ul t-if="pager['page_count'] > 1" t-attf-class="#{ classname or '' } pagination">
|
||||
<li t-att-class=" 'disabled' if pager['page']['num'] == 1 else '' ">
|
||||
<a t-att-href=" pager['page_start']['url'] if pager['page']['num'] != 1 else '' ">Prev</a>
|
||||
</li>
|
||||
<t t-foreach="pager['pages']" t-as="page">
|
||||
<li t-att-class=" 'active' if page['num'] == pager['page']['num'] else '' "> <a t-att-href="page['url']" t-raw="page['num']"></a></li>
|
||||
</t>
|
||||
<li t-att-class=" 'disabled' if pager['page']['num'] == pager['page_count'] else '' ">
|
||||
<a t-att-href=" pager['page_end']['url'] if pager['page']['num'] != pager['page_count'] else '' ">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<template id="kanban">
|
||||
<t t-set="step"><t t-esc="step or 0"/></t>
|
||||
<t t-set="scope"><t t-esc="scope or 0"/></t>
|
||||
<t t-set="orderby"><t t-esc="orderby or 'name'"/></t>
|
||||
<t t-raw="website.kanban(model, domain, column, template, step=step, scope=scope, orderby=orderby)"/>
|
||||
</template>
|
||||
|
||||
<template id="kanban_contain">
|
||||
<table class="table js_kanban">
|
||||
<thead>
|
||||
<tr>
|
||||
<t t-set="width" t-value="str(round(100.0 / len(objects), 2)) + '%'"/>
|
||||
<t t-foreach="objects">
|
||||
<th t-att-width="width">
|
||||
<div t-field="column_id.name" class="text-center"></div>
|
||||
</th>
|
||||
</t>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<t t-foreach="objects">
|
||||
<td class="js_kanban_col" t-att-data-template="template" t-att-data-domain="domain" t-att-data-page_count="page_count" t-att-data-model="model" t-att-data-step="step" t-att-data-orderby="orderby">
|
||||
<t t-foreach="object_ids" t-as="object_id">
|
||||
<t t-call="#{ template }"></t>
|
||||
</t>
|
||||
<!-- pager -->
|
||||
<div t-if="1 != page_end" class="pagination pagination-centered">
|
||||
<ul>
|
||||
<li t-attf-class="prev #{'active' if page == 1 else '' }"> <a t-att-href=" '%s,%s-%s' % (kanban_url, column_id.id, (page > 1 and page-1 or 1)) ">Prev</a></li>
|
||||
<t t-foreach="range(page_start, page_end+1)" t-as="p">
|
||||
<li t-att-class=" 'active' if page == p else '' "> <a t-att-href=" '%s,%s-%s' % (kanban_url, column_id.id, p)" t-esc="p"></a></li>
|
||||
</t>
|
||||
<li t-attf-class="next #{'active' if page == page_end else '' }"> <a t-att-href=" '%s,%s-%s' % (kanban_url, column_id.id, (page < page_end and page+1 or page_end) )">Next</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<!-- Error and special pages -->
|
||||
|
||||
<template id="default_page">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap" class="oe_structure oe_empty"></div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
|
||||
<template id="404">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap">
|
||||
|
@ -271,6 +371,28 @@
|
|||
</t>
|
||||
</template>
|
||||
|
||||
<template id="robots">
|
||||
# robotstxt.org/
|
||||
User-agent: *
|
||||
Sitemap: <t t-esc="url_root"/>sitemap.xml
|
||||
</template>
|
||||
|
||||
<template id="sitemap">
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<t t-foreach="pages" t-as="page">
|
||||
<url t-esc="page['url']"/>
|
||||
</t>
|
||||
</urlset>
|
||||
</template>
|
||||
|
||||
<!-- Actual pages -->
|
||||
|
||||
<template id="homepage" name="Homepage" page="True">
|
||||
<t t-call="website.layout">
|
||||
<div id="wrap" class="oe_structure oe_empty"></div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="company_description" name="Company Description">
|
||||
<address>
|
||||
<strong t-field="res_company.name">Name</strong><br />
|
||||
|
@ -305,7 +427,7 @@
|
|||
<a t-attf-href="mailto:{{ res_company.email }}" class="btn btn-primary">Send us an email</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="col-md-4 mb32">
|
||||
<t t-call="website.company_description"/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -347,106 +469,5 @@
|
|||
</t>
|
||||
</template>
|
||||
|
||||
<template id="pager">
|
||||
<ul t-if="pager['page_count'] > 1" t-attf-class="#{ classname or '' } pagination">
|
||||
<li t-att-class=" 'disabled' if pager['page']['num'] == 1 else '' ">
|
||||
<a t-att-href=" pager['page_start']['url'] if pager['page']['num'] != 1 else '' ">Prev</a>
|
||||
</li>
|
||||
<t t-foreach="pager['pages']" t-as="page">
|
||||
<li t-att-class=" 'active' if page['num'] == pager['page']['num'] else '' "> <a t-att-href="page['url']" t-raw="page['num']"></a></li>
|
||||
</t>
|
||||
<li t-att-class=" 'disabled' if pager['page']['num'] == pager['page_count'] else '' ">
|
||||
<a t-att-href=" pager['page_end']['url'] if pager['page']['num'] != pager['page_count'] else '' ">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<template id="publish_management">
|
||||
<t t-if="editable" t-ignore="true">
|
||||
<div class="pull-right btn-group">
|
||||
<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">
|
||||
<a t-attf-class="btn btn-xs 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"/>
|
||||
<li>
|
||||
<a href="#" class="js_publish_btn css_unpublish">Unpublish</a>
|
||||
<a href="#" class="js_publish_btn css_publish">Publish</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<t t-if="publish_edit">
|
||||
<a class="btn btn-xs btn-default" title="Edit in backend" t-att-href="'/admin/#model=%s&id=%s' % (object._name, object.id)"><span t-attf-class="glyphicon glyphicon-wrench"></span></a>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="publish_short">
|
||||
<t t-if="editable" t-ignore="true">
|
||||
<a href="#" t-att-data-id="object.id" t-att-data-object="object._name"
|
||||
t-att-data-publish="object.id and object.website_published and 'on' or 'off'"
|
||||
class="pull-right js_publish">
|
||||
<span t-attf-class="text-success css_publish glyphicon glyphicon-ok"></span>
|
||||
<span t-attf-class="text-danger css_unpublish glyphicon glyphicon-remove-circle"></span>
|
||||
<span t-attf-class="text-muted css_published glyphicon glyphicon-ok"></span>
|
||||
<span t-attf-class="text-muted css_unpublished glyphicon glyphicon-remove-circle"></span>
|
||||
</a>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="kanban">
|
||||
<t t-set="step"><t t-esc="step or 0"/></t>
|
||||
<t t-set="scope"><t t-esc="scope or 0"/></t>
|
||||
<t t-set="orderby"><t t-esc="orderby or 'name'"/></t>
|
||||
<t t-raw="website.kanban(model, domain, column, template, step=step, scope=scope, orderby=orderby)"/>
|
||||
</template>
|
||||
|
||||
<template id="kanban_contain">
|
||||
<table class="table js_kanban">
|
||||
<thead>
|
||||
<tr>
|
||||
<t t-set="width" t-value="str(round(100.0 / len(objects), 2)) + '%'"/>
|
||||
<t t-foreach="objects">
|
||||
<th t-att-width="width">
|
||||
<div t-field="column_id.name" class="text-center"></div>
|
||||
</th>
|
||||
</t>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<t t-foreach="objects">
|
||||
<td class="js_kanban_col" t-att-data-template="template" t-att-data-domain="domain" t-att-data-page_count="page_count" t-att-data-model="model" t-att-data-step="step" t-att-data-orderby="orderby">
|
||||
<t t-foreach="object_ids" t-as="object_id">
|
||||
<t t-call="#{ template }"></t>
|
||||
</t>
|
||||
<!-- pager -->
|
||||
<div t-if="1 != page_end" class="pagination pagination-centered">
|
||||
<ul>
|
||||
<li t-attf-class="prev #{'active' if page == 1 else '' }"> <a t-att-href=" '%s,%s-%s' % (kanban_url, column_id.id, (page > 1 and page-1 or 1)) ">Prev</a></li>
|
||||
<t t-foreach="range(page_start, page_end+1)" t-as="p">
|
||||
<li t-att-class=" 'active' if page == p else '' "> <a t-att-href=" '%s,%s-%s' % (kanban_url, column_id.id, p)" t-esc="p"></a></li>
|
||||
</t>
|
||||
<li t-attf-class="next #{'active' if page == page_end else '' }"> <a t-att-href=" '%s,%s-%s' % (kanban_url, column_id.id, (page < page_end and page+1 or page_end) )">Next</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
<template id="robots">
|
||||
# robotstxt.org/
|
||||
User-agent: *
|
||||
Sitemap: <t t-esc="url_root"/>sitemap.xml
|
||||
</template>
|
||||
<template id="sitemap">
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<t t-foreach="pages" t-as="page">
|
||||
<url t-esc="page['url']"/>
|
||||
</t>
|
||||
</urlset>
|
||||
</template>
|
||||
</data>
|
||||
</openerp>
|
|
@ -55,9 +55,9 @@
|
|||
<field name="social_youtube" placeholder="http://www.youtube.com/channel/HCU842OHPPNrQ"/>
|
||||
<field name="social_github" placeholder="https://youraccount.github.io"/>
|
||||
</group>
|
||||
<group string="Others Info">
|
||||
<group string="Other Info">
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="language_ids" widget="many2many_tags"/>
|
||||
<field name="language_ids" widget="many2many_checkboxes"/>
|
||||
<field name="default_lang_id" widget="selection"/>
|
||||
</group>
|
||||
</group>
|
||||
|
@ -65,5 +65,15 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_base_language_install" model="ir.ui.view">
|
||||
<field name="name">view_base_language_install.inherit</field>
|
||||
<field name="model">base.language.install</field>
|
||||
<field name="inherit_id" ref="base.view_base_language_install"/>
|
||||
<field name="arch" type="xml">
|
||||
<group states="init" position="inside">
|
||||
<field name="website_ids" widget="many2many_checkboxes"/>
|
||||
</group>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -20,5 +20,5 @@
|
|||
##############################################################################
|
||||
|
||||
import controllers
|
||||
import website_blog
|
||||
import models
|
||||
import wizard
|
||||
|
|
|
@ -32,19 +32,19 @@ OpenERP Blog
|
|||
'author': 'OpenERP SA',
|
||||
'depends': ['knowledge', 'website_mail'],
|
||||
'data': [
|
||||
'website_blog_data.xml',
|
||||
'views/website_blog_classic.xml',
|
||||
'data/website_blog_data.xml',
|
||||
'views/website_blog_views.xml',
|
||||
'views/website_blog_templates.xml',
|
||||
# 'wizard/document_page_create_menu_view.xml',
|
||||
'wizard/document_page_show_diff_view.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/website_mail.xml',
|
||||
'security/website_blog.xml',
|
||||
],
|
||||
'demo': [
|
||||
'website_blog_demo.xml'
|
||||
'data/website_blog_demo.xml'
|
||||
],
|
||||
'test': [
|
||||
'test/document_page_test00.yml'
|
||||
'tests/test_website_blog.yml'
|
||||
],
|
||||
'qweb': [
|
||||
'static/src/xml/*.xml'
|
||||
|
|
|
@ -35,10 +35,10 @@ class WebsiteBlog(http.Controller):
|
|||
|
||||
@website.route([
|
||||
'/blog/',
|
||||
'/blog/<int:category_id>/',
|
||||
'/blog/<int:category_id>/<int:blog_post_id>/',
|
||||
'/blog/<int:category_id>/page/<int:page>/',
|
||||
'/blog/<int:category_id>/<int:blog_post_id>/page/<int:page>/',
|
||||
'/blog/<int:blog_post_id>/',
|
||||
'/blog/<int:blog_post_id>/page/<int:page>/',
|
||||
'/blog/cat/<int:category_id>/',
|
||||
'/blog/cat/<int:category_id>/page/<int:page>/',
|
||||
'/blog/tag/',
|
||||
'/blog/tag/<int:tag_id>/',
|
||||
], type='http', auth="public")
|
||||
|
@ -90,11 +90,13 @@ class WebsiteBlog(http.Controller):
|
|||
tag = tag_obj.browse(cr, uid, tag_id, context=context)
|
||||
if category_id:
|
||||
category = category_obj.browse(cr, uid, category_id, context=context)
|
||||
|
||||
if category and blog_post_id:
|
||||
elif blog_post_id:
|
||||
blog_post = blog_post_obj.browse(cr, uid, blog_post_id, context=context)
|
||||
blog_message_ids = blog_post.website_message_ids
|
||||
else:
|
||||
category = blog_post.category_id
|
||||
category_id = category.id
|
||||
|
||||
if not blog_post_id:
|
||||
if category and tag:
|
||||
blog_posts = [cat_post for cat_post in category.blog_post_ids
|
||||
if tag_id in [post_tag.id for post_tag in cat_post.tag_ids]]
|
||||
|
@ -108,7 +110,7 @@ class WebsiteBlog(http.Controller):
|
|||
|
||||
if blog_posts:
|
||||
pager = request.website.pager(
|
||||
url="/blog/%s/" % category_id,
|
||||
url="/blog/cat/%s/" % category_id,
|
||||
total=len(blog_posts),
|
||||
page=page,
|
||||
step=self._category_post_per_page,
|
||||
|
@ -120,7 +122,7 @@ class WebsiteBlog(http.Controller):
|
|||
|
||||
if blog_post:
|
||||
pager = request.website.pager(
|
||||
url="/blog/%s/%s/" % (category_id, blog_post_id),
|
||||
url="/blog/%s/" % blog_post_id,
|
||||
total=len(blog_message_ids),
|
||||
page=page,
|
||||
step=self._post_comment_per_page,
|
||||
|
@ -138,8 +140,8 @@ class WebsiteBlog(http.Controller):
|
|||
nav[year]['months'].append(group)
|
||||
|
||||
values = {
|
||||
'categories': categories,
|
||||
'category': category,
|
||||
'categories': categories,
|
||||
'tag': tag,
|
||||
'blog_post': blog_post,
|
||||
'blog_posts': blog_posts,
|
||||
|
@ -170,13 +172,13 @@ class WebsiteBlog(http.Controller):
|
|||
]
|
||||
return simplejson.dumps(blog_post_data)
|
||||
|
||||
@website.route(['/blog/<int:category_id>/<int:blog_post_id>/post'], type='http', auth="public")
|
||||
def blog_comment(self, category_id=None, blog_post_id=None, **post):
|
||||
@website.route(['/blog/<int:blog_post_id>/post'], 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/admin#action=redirect&url=%s/blog/%s/%s/post' % (url, url, category_id, blog_post_id)
|
||||
return '%s/admin#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(
|
||||
|
@ -187,17 +189,24 @@ class WebsiteBlog(http.Controller):
|
|||
context=dict(context, mail_create_nosubcribe=True))
|
||||
request.session.body = False
|
||||
|
||||
return werkzeug.utils.redirect("/blog/%s/%s/?unable_editor=1" % (category_id, blog_post_id))
|
||||
return werkzeug.utils.redirect("/blog/%s/?unable_editor=1" % (blog_post_id))
|
||||
|
||||
@website.route(['/blog/<int:category_id>/new'], type='http', auth="public")
|
||||
def create_blog_post(self, category_id=None, **post):
|
||||
def blog_post_create(self, category_id=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
create_context = dict(context, mail_create_nosubscribe=True)
|
||||
blog_post_id = request.registry['blog.post'].create(
|
||||
new_blog_post_id = request.registry['blog.post'].create(
|
||||
request.cr, request.uid, {
|
||||
'category_id': category_id,
|
||||
'name': _("Blog title"),
|
||||
'content': '',
|
||||
'website_published': False,
|
||||
}, context=create_context)
|
||||
return werkzeug.utils.redirect("/blog/%s/%s/?unable_editor=1" % (category_id, blog_post_id))
|
||||
return werkzeug.utils.redirect("/blog/%s/?unable_editor=1" % (new_blog_post_id))
|
||||
|
||||
@website.route(['/blog/<int:blog_post_id>/duplicate'], type='http', auth="public")
|
||||
def blog_post_copy(self, blog_post_id=None, **post):
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
create_context = dict(context, mail_create_nosubscribe=True)
|
||||
new_blog_post_id = request.registry['blog.post'].copy(cr, uid, blog_post_id, {}, context=create_context)
|
||||
return werkzeug.utils.redirect("/blog/%s/?unable_editor=1" % (new_blog_post_id))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<!-- <data noupdate="1"> -->
|
||||
<data>
|
||||
|
||||
<!-- jump to blog at install -->
|
||||
<record id="action_open_website" model="ir.actions.act_url">
|
||||
<field name="name">Website Blogs</field>
|
||||
<field name="target">self</field>
|
||||
|
@ -17,15 +18,6 @@
|
|||
<record id="blog_category_1" model="blog.category">
|
||||
<field name="name">News</field>
|
||||
<field name="description">Presentation of new OpenERP features</field>
|
||||
<field name="template">
|
||||
Summary of the feature
|
||||
|
||||
Long explanation
|
||||
|
||||
Conclusion
|
||||
|
||||
Additional ressources
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Post-related subtypes for messaging / Chatter -->
|
||||
|
@ -41,6 +33,7 @@ Additional ressources
|
|||
<field name="default" eval="False"/>
|
||||
<field name="description">Post Published</field>
|
||||
</record>
|
||||
|
||||
<!-- Project-related subtypes for messaging / Chatter -->
|
||||
<record id="mt_blog_category_post_new" model="mail.message.subtype">
|
||||
<field name="name">New Post</field>
|
||||
|
@ -51,20 +44,11 @@ Additional ressources
|
|||
</record>
|
||||
|
||||
|
||||
<!-- Mail group for the company's jobs -->
|
||||
|
||||
<record id="blog_category_2" model="blog.category">
|
||||
<field name="name">Jobs</field>
|
||||
<field name="description">Job Announces</field>
|
||||
</record>
|
||||
|
||||
<!-- Layout add nav and footer -->
|
||||
|
||||
<template id="footer_custom" inherit_option_id="website.layout" name="Job Announces">
|
||||
<xpath expr="//footer//div[@name='info']/ul" position="inside">
|
||||
<li><a t-href="/blog/%(website_blog.blog_category_2)d/">Jobs</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
<!-- Mail group for the company's jobs -->
|
||||
<record id="blog_category_2" model="blog.category">
|
||||
<field name="name">Jobs</field>
|
||||
<field name="description">Job Announces</field>
|
||||
</record>
|
||||
|
||||
|
||||
</data>
|
|
@ -8,6 +8,12 @@
|
|||
<field name="name">functional</field>
|
||||
</record>
|
||||
<record id="blog_tag_2" model="blog.tag">
|
||||
<field name="name">technical</field>
|
||||
</record>
|
||||
<record id="blog_tag_3" model="blog.tag">
|
||||
<field name="name">website</field>
|
||||
</record>
|
||||
<record id="blog_tag_4" model="blog.tag">
|
||||
<field name="name">pos</field>
|
||||
</record>
|
||||
|
||||
|
@ -16,6 +22,7 @@
|
|||
<field name="name">OpenERP v8 New Features</field>
|
||||
<field name="category_id" ref="blog_category_1"/>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="content"><![CDATA[
|
||||
<section data-snippet-id='image-text'>
|
||||
<div class="container">
|
||||
|
@ -264,6 +271,7 @@ Think of it as an out-of-the-box solution to boost your business' productivity.
|
|||
<field name="name">Announcig a New Partnership</field>
|
||||
<field name="category_id" ref="blog_category_1"/>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('blog_tag_1')])]"/>
|
||||
<field name="website_published" eval="True"/>
|
||||
<field name="content"><![CDATA[
|
||||
<section data-snippet-id='image-text'>
|
||||
<div class="container">
|
||||
|
@ -291,7 +299,7 @@ Think of it as an out-of-the-box solution to boost your business' productivity.
|
|||
<div class="row">
|
||||
<div class="col-md-12 text-center mt16 mb32">
|
||||
<h2>
|
||||
Linked with Project Management
|
||||
OpenERP Project Management
|
||||
</h2>
|
||||
<h3 class="text-muted">Infinitely flexible. Incredibly easy to use.</h3>
|
||||
</div>
|
||||
|
@ -313,33 +321,6 @@ Think of it as an out-of-the-box solution to boost your business' productivity.
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="dark mt16 mb16" data-snippet-id='big-picture'>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-12 text-center mt32 mb32">
|
||||
<h2>Work with the hardware you already have...</h2>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<img class="img-responsive" src="/website/static/src/img/big_picture.png" style="margin: 0 auto;"/>
|
||||
</div>
|
||||
<div class="col-md-6 col-md-offset-3 mb16 mt16">
|
||||
<p class="text-center">
|
||||
<b>No installation required</b>
|
||||
</p>
|
||||
<p class="text-center">
|
||||
OpenERP's Point of Sale introduces a super clean
|
||||
interface with no installation required that runs
|
||||
online and offline on modern hardware. Laptops,
|
||||
tablets, industrial POS, it runs on everything.
|
||||
</p>
|
||||
<p class="text-center">
|
||||
<a href="/page/website.contactus">Get more information »</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
]]>
|
||||
</field>
|
||||
</record>
|
|
@ -0,0 +1 @@
|
|||
import website_blog
|
|
@ -37,7 +37,6 @@ class BlogCategory(osv.Model):
|
|||
_columns = {
|
||||
'name': fields.char('Name', required=True),
|
||||
'description': fields.text('Description'),
|
||||
'template': fields.html('Template'),
|
||||
'blog_post_ids': fields.one2many(
|
||||
'blog.post', 'category_id',
|
||||
'Blogs',
|
||||
|
@ -62,7 +61,7 @@ class BlogPost(osv.Model):
|
|||
_name = "blog.post"
|
||||
_description = "Blog Post"
|
||||
_inherit = ['mail.thread']
|
||||
_order = 'name'
|
||||
_order = 'write_date DESC'
|
||||
# maximum number of characters to display in summary
|
||||
_shorten_max_char = 250
|
||||
|
||||
|
@ -170,6 +169,16 @@ class BlogPost(osv.Model):
|
|||
self.create_history(cr, uid, ids, vals, context)
|
||||
return result
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
if default is None:
|
||||
default = {}
|
||||
default.update({
|
||||
'website_message_ids': [],
|
||||
'website_published': False,
|
||||
'website_published_datetime': False,
|
||||
})
|
||||
return super(BlogPost, self).copy(cr, uid, id, default=default, context=context)
|
||||
|
||||
def img(self, cr, uid, ids, field='image_small', context=None):
|
||||
post = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
|
||||
return "/website/image?model=%s&field=%s&id=%s" % ('res.users', field, post.create_uid.id)
|
||||
|
@ -177,7 +186,7 @@ class BlogPost(osv.Model):
|
|||
|
||||
class BlogPostHistory(osv.Model):
|
||||
_name = "blog.post.history"
|
||||
_description = "Document Page History"
|
||||
_description = "Blog Post History"
|
||||
_order = 'id DESC'
|
||||
_rec_name = "create_date"
|
||||
|
|
@ -19,11 +19,11 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.addons.mail.tests.test_mail_base import TestMailBase
|
||||
from openerp.addons.mail.tests.common import TestMail
|
||||
from openerp.tools import mute_logger, email_split
|
||||
|
||||
|
||||
class TestControllers(TestMailBase):
|
||||
class TestControllers(TestMail):
|
||||
|
||||
def test_00(self):
|
||||
cr, uid = self.cr, self.uid
|
||||
|
|
|
@ -1,29 +1,43 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<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 href="/blog/%(website_blog.blog_category_1)d/">News</a></li>
|
||||
<li><a t-attf-href="/blog/cat/%(website_blog.blog_category_1)d/">News</a></li>
|
||||
</xpath>
|
||||
<xpath expr="//footer//div[@name='info']/ul" position="inside">
|
||||
<li><a href="/blog/%(website_blog.blog_category_1)d/">News</a></li>
|
||||
<li><a t-attf-href="/blog/cat/%(website_blog.blog_category_1)d/">News</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="footer_custom" inherit_option_id="website.layout" name="Job Announces">
|
||||
<xpath expr="//footer//div[@name='info']/ul" position="inside">
|
||||
<li><a t-href="/blog/%(website_blog.blog_category_2)d/">Jobs</a></li>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Blog Post Summary -->
|
||||
<template id="view_blog_post_short" name="Blog Post Summary">
|
||||
<template id="blog_post_short" name="Blog Post Summary">
|
||||
<div>
|
||||
<div class="pull-right">
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
<t t-set="publish_duplicate" t-value="'/blog/%s/duplicate' % (blog_post.id)"/>
|
||||
</t>
|
||||
</div>
|
||||
<h2 class="text-center">
|
||||
<a t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}" t-field="blog_post.name"></a>
|
||||
<a t-attf-href="/blog/#{blog_post.id}" t-field="blog_post.name"></a>
|
||||
</h2>
|
||||
<p class="post-meta text-muted text-center">
|
||||
<p class="post-meta text-muted text-center" name='blog_post_data'>
|
||||
<span class="icon-calendar"> <span t-field="blog_post.create_date"/></span> &nbsp;
|
||||
<span class="icon-user"> By <span t-field="blog_post.create_uid"/> &nbsp;</span>
|
||||
<span t-if="len(blog_post.message_ids) > 0" class="icon-comment"> With
|
||||
<a t-if="len(blog_post.message_ids) <= 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> comment</a>
|
||||
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="/blog/#{blog_post.category_id.id}/#{blog_post.id}#comments"><t t-esc="len(blog_post.message_ids)"/> comments</a>
|
||||
<span t-if="len(blog_post.message_ids) > 0" class="icon-comment">
|
||||
<a t-attf-href="/blog/#{blog_post.id}/#comment">
|
||||
<t t-if="len(blog_post.message_ids) <= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t>
|
||||
<t t-if="len(blog_post.message_ids) > 1"><t t-esc="len(blog_post.message_ids)"/> comments</t>
|
||||
</a>
|
||||
</span>
|
||||
</p>
|
||||
<div t-field="blog_post.shortened_content" class="blog_content"/>
|
||||
|
@ -33,43 +47,56 @@
|
|||
</template>
|
||||
|
||||
<!-- Options: Blog Post Summary: hide author -->
|
||||
<template id="view_blog_post_short_author" inherit_option_id="website_blog.view_blog_post_short" name="Hide Authors">
|
||||
<template id="opt_blog_post_short_author" name="Hide Authors"
|
||||
inherit_option_id="website_blog.blog_post_short">
|
||||
<xpath expr="//span[@class='icon-user']" position="attributes">
|
||||
<attribute name="class">hidden</attribute>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post Summary: show category -->
|
||||
<template id="view_blog_post_short_category" inherit_option_id="website_blog.view_blog_post_short" name="Show Blog Name">
|
||||
<template id="opt_blog_post_short_category" name="Blog Name"
|
||||
inherit_option_id="website_blog.blog_post_short">
|
||||
<xpath expr="//span[@class='icon-user']" position="after">
|
||||
<span class="icon-folder-open"> In <span t-field="blog_post.category_id"/> &nbsp;</span>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Option: Blog Post Summary: show tags -->
|
||||
<template id="opt_blog_post_short_tags" name="Tags"
|
||||
inherit_option_id="website_blog.blog_post_short" inherit_id="website_blog.blog_post_short">
|
||||
<xpath expr="//p[@name='blog_post_data']" position="after">
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="icon-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="tag">
|
||||
<a t-attf-href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &nbsp;
|
||||
</t>
|
||||
</p>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Blog Post Complete -->
|
||||
<template id="view_blog_post" name="Blog Post">
|
||||
<template id="blog_post_complete" name="Blog Post">
|
||||
<div>
|
||||
<t t-call="website.publish_management">
|
||||
<t t-set="object" t-value="blog_post"/>
|
||||
<t t-set="publish_edit" t-value="True"/>
|
||||
<t t-set="publish_duplicate" t-value="'/blog/%s/duplicate' % (blog_post.id)"/>
|
||||
</t>
|
||||
</div><div class="clearfix"/>
|
||||
</div>
|
||||
<div class="clearfix"/>
|
||||
|
||||
<h1 class="text-center" t-field="blog_post.name"/>
|
||||
<p class="post-meta text-muted text-center">
|
||||
<p class="post-meta text-muted text-center" name="blog_post_data">
|
||||
<span class="icon-calendar"> <span t-field="blog_post.create_date"/></span> &nbsp;
|
||||
<span class="icon-user"> By <span t-field="blog_post.create_uid"/> &nbsp;</span>
|
||||
<span t-if="len(blog_post.message_ids) > 0" class="icon-comment"> With
|
||||
<a t-if="len(blog_post.message_ids) <= 1" t-attf-href="#comments"><t t-esc="len(blog_post.message_ids)"/> comment</a>
|
||||
<a t-if="len(blog_post.message_ids) > 1" t-attf-href="#comments"><t t-esc="len(blog_post.message_ids)"/> comments</a>
|
||||
<a t-attf-href="#comments">
|
||||
<t t-if="len(blog_post.message_ids) <= 1" ><t t-esc="len(blog_post.message_ids)"/> comment</t>
|
||||
<t t-if="len(blog_post.message_ids) > 1"><t t-esc="len(blog_post.message_ids)"/> comments</t>
|
||||
</a>
|
||||
</span>
|
||||
</p>
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="icon-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="tag">
|
||||
<a t-attf-href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &nbsp;
|
||||
</t>
|
||||
</p>
|
||||
|
||||
<div t-field="blog_post.content" class="mt16"/>
|
||||
<hr class="mb32"/>
|
||||
|
@ -102,78 +129,103 @@
|
|||
</template>
|
||||
|
||||
<!-- Options: Blog Post: user can reply -->
|
||||
<template id="view_blog_post_author" inherit_option_id="website_blog.view_blog_post" name="Hide Authors">
|
||||
<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.category_id.id}/#{blog_post.id}/post#post"
|
||||
method="POST">
|
||||
<img class="img pull-left img-rounded" t-att-src="'/website/image?model=res.partner&field=image_small&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>
|
||||
<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&field=image_small&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>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: hide author -->
|
||||
<template id="view_blog_post_author" inherit_option_id="website_blog.view_blog_post" name="Hide Authors">
|
||||
<template id="opt_blog_post_complete_author" name="Hide Authors"
|
||||
inherit_option_id="website_blog.blog_post_complete">
|
||||
<xpath expr="//span[@class='icon-user']" position="attributes">
|
||||
<attribute name="class">hidden</attribute>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: show category -->
|
||||
<template id="view_blog_post_show_category" inherit_option_id="website_blog.view_blog_post" name="Show Blog Name">
|
||||
<template id="opt_blog_post_complete_category" name="Blog Name"
|
||||
inherit_option_id="website_blog.blog_post_complete">
|
||||
<xpath expr="//span[@class='icon-user']" position="after">
|
||||
<span class="icon-folder-open"> In <span t-field="blog_post.category_id"/> &nbsp;</span>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Options: Blog Post: show tags -->
|
||||
<template id="opt_blog_post_complete_tags" name="Tags"
|
||||
inherit_option_id="website_blog.blog_post_complete" inherit_id="website_blog.blog_post_complete">
|
||||
<xpath expr="//p[@name='blog_post_data']" position="after">
|
||||
<p class="post-meta text-muted text-center" t-if="len(blog_post.tag_ids)">
|
||||
<span class="icon-tags"/>
|
||||
<t t-foreach="blog_post.tag_ids" t-as="tag">
|
||||
<a t-attf-href="/blog/tag/#{tag.id}" t-esc="tag.name"/> &nbsp;
|
||||
</t>
|
||||
</p>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Page -->
|
||||
<template id="index" name="Blogs" page="True">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="head">
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"></script>
|
||||
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
|
||||
</t>
|
||||
<t t-set="title">Blog</t>
|
||||
<div id="wrap">
|
||||
<div class="container mt16 js_website_blog">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-sm-9" t-if="not blog_post">
|
||||
<t t-foreach="blog_posts" t-as="blog_post" data-publish="">
|
||||
<t t-call="website_blog.view_blog_post_short"/>
|
||||
</t>
|
||||
<div class="pull-right" t-call="website.pager"/>
|
||||
</div>
|
||||
<div class="col-md-9 col-lg-8" t-if="blog_post">
|
||||
<t t-call="website_blog.view_blog_post">
|
||||
<t t-set="blog_post" t-value="blog_post"/>
|
||||
</t>
|
||||
<t t-set="head">
|
||||
<script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"></script>
|
||||
<link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
|
||||
</t>
|
||||
<t t-set="title">Blog</t>
|
||||
<div id="wrap">
|
||||
<div class="container mt16 js_website_blog">
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-sm-12" t-if="not blog_post" id="blog_post">
|
||||
<t t-if="category and editable">
|
||||
<div class="row">
|
||||
<a t-attf-href="/blog/#{category.id}/new" class="btn btn-primary pull-right">New Blog Post</a>
|
||||
</div>
|
||||
</t>
|
||||
<t t-foreach="blog_posts" t-as="blog_post" data-publish="">
|
||||
<t t-call="website_blog.blog_post_short"/>
|
||||
</t>
|
||||
<div class="pull-right" t-call="website.pager"/>
|
||||
</div>
|
||||
<div class="col-lg-12 col-sm-12" t-if="blog_post" id="blog_posts_summary">
|
||||
<t t-call="website_blog.blog_post_complete">
|
||||
<t t-set="blog_post" t-value="blog_post"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- Option: right column -->
|
||||
<template id="blog_right_column" inherit_id="website_blog.index" inherit_option_id="website_blog.index" name="Right Column">
|
||||
<!-- Option: Blog: Right Column -->
|
||||
<template id="blog_right_column" name="Right Column"
|
||||
inherit_option_id="website_blog.index" inherit_id="website_blog.index">
|
||||
<xpath expr="//div[@class='row']" position="inside">
|
||||
<div class="col-sm-3 hidden-xs col-lg-offset-1 mb32" id="right_column">
|
||||
<t t-if="category and editable">
|
||||
<a t-attf-href="/blog/#{category.id}/new" class="btn btn-primary pull-right">New Blog Post</a>
|
||||
</t>
|
||||
<div class="clearfix mb48"/>
|
||||
<div class="col-lg-3 col-sm-3 hidden-xs col-lg-offset-1 mb32" id="right_column">
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='blog_post']" position="attributes">
|
||||
<attribute name="class">col-lg-8 col-sm-8</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='blog_posts_summary']" position="attributes">
|
||||
<attribute name="class">col-lg-8 col-sm-8</attribute>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Option: Right Column: archives -->
|
||||
<template id="blog_history" inherit_id="website_blog.blog_right_column" inherit_option_id="website_blog.blog_right_column" name="Archives">
|
||||
<template id="opt_blog_rc_history" name="Archives"
|
||||
inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column">
|
||||
<xpath expr="//div[@id='right_column']" position="inside">
|
||||
<section>
|
||||
<h4>Archives</h4>
|
||||
|
@ -195,7 +247,8 @@
|
|||
</template>
|
||||
|
||||
<!-- Option: Right Column: about us -->
|
||||
<template id="blog_aboutus" inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column" name="About" priority="4">
|
||||
<template id="opt_blog_rc_about_us" name="About Us" priority="4"
|
||||
inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column">
|
||||
<xpath expr="//div[@id='right_column']" position="inside">
|
||||
<section class="mb16">
|
||||
<h4>About us</h4>
|
||||
|
@ -211,7 +264,8 @@
|
|||
</template>
|
||||
|
||||
<!-- Option: Right Column: follow us -->
|
||||
<template id="blog_followus" inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column" name="Follow us" priority="2">
|
||||
<template id="opt_blog_rc_follow_us" name="Follow us" priority="2"
|
||||
inherit_option_id="website_blog.blog_right_column" inherit_id="website_blog.blog_right_column">
|
||||
<xpath expr="//div[@id='right_column']" position="inside">
|
||||
<section class="mb16">
|
||||
<h4>Follow us</h4>
|
||||
|
@ -239,8 +293,9 @@
|
|||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Option: Right Column: categories + category in blog post -->
|
||||
<template id="blog_categories" inherit_option_id="website_blog.blog_right_column" name="Other Blogs" priority="6">
|
||||
<!-- Option: Right Column: categories -->
|
||||
<template id="opt_blog_rc_categories" name="Other Blogs" priority="6"
|
||||
inherit_option_id="website_blog.blog_right_column">
|
||||
<xpath expr="//div[@id='right_column']" position="inside">
|
||||
<section class="mb16">
|
||||
<h4>Other Blogs</h4>
|
||||
|
@ -257,5 +312,5 @@
|
|||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<openerp>
|
||||
<data>
|
||||
<menuitem name="Knowledge" id="knowledge.menu_document"/>
|
||||
<menuitem name="Pages" id="menu_wiki" parent="knowledge.menu_document" sequence="20" />
|
||||
<menuitem name="Blog Posts" id="menu_wiki" parent="knowledge.menu_document" sequence="20" />
|
||||
|
||||
<!-- Category views -->
|
||||
<record model="ir.ui.view" id="view_blog_category_list">
|
||||
|
@ -23,7 +23,6 @@
|
|||
<group>
|
||||
<field name="name"/>
|
||||
<field name="description"/>
|
||||
<field name="template" widget="html"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
|
@ -60,14 +59,12 @@
|
|||
<group>
|
||||
<field name="category_id" string="Category"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="write_uid" groups="base.group_no_one" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/>
|
||||
<field name="write_date" groups="base.group_no_one"/>
|
||||
<field name="menu_id" groups="base.group_no_one"/>
|
||||
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
|
||||
<group string="Technical" groups="base.group_no_one">
|
||||
<field name="write_uid" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_document_user']}"/>
|
||||
<field name="write_date"/>
|
||||
<field name="menu_id"/>
|
||||
</group>
|
||||
<div class="oe_document_page">
|
||||
<field name="content" placeholder="e.g. Once upon a time..." widget="html"/>
|
||||
</div>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
|
||||
|
@ -107,7 +104,7 @@
|
|||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem id="menu_page" parent="menu_wiki" name="Pages" action="action_blog_post" sequence="10"/>
|
||||
<menuitem id="menu_page" parent="menu_wiki" name="Blog Posts" action="action_blog_post" sequence="10"/>
|
||||
|
||||
<record model="ir.actions.act_window" id="action_blog_category">
|
||||
<field name="name">Category</field>
|
|
@ -1 +0,0 @@
|
|||
import controllers
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
'name': 'Public References',
|
||||
'category': 'Website',
|
||||
'summary': 'Publish Customer References',
|
||||
'version': '1.0',
|
||||
'description': """
|
||||
OpenERP Blog
|
||||
============
|
||||
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['website_partner', 'sale', 'website_google_map'],
|
||||
'data': [
|
||||
'views/website_contract.xml',
|
||||
],
|
||||
'qweb': ['static/src/xml/*.xml'],
|
||||
'installable': True,
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import openerp
|
||||
from openerp.addons.web import http
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
import urllib
|
||||
|
||||
|
||||
class website_contract(http.Controller):
|
||||
|
||||
@website.route(['/references/', '/references/page/<int:page>/'], type='http', auth="public")
|
||||
def references(self, page=0, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
account_obj = request.registry['account.analytic.account']
|
||||
|
||||
# check contracts
|
||||
contract_ids = account_obj.search(request.cr, openerp.SUPERUSER_ID, [(1, "=", 1)])
|
||||
contracts = account_obj.browse(request.cr, openerp.SUPERUSER_ID,
|
||||
contract_ids, request.context)
|
||||
contract_project_ids = [contract.partner_id.id for contract in contracts
|
||||
if contract.partner_id]
|
||||
domain = ['|', ('id', "in", contract_project_ids), ('id', "child_of", contract_project_ids)]
|
||||
|
||||
if post.get('search'):
|
||||
domain += [
|
||||
'|',
|
||||
('name', 'ilike', "%%%s%%" % post.get("search")),
|
||||
('website_description', 'ilike', "%%%s%%" % post.get("search"))
|
||||
]
|
||||
if request.context['is_public_user']:
|
||||
domain = ['&'] + domain + [('website_published', '=', True)]
|
||||
|
||||
# public partner profile
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID,
|
||||
domain + [('website_published', '=', True)], context=request.context)
|
||||
google_map_partner_ids = ",".join([str(p) for p in partner_ids])
|
||||
|
||||
# group by country
|
||||
countries = partner_obj.read_group(
|
||||
request.cr, request.uid, domain, ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
country_count = partner_obj.search(
|
||||
request.cr, request.uid, domain, count=True, context=request.context)
|
||||
countries.insert(0, {
|
||||
'country_id_count': country_count,
|
||||
'country_id': ("all", _("All Countries"))
|
||||
})
|
||||
|
||||
if post.get("country", "all") != 'all':
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, request.uid,
|
||||
[
|
||||
('id', 'in', partner_ids),
|
||||
('country_id', '=', int(post.get('country')))
|
||||
], context=request.context)
|
||||
|
||||
step = 20
|
||||
pager = request.website.pager(url="/references/", total=len(partner_ids), page=page, step=step, scope=7, url_args=post)
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, [('id', 'in', partner_ids)],
|
||||
limit=step, offset=pager['offset'], context=request.context)
|
||||
partners = partner_obj.browse(request.cr, openerp.SUPERUSER_ID,
|
||||
partner_ids, request.context)
|
||||
values = {
|
||||
'countries': countries,
|
||||
'partner_ids': partners,
|
||||
'google_map_partner_ids': google_map_partner_ids,
|
||||
'pager': pager,
|
||||
'searches': post,
|
||||
'search_path': "?%s" % urllib.urlencode(post),
|
||||
}
|
||||
return request.website.render("website_contract.index", values)
|
||||
|
||||
@website.route(['/references/<int:partner_id>/'], type='http', auth="public")
|
||||
def references_ref(self, partner_id=None, **post):
|
||||
""" Route for displaying a single partner.
|
||||
|
||||
:param integer partner_id: partner to display. If not set or not valid
|
||||
call basic references method.
|
||||
"""
|
||||
partner_obj = request.registry['res.partner']
|
||||
if request.context['is_public_user']:
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, [
|
||||
('website_published', '=', True),
|
||||
('id', '=', partner_id)
|
||||
], context=request.context)
|
||||
partner_id = partner_ids and partner_ids[0] or None
|
||||
|
||||
if not partner_id:
|
||||
return self.references(post=post)
|
||||
|
||||
values = {
|
||||
'partner_id': partner_obj.browse(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_id,
|
||||
dict(request.context, show_address=True)),
|
||||
}
|
||||
|
||||
return request.website.render("website_contract.details", values)
|
|
@ -1,12 +1,11 @@
|
|||
{
|
||||
'name': 'Public Partners References',
|
||||
'name': 'Publish Partner Assignment',
|
||||
'category': 'Website',
|
||||
'summary': 'Publish Customer References',
|
||||
'summary': 'Publish and Assign Partner',
|
||||
'version': '1.0',
|
||||
'description': """
|
||||
OpenERP Public Partners References
|
||||
==================================
|
||||
|
||||
Publish and Assign Partner
|
||||
==========================
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['website_partner', 'website_google_map'],
|
||||
|
|
|
@ -1,82 +1,88 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import urllib
|
||||
|
||||
import openerp
|
||||
from openerp.addons.web import http
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.web.http import request
|
||||
from openerp.addons.website.models import website
|
||||
import urllib
|
||||
|
||||
class website_crm_partner_assign(http.Controller):
|
||||
|
||||
@website.route(['/partners/', '/partners/page/<int:page>/'], type='http', auth="public", multilang=True)
|
||||
def partners(self, page=0, **post):
|
||||
class WebsiteCrmPartnerAssign(http.Controller):
|
||||
_references_per_page = 20
|
||||
|
||||
@website.route([
|
||||
'/partners/', '/partners/page/<int:page>/',
|
||||
'/partners/country/<int:country_id>', '/partners/country/page/<int:country_id>/',
|
||||
], type='http', auth="public", multilang=True)
|
||||
def partners(self, country_id=0, page=0, **post):
|
||||
country_obj = request.registry['res.country']
|
||||
partner_obj = request.registry['res.partner']
|
||||
post_name = post.get('search', '')
|
||||
grade_id = post.get('grade', '')
|
||||
country = None
|
||||
|
||||
def dom_without(without):
|
||||
domain = [('grade_id', '!=', False)]
|
||||
domain += openerp.SUPERUSER_ID != request.uid and [('website_published', '=', True)] or [(1, "=", 1)]
|
||||
for key, search in domain_search.items():
|
||||
if key != without:
|
||||
domain += search
|
||||
return domain
|
||||
# format displayed membership lines domain
|
||||
base_partner_domain = [('is_company', '=', True)]
|
||||
if request.context['is_public_user']:
|
||||
base_partner_domain += [('website_published', '=', True)]
|
||||
partner_domain = list(base_partner_domain)
|
||||
if grade_id:
|
||||
partner_domain += [('grade_id', '=', int(grade_id))] # try/catch int
|
||||
if country_id:
|
||||
country = country_obj.browse(request.cr, request.uid, country_id, request.context)
|
||||
partner_domain += [('country_id', '=', country_id)]
|
||||
if post_name:
|
||||
partner_domain += ['|', ('name', 'ilike', "%%%s%%" % post_name), ('website_description', 'ilike', "%%%s%%" % post_name)]
|
||||
|
||||
# search domains
|
||||
domain_search = {}
|
||||
if post.get('search'):
|
||||
domain_search["search"] += ['|',
|
||||
('name', 'ilike', "%%%s%%" % post.get("search")),
|
||||
('website_description', 'ilike', "%%%s%%" % post.get("search"))]
|
||||
if post.get("grade", "all") != 'all':
|
||||
domain_search["grade"] = [("grade_id", "=", int(post.get("grade")))]
|
||||
if post.get("country", "all") != 'all':
|
||||
domain_search["country"] = [("country_id", "=", int(post.get("country")))]
|
||||
|
||||
# public partner profile
|
||||
# format pager
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, dom_without(False),
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain,
|
||||
context=request.context)
|
||||
pager = request.website.pager(url="/partners/", total=len(partner_ids), page=page, step=self._references_per_page, scope=7, url_args=post)
|
||||
|
||||
# search for partners to display
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_domain,
|
||||
context=request.context,
|
||||
limit=self._references_per_page, offset=pager['offset'],
|
||||
order="grade_id ASC,partner_weight DESC")
|
||||
google_map_partner_ids = ",".join([str(p) for p in partner_ids])
|
||||
partners = partner_obj.browse(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_ids, request.context)
|
||||
|
||||
# group by country
|
||||
domain = dom_without("country")
|
||||
countries = partner_obj.read_group(
|
||||
request.cr, request.uid, domain, ["id", "country_id"],
|
||||
request.cr, request.uid, base_partner_domain, ["id", "country_id"],
|
||||
groupby="country_id", orderby="country_id", context=request.context)
|
||||
|
||||
partners = partner_obj.search(request.cr, request.uid, domain,
|
||||
context=request.context, count=True)
|
||||
countries_partners = partner_obj.search(
|
||||
request.cr, request.uid, base_partner_domain,
|
||||
context=request.context, count=True)
|
||||
countries.insert(0, {
|
||||
'country_id_count': partners,
|
||||
'country_id': ("all", _("All Countries"))
|
||||
'country_id_count': countries_partners,
|
||||
'country_id': (0, _("All Countries"))
|
||||
})
|
||||
|
||||
# group by grade
|
||||
domain = dom_without("grade")
|
||||
grades = partner_obj.read_group(
|
||||
request.cr, request.uid, domain, ["id", "grade_id"],
|
||||
request.cr, request.uid, base_partner_domain, ["id", "grade_id"],
|
||||
groupby="grade_id", orderby="grade_id", context=request.context)
|
||||
|
||||
grade_id_count = partner_obj.search(request.cr, request.uid, domain,
|
||||
count=True, context=request.context)
|
||||
grades_partners = partner_obj.search(
|
||||
request.cr, request.uid, base_partner_domain,
|
||||
context=request.context, count=True)
|
||||
grades.insert(0, {
|
||||
'grade_id_count': grade_id_count,
|
||||
'grade_id': ("all", _("All Grade"))
|
||||
'grade_id_count': grades_partners,
|
||||
'grade_id': ("all", _("All Grades"))
|
||||
})
|
||||
|
||||
step = 20
|
||||
pager = request.website.pager(url="/partners/", total=len(partner_ids), page=page, step=step, scope=7, url_args=post)
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID, [('id', 'in', partner_ids)],
|
||||
context=request.context, limit=step, offset=pager['offset'],
|
||||
order="grade_id ASC,partner_weight DESC")
|
||||
partners = partner_obj.browse(request.cr, openerp.SUPERUSER_ID,
|
||||
partner_ids, request.context)
|
||||
|
||||
values = {
|
||||
'countries': countries,
|
||||
'current_country_id': country_id,
|
||||
'current_country': country,
|
||||
'grades': grades,
|
||||
'partner_ids': partners,
|
||||
'grade_id': grade_id,
|
||||
'partners': partners,
|
||||
'google_map_partner_ids': google_map_partner_ids,
|
||||
'pager': pager,
|
||||
'searches': post,
|
||||
|
@ -84,23 +90,19 @@ class website_crm_partner_assign(http.Controller):
|
|||
}
|
||||
return request.website.render("website_crm_partner_assign.index", values)
|
||||
|
||||
@website.route(['/partners/<int:ref_id>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, ref_id=0, **post):
|
||||
@website.route(['/partners/<int:partner_id>/'], type='http', auth="public", multilang=True)
|
||||
def partners_ref(self, partner_id=0, **post):
|
||||
partner_obj = request.registry['res.partner']
|
||||
partner_ids = partner_obj.search(
|
||||
request.cr, openerp.SUPERUSER_ID,
|
||||
[('website_published', '=', True), ('id', '=', ref_id)],
|
||||
context=request.context)
|
||||
|
||||
if not request.context['is_public_user']:
|
||||
partner_ids += partner_obj.search(
|
||||
request.cr, request.uid, [('id', '=', ref_id)],
|
||||
context=request.context)
|
||||
if request.context['is_public_user']:
|
||||
partner_ids = partner_obj.search(request.cr, openerp.SUPERUSER_ID, [('website_pushished', '=', True), ('id', '=', partner_id)], context=request.context)
|
||||
else:
|
||||
partner_ids = partner_obj.search(request.cr, request.uid, [('id', '=', partner_id)], context=request.context)
|
||||
if not partner_ids:
|
||||
return self.members(post)
|
||||
|
||||
values = {
|
||||
'partner_id': partner_obj.browse(
|
||||
request.cr, openerp.SUPERUSER_ID, partner_ids[0],
|
||||
context=dict(request.context, show_address=True)),
|
||||
}
|
||||
|
||||
return request.website.render("website_crm_partner_assign.details", values)
|
||||
return request.website.render("website_crm_partner_assign.partner", values)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
|
||||
<!-- 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 t-href="/partners/">Partners</a></li>
|
||||
|
@ -12,29 +11,42 @@
|
|||
</template>
|
||||
|
||||
<!-- Page -->
|
||||
|
||||
<template id="layout" name="Partners Layout">
|
||||
<t t-call="website.layout">
|
||||
<t t-set="title">Partners</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure"/>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<t t-raw="ref_content" />
|
||||
<t t-set="title">Partners</t>
|
||||
<div id="wrap">
|
||||
<div class="oe_structure"/>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<t t-raw="ref_content" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<template id="index" name="Partners">
|
||||
<template id="index" name="Find Partners">
|
||||
<t t-call="website_crm_partner_assign.layout">
|
||||
<t t-set="ref_content">
|
||||
<h1 class="col-md-12 text-center">
|
||||
Want services on OpenERP?<br/>
|
||||
<small>Contact a local partner</small>
|
||||
</h1>
|
||||
<div class="col-md-12" id="ref_content">
|
||||
<div class="col-md-4" id="partner_left">
|
||||
<h3>Partners by Country</h3>
|
||||
<ul class="nav nav-pills nav-stacked mt16">
|
||||
<t t-foreach="countries" t-as="country_dict">
|
||||
<t t-if="country_dict['country_id']">
|
||||
<li t-att-class="country_dict['country_id'][0] == current_country_id and 'active' or ''">
|
||||
<a t-href="/partners/country/#{ country_dict['country_id'][0] }">
|
||||
<t t-esc="country_dict['country_id'][1]"/> <small>(<t t-esc="country_dict['country_id_count']"/>)</small>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-8" id="ref_content">
|
||||
<div class='navbar'>
|
||||
<div>
|
||||
<t t-call="website.pager">
|
||||
|
@ -42,26 +54,15 @@
|
|||
</t>
|
||||
<form t-action="/partners/" method="get" class="navbar-search pull-right pagination form-inline">
|
||||
<div class="form-group">
|
||||
<input type="text" name="search" class="search-query col-md-2 mt4 form-control" placeholder="Search" t-att-value="searches.get('search') or '' or ''"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select class="search-query col-md-2 mt4 form-control" name="country" t-if="len(countries) > 1" onchange="submit()">
|
||||
<t t-foreach="countries">
|
||||
<t t-if="country_id">
|
||||
<option t-att-selected="searches.get('country') == str(country_id and country_id[0]) and 'selected'" t-att-value="country_id[0]">
|
||||
<t t-esc="country_id[1]"/> (<t t-esc="country_id_count"/>)
|
||||
</option>
|
||||
</t>
|
||||
</t>
|
||||
</select>
|
||||
<input type="text" name="search" class="search-query col-md-2 mt4 form-control" placeholder="Search" t-att-value="name_search"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<select class="search-query col-md-2 mt4 form-control" name="grade" t-if="len(grades) > 1" onchange="submit()">
|
||||
<t t-foreach="grades">
|
||||
<t t-if="grade_id">
|
||||
<option t-att-selected="searches.get('grade') == str(grade_id and grade_id[0]) and 'selected'" t-att-value="grade_id[0]">
|
||||
<t t-esc="grade_id[1]"/> (<t t-esc="grade_id_count"/>)
|
||||
</option>
|
||||
<option t-att-selected="searches.get('grade') == str(grade_id and grade_id[0]) and 'selected'" t-att-value="grade_id[0]">
|
||||
<t t-esc="grade_id[1]"/> (<t t-esc="grade_id_count"/>)
|
||||
</option>
|
||||
</t>
|
||||
</t>
|
||||
</select>
|
||||
|
@ -70,19 +71,22 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<t t-foreach="partner_ids" t-as="partner">
|
||||
<t t-if="grade_id != partner.grade_id.id">
|
||||
<t t-set="grade_id" t-value="partner.grade_id.id"/>
|
||||
<h3 class="text-center well"><span t-field="partner.grade_id"/> Partners</h3>
|
||||
<t t-foreach="partners" t-as="partner_id">
|
||||
<t t-if="internal_gid != partner_id.grade_id.id">
|
||||
<t t-set="internal_gid" t-value="partner_id.grade_id.id"/>
|
||||
<h3 class="text-center">
|
||||
<span t-field="partner_id.grade_id"/> Partners
|
||||
<t t-if="current_country"> in <t t-esc="current_country.name"/></t>
|
||||
</h3>
|
||||
</t>
|
||||
<div class="media thumbnail" data-publish="">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner"/></t>
|
||||
<a class="pull-left" t-href="/partners/#{ partner.id }/">
|
||||
<img class="media-object" t-att-src="partner.img('image_small')"/>
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
|
||||
<a class="pull-left" t-href="/partners/#{ partner_id.id }/">
|
||||
<img class="media-object" t-att-src="partner_id.img('image_small')"/>
|
||||
</a>
|
||||
<div class="media-body" style="min-height: 64px;">
|
||||
<a class="media-heading" t-href="/partners/#{ partner.id }/"><span t-field="partner.parent_id"/> <span t-field="partner.name"/></a> - <span t-field="partner.grade_id"/>
|
||||
<div t-field="partner.website_short_description"/>
|
||||
<a class="media-heading" t-href="/partners/#{ partner_id.id }/"><span t-field="partner_id.parent_id"/> <span t-field="partner_id.name"/></a> - <span t-field="partner_id.grade_id"/>
|
||||
<div t-field="partner_id.website_short_description"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
@ -93,48 +97,19 @@
|
|||
</template>
|
||||
|
||||
<template id="ref_country" inherit_id="website_crm_partner_assign.index" inherit_option_id="website_crm_partner_assign.index" name="Left World Map">
|
||||
<xpath expr="//div[@id='ref_content']" position="before">
|
||||
<div class="col-md-4">
|
||||
<ul class="nav">
|
||||
<li class="navbar-header">World Map</li>
|
||||
<iframe t-attf-src="/google_map/?width=320&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/partners/"
|
||||
style="width:320px; height:260px; border:0; padding:0; margin:0;"></iframe>
|
||||
</ul>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//div[@id='ref_content']" position="attributes">
|
||||
<attribute name="class">col-md-8</attribute>
|
||||
<xpath expr="//div[@id='partner_left']//ul" position="after">
|
||||
<h3>World Map</h3>
|
||||
<ul class="nav">
|
||||
<iframe t-attf-src="/google_map/?width=320&height=240&partner_ids=#{ google_map_partner_ids }&partner_url=/partners/"
|
||||
style="width:320px; height:260px; border:0; padding:0; margin:0;"></iframe>
|
||||
</ul>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="details" name="Partner Detail">
|
||||
<template id="partner" name="Partner Detail">
|
||||
<t t-call="website_crm_partner_assign.layout">
|
||||
<t t-set="ref_content">
|
||||
<t t-call="website.publish_management"><t t-set="object" t-value="partner_id"/></t>
|
||||
<h1 class="col-md-12 text-center" t-field="partner_id.name"/>
|
||||
<div class="col-md-4">
|
||||
<div class="text-center">
|
||||
<img t-att-src="partner_id.img('image_medium')"/>
|
||||
</div>
|
||||
<address>
|
||||
<table style="margin: auto;" class="well">
|
||||
<colgroup>
|
||||
<col width="100"/>
|
||||
<col/>
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<t t-set="address" t-value="'<br/>'.join(partner_id.name_get()[0][1].split('\n')[1:])"/>
|
||||
<tr t-if="address or editable"><th>Address</th><td class="span2" t-raw="address"/></tr>
|
||||
<tr t-if="partner_id.website or editable"><th>Website</th><td class="span2" t-field="partner_id.website"/></tr>
|
||||
<tr t-if="partner_id.phone or editable"><th>Tel</th><td class="span2" t-field="partner_id.phone"/></tr>
|
||||
<tr t-if="partner_id.mobile or editable"><th>Tel</th><td class="span2" t-field="partner_id.mobile"/></tr>
|
||||
<tr t-if="partner_id.fax or editable"><th>Fax</th><td class="span2" t-field="partner_id.fax"/></tr>
|
||||
<tr t-if="partner_id.email or editable"><th>Email</th><td class="span2" t-field="partner_id.email"/></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</address>
|
||||
</div>
|
||||
<div class="col-md-8 mt32" t-field="partner_id.website_description"/>
|
||||
<t t-call="website_partner.partner_detail"/>
|
||||
</t>
|
||||
</t>
|
||||
</template>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue