[MERGE] from trunk
bzr revid: fva@openerp.com-20140428152938-ib1yl6f7lgat51vm
This commit is contained in:
commit
1aaed44874
|
@ -642,7 +642,7 @@ class account_move_line(osv.osv):
|
||||||
(_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']),
|
(_check_date, 'The date of your Journal Entry is not in the defined period! You should change the date or remove this constraint from the journal.', ['date']),
|
||||||
(_check_currency, 'The selected account of your Journal Entry forces to provide a secondary currency. You should remove the secondary currency on the account or select a multi-currency view on the journal.', ['currency_id']),
|
(_check_currency, 'The selected account of your Journal Entry forces to provide a secondary currency. You should remove the secondary currency on the account or select a multi-currency view on the journal.', ['currency_id']),
|
||||||
(_check_currency_and_amount, "You cannot create journal items with a secondary currency without recording both 'currency' and 'amount currency' field.", ['currency_id','amount_currency']),
|
(_check_currency_and_amount, "You cannot create journal items with a secondary currency without recording both 'currency' and 'amount currency' field.", ['currency_id','amount_currency']),
|
||||||
(_check_currency_amount, 'The amount expressed in the secondary currency must be positive when the journal item is a debit and negative when if it is a credit.', ['amount_currency']),
|
(_check_currency_amount, 'The amount expressed in the secondary currency must be positive when account is debited and negative when account is credited.', ['amount_currency']),
|
||||||
(_check_currency_company, "You cannot provide a secondary currency if it is the same than the company one." , ['currency_id']),
|
(_check_currency_company, "You cannot provide a secondary currency if it is the same than the company one." , ['currency_id']),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -384,6 +384,7 @@
|
||||||
<group expand="0" string="Group By...">
|
<group expand="0" string="Group By...">
|
||||||
<filter string="User" context="{'group_by':'user_id'}" icon="terp-personal"/>
|
<filter string="User" context="{'group_by':'user_id'}" icon="terp-personal"/>
|
||||||
<filter string="Type" context="{'group_by':'type'}" icon="terp-stock_symbol-selection"/>
|
<filter string="Type" context="{'group_by':'type'}" icon="terp-stock_symbol-selection"/>
|
||||||
|
<filter string="Company" context="{'group_by':'company_id'}" icon="terp-go-home" groups="base.group_multi_company"/>
|
||||||
</group>
|
</group>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
|
@ -881,6 +882,7 @@
|
||||||
<field name="price_include"/>
|
<field name="price_include"/>
|
||||||
<field name="description"/>
|
<field name="description"/>
|
||||||
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
<field name="company_id" widget="selection" groups="base.group_multi_company"/>
|
||||||
|
<field name="type_tax_use" invisible="1"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
@ -891,6 +893,12 @@
|
||||||
<search string="Search Taxes">
|
<search string="Search Taxes">
|
||||||
<field name="name" filter_domain="['|', ('name','ilike',self), ('description','ilike',self)]" string="Tax"/>
|
<field name="name" filter_domain="['|', ('name','ilike',self), ('description','ilike',self)]" string="Tax"/>
|
||||||
<field name="company_id" groups="base.group_multi_company"/>
|
<field name="company_id" groups="base.group_multi_company"/>
|
||||||
|
<filter string="Sale" domain="[('type_tax_use','=','sale')]" />
|
||||||
|
<filter string="Purchase" domain="[('type_tax_use','=','purchase')]" />
|
||||||
|
<group string="Group By...">
|
||||||
|
<filter string="Company" domain="[]" context="{'group_by':'company_id'}"/>
|
||||||
|
<filter string="Tax Application" domain="[]" context="{'group_by':'type_tax_use'}"/>
|
||||||
|
</group>
|
||||||
</search>
|
</search>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<page name="sales_purchases" position="after" version="7.0">
|
<page name="sales_purchases" position="after" version="7.0">
|
||||||
<page string="Accounting" col="4" name="accounting" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}">
|
<page string="Accounting" col="4" name="accounting" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}" groups="account.group_account_invoice">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="property_account_position" widget="selection"/>
|
<field name="property_account_position" widget="selection"/>
|
||||||
|
@ -127,7 +127,7 @@
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
<page string="Accounting" name="accounting_disabled" attrs="{'invisible': ['|',('is_company','=',True),('parent_id','=',False)]}">
|
<page string="Accounting" name="accounting_disabled" attrs="{'invisible': ['|',('is_company','=',True),('parent_id','=',False)]}" groups="account.group_account_invoice">
|
||||||
<div>
|
<div>
|
||||||
<p>Accounting-related settings are managed on <button name="open_commercial_entity" type="object" string="the parent company" class="oe_link"/></p>
|
<p>Accounting-related settings are managed on <button name="open_commercial_entity" type="object" string="the parent company" class="oe_link"/></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -259,6 +259,12 @@ class account_config_settings(osv.osv_memory):
|
||||||
def onchange_tax_rate(self, cr, uid, ids, rate, context=None):
|
def onchange_tax_rate(self, cr, uid, ids, rate, context=None):
|
||||||
return {'value': {'purchase_tax_rate': rate or False}}
|
return {'value': {'purchase_tax_rate': rate or False}}
|
||||||
|
|
||||||
|
def onchange_multi_currency(self, cr, uid, ids, group_multi_currency, context=None):
|
||||||
|
res = {}
|
||||||
|
if not group_multi_currency:
|
||||||
|
res['value'] = {'income_currency_exchange_account_id': False, 'expense_currency_exchange_account_id': False}
|
||||||
|
return res
|
||||||
|
|
||||||
def onchange_start_date(self, cr, uid, id, start_date):
|
def onchange_start_date(self, cr, uid, id, start_date):
|
||||||
if start_date:
|
if start_date:
|
||||||
start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d")
|
start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d")
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
<label for="id" string="Features"/>
|
<label for="id" string="Features"/>
|
||||||
<div>
|
<div>
|
||||||
<div name="group_multi_currency">
|
<div name="group_multi_currency">
|
||||||
<field name="group_multi_currency" class="oe_inline"/>
|
<field name="group_multi_currency" class="oe_inline" on_change="onchange_multi_currency(group_multi_currency)"/>
|
||||||
<label for="group_multi_currency"/>
|
<label for="group_multi_currency"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -189,7 +189,7 @@ class account_voucher(osv.osv):
|
||||||
if not ids:
|
if not ids:
|
||||||
return []
|
return []
|
||||||
if context is None: context = {}
|
if context is None: context = {}
|
||||||
return [(r['id'], (str("%.2f" % r['amount']) or '')) for r in self.read(cr, uid, ids, ['amount'], context, load='_classic_write')]
|
return [(r['id'], (r['number'] or _('Voucher'))) for r in self.read(cr, uid, ids, ['number'], context, load='_classic_write')]
|
||||||
|
|
||||||
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
|
def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False):
|
||||||
mod_obj = self.pool.get('ir.model.data')
|
mod_obj = self.pool.get('ir.model.data')
|
||||||
|
|
|
@ -259,7 +259,7 @@
|
||||||
<!-- Short thread: Admin ask, Agrolait answer [DEMO: mark thread as done] -->
|
<!-- Short thread: Admin ask, Agrolait answer [DEMO: mark thread as done] -->
|
||||||
<record id="msg_discus1" model="mail.message">
|
<record id="msg_discus1" model="mail.message">
|
||||||
<field name="subject">Feedback about our On Site Assistance</field>
|
<field name="subject">Feedback about our On Site Assistance</field>
|
||||||
<field name="body"><![CDATA[<p>Hi Virginie,</p><p>I writing to you about our <i>On Site Assistance Service</i> that we delivered to Agrolait last week. Do you have any feedback or remark about our service? I noticed you requested new IP phones. Will it be used for new employees, or did you have any issue with the ones we provided?<br />Best regards,</p>]]></field>
|
<field name="body"><![CDATA[<p>Hi Virginie,</p><p>I wrote to you about our <i>On Site Assistance Service</i> that we delivered to Agrolait last week. Do you have any feedback or remark about our service? I noticed you requested new IP phones. Will it be used for new employees, or did you have any issue with the ones we provided?<br />Best regards,</p>]]></field>
|
||||||
<field name="type">comment</field>
|
<field name="type">comment</field>
|
||||||
<field name="subtype_id" ref="mt_comment"/>
|
<field name="subtype_id" ref="mt_comment"/>
|
||||||
<field name="author_id" ref="base.partner_root"/>
|
<field name="author_id" ref="base.partner_root"/>
|
||||||
|
|
|
@ -49,17 +49,11 @@
|
||||||
<field name="name">Members Analysis</field>
|
<field name="name">Members Analysis</field>
|
||||||
<field name="res_model">report.membership</field>
|
<field name="res_model">report.membership</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
|
<field name="view_mode">graph</field>
|
||||||
<field name="search_view_id" ref="view_report_membership_search"/>
|
<field name="search_view_id" ref="view_report_membership_search"/>
|
||||||
<field name="context">{"search_default_year":1,"search_default_member":1, 'search_default_Revenue':1, 'search_default_this_month':1, 'search_default_salesman':1,'group_by_no_leaf':1}</field>
|
<field name="context">{"search_default_year":1,"search_default_member":1, 'search_default_Revenue':1, 'search_default_this_month':1, 'search_default_salesman':1,'group_by_no_leaf':1}</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record model="ir.actions.act_window.view" id="action_report_membership_tree_view2">
|
|
||||||
<field name="sequence" eval="3"/>
|
|
||||||
<field name="view_mode">graph</field>
|
|
||||||
<field name="view_id" ref="view_report_membership_graph1"/>
|
|
||||||
<field name="act_window_id" ref="action_report_membership_tree"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<menuitem name="Members Analysis" parent="base.menu_report_association"
|
<menuitem name="Members Analysis" parent="base.menu_report_association"
|
||||||
action="action_report_membership_tree"
|
action="action_report_membership_tree"
|
||||||
id="menu_report_membership"
|
id="menu_report_membership"
|
||||||
|
|
|
@ -9,20 +9,6 @@
|
||||||
|
|
||||||
<!-- Report for Users' Timesheet and Task Hours per Month -->
|
<!-- Report for Users' Timesheet and Task Hours per Month -->
|
||||||
|
|
||||||
<record id="view_report_timesheet_task_user_tree" model="ir.ui.view">
|
|
||||||
<field name="name">report.timesheet.task.user.tree</field>
|
|
||||||
<field name="model">report.timesheet.task.user</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<tree string="Timesheet/Task hours Report Per Month" >
|
|
||||||
<field name="name"/>
|
|
||||||
<field name="year" invisible="1"/>
|
|
||||||
<field name="month" invisible="1"/>
|
|
||||||
<field name="user_id"/>
|
|
||||||
<field name="timesheet_hrs" widget="float_time" />
|
|
||||||
<field name="task_hrs" widget="float_time"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
<record id="view_report_timesheet_task_user_search" model="ir.ui.view">
|
<record id="view_report_timesheet_task_user_search" model="ir.ui.view">
|
||||||
<field name="name">report.timesheet.task.user.search</field>
|
<field name="name">report.timesheet.task.user.search</field>
|
||||||
<field name="model">report.timesheet.task.user</field>
|
<field name="model">report.timesheet.task.user</field>
|
||||||
|
@ -55,7 +41,7 @@
|
||||||
<field name="name">Task Hours Per Month</field>
|
<field name="name">Task Hours Per Month</field>
|
||||||
<field name="res_model">report.timesheet.task.user</field>
|
<field name="res_model">report.timesheet.task.user</field>
|
||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,graph</field>
|
<field name="view_mode">graph</field>
|
||||||
<field name="context">{'search_default_year':1,'search_default_month':1, 'search_default_group_user_id':1}</field>
|
<field name="context">{'search_default_year':1,'search_default_month':1, 'search_default_group_user_id':1}</field>
|
||||||
</record>
|
</record>
|
||||||
<menuitem id="menu_timesheet_task_user" parent="hr.menu_hr_reporting_timesheet"
|
<menuitem id="menu_timesheet_task_user" parent="hr.menu_hr_reporting_timesheet"
|
||||||
|
|
|
@ -2506,7 +2506,7 @@ class stock_move(osv.osv):
|
||||||
source_location = move.location_dest_id
|
source_location = move.location_dest_id
|
||||||
if source_location.usage != 'internal':
|
if source_location.usage != 'internal':
|
||||||
#restrict to scrap from a virtual location because it's meaningless and it may introduce errors in stock ('creating' new products from nowhere)
|
#restrict to scrap from a virtual location because it's meaningless and it may introduce errors in stock ('creating' new products from nowhere)
|
||||||
raise osv.except_osv(_('Error!'), _('Forbidden operation: it is not allowed to scrap products from a virtual location.'))
|
raise osv.except_osv(_('Error!'), _('Operation Forbidden! it is not allowed to scrap products from a virtual location: %s' %(move.location_id.complete_name)))
|
||||||
move_qty = move.product_qty
|
move_qty = move.product_qty
|
||||||
uos_qty = quantity / move_qty * move.product_uos_qty
|
uos_qty = quantity / move_qty * move.product_uos_qty
|
||||||
default_val = {
|
default_val = {
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
.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;
|
|
||||||
}
|
|
|
@ -1,559 +0,0 @@
|
||||||
/* ===========================================================
|
|
||||||
# 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);
|
|
|
@ -518,10 +518,30 @@ div.tour-backdrop {
|
||||||
z-index: 2009;
|
z-index: 2009;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover.tour {
|
.popover.tour.orphan .arrow {
|
||||||
z-index: 2010;
|
display: none;
|
||||||
|
}
|
||||||
|
.popover.tour .popover-navigation {
|
||||||
|
padding: 9px 14px;
|
||||||
|
}
|
||||||
|
.popover.tour .popover-navigation *[data-role="end"] {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
.popover.tour .popover-navigation *[data-role="next"], .popover.tour .popover-navigation *[data-role="end"] {
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover.fixed {
|
.popover.fixed {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tour-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1100;
|
||||||
|
background-color: black;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
|
@ -451,9 +451,26 @@ $editorbar_height: 30px
|
||||||
div.tour-backdrop
|
div.tour-backdrop
|
||||||
z-index: 2009
|
z-index: 2009
|
||||||
.popover.tour
|
.popover.tour
|
||||||
z-index: 2010
|
&.orphan .arrow
|
||||||
|
display: none
|
||||||
|
.popover-navigation
|
||||||
|
padding: 9px 14px
|
||||||
|
*[data-role="end"]
|
||||||
|
float: right
|
||||||
|
*[data-role="next"],*[data-role="end"]
|
||||||
|
cursor: pointer
|
||||||
.popover.fixed
|
.popover.fixed
|
||||||
position: fixed
|
position: fixed
|
||||||
|
.tour-backdrop
|
||||||
|
position: fixed
|
||||||
|
top: 0
|
||||||
|
right: 0
|
||||||
|
bottom: 0
|
||||||
|
left: 0
|
||||||
|
z-index: 1100
|
||||||
|
background-color: #000
|
||||||
|
opacity: 0.8
|
||||||
|
|
||||||
|
|
||||||
// }}}
|
// }}}
|
||||||
|
|
||||||
|
|
|
@ -545,7 +545,7 @@
|
||||||
|
|
||||||
observer.disconnect();
|
observer.disconnect();
|
||||||
var editor = this.rte.editor;
|
var editor = this.rte.editor;
|
||||||
var root = editor.element.$;
|
var root = editor.element && editor.element.$;
|
||||||
editor.destroy();
|
editor.destroy();
|
||||||
// FIXME: select editables then filter by dirty?
|
// FIXME: select editables then filter by dirty?
|
||||||
var defs = this.rte.fetch_editables(root)
|
var defs = this.rte.fetch_editables(root)
|
||||||
|
|
|
@ -362,7 +362,6 @@
|
||||||
},
|
},
|
||||||
clean_for_save: function () {
|
clean_for_save: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
$("*[contentEditable], *[attributeEditable]")
|
$("*[contentEditable], *[attributeEditable]")
|
||||||
.removeAttr('contentEditable')
|
.removeAttr('contentEditable')
|
||||||
.removeAttr('attributeEditable');
|
.removeAttr('attributeEditable');
|
||||||
|
|
|
@ -4,127 +4,116 @@
|
||||||
var website = openerp.website;
|
var website = openerp.website;
|
||||||
var _t = openerp._t;
|
var _t = openerp._t;
|
||||||
|
|
||||||
website.EditorBar.include({
|
website.Tour.register({
|
||||||
start: function () {
|
|
||||||
this.registerTour(new website.Tour.Banner(this));
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
website.Tour.Banner = website.Tour.extend({
|
|
||||||
id: 'banner',
|
id: 'banner',
|
||||||
name: "Build a page",
|
name: _t("Build a page"),
|
||||||
path: '/page/website.homepage',
|
path: '/page/website.homepage',
|
||||||
init: function () {
|
steps: [
|
||||||
var self = this;
|
{
|
||||||
self.steps = [
|
title: _t("Welcome to your website!"),
|
||||||
{
|
content: _t("This tutorial will guide you to build your home page. We will start by adding a banner."),
|
||||||
title: _t("Welcome to your website!"),
|
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
||||||
content: _t("This tutorial will guide you to build your home page. We will start by adding a banner."),
|
},
|
||||||
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
{
|
||||||
},
|
waitNot: '.popover.tour',
|
||||||
{
|
element: 'button[data-action=edit]',
|
||||||
waitNot: '.popover.tour',
|
placement: 'bottom',
|
||||||
element: 'button[data-action=edit]',
|
title: _t("Edit this page"),
|
||||||
placement: 'bottom',
|
content: _t("Every page of your website can be modified through the <i>Edit</i> button."),
|
||||||
title: _t("Edit this page"),
|
popover: { fixed: true },
|
||||||
content: _t("Every page of your website can be modified through the <i>Edit</i> button."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
element: 'button[data-action=snippet]',
|
||||||
{
|
placement: 'bottom',
|
||||||
element: 'button[data-action=snippet]',
|
title: _t("Insert building blocks"),
|
||||||
placement: 'bottom',
|
content: _t("Click here to insert blocks of content in the page."),
|
||||||
title: _t("Insert building blocks"),
|
popover: { fixed: true },
|
||||||
content: _t("Click here to insert blocks of content in the page."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
snippet: '#snippet_structure .oe_snippet:first',
|
||||||
{
|
placement: 'bottom',
|
||||||
snippet: '#snippet_structure .oe_snippet:first',
|
title: _t("Drag & Drop a Banner"),
|
||||||
placement: 'bottom',
|
content: _t("Drag the Banner block and drop it in your page."),
|
||||||
title: _t("Drag & Drop a Banner"),
|
popover: { fixed: true },
|
||||||
content: _t("Drag the Banner block and drop it in your page."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
waitFor: '.oe_overlay_options .oe_options:visible',
|
||||||
{
|
element: '#wrap .carousel:first div.carousel-content',
|
||||||
waitFor: '.oe_overlay_options .oe_options:visible',
|
placement: 'top',
|
||||||
element: '#wrap .carousel:first div.carousel-content',
|
title: _t("Customize banner's text"),
|
||||||
placement: 'top',
|
content: _t("Click in the text and start editing it."),
|
||||||
title: _t("Customize banner's text"),
|
sampleText: 'Here, a customized text',
|
||||||
content: _t("Click in the text and start editing it."),
|
},
|
||||||
sampleText: 'Here, a customized text',
|
{
|
||||||
},
|
waitNot: '#wrap .carousel:first div.carousel-content:has(h2:'+
|
||||||
{
|
'containsExact('+_t('Your Banner Title')+')):has(h3:'+
|
||||||
waitNot: '#wrap .carousel:first div.carousel-content:has(h2:'+
|
'containsExact('+_t('Click to customize this text')+'))',
|
||||||
'containsExact('+_t('Your Banner Title')+')):has(h3:'+
|
element: '.oe_snippet_parent:visible',
|
||||||
'containsExact('+_t('Click to customize this text')+'))',
|
placement: 'bottom',
|
||||||
element: '.oe_snippet_parent:visible',
|
title: _t("Get banner properties"),
|
||||||
placement: 'bottom',
|
content: _t("Select the parent container to get the global options of the banner."),
|
||||||
title: _t("Get banner properties"),
|
popover: { fixed: true },
|
||||||
content: _t("Select the parent container to get the global options of the banner."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
element: '.oe_overlay_options .oe_options:visible',
|
||||||
{
|
placement: 'left',
|
||||||
element: '.oe_overlay_options .oe_options:visible',
|
title: _t("Customize the banner"),
|
||||||
placement: 'left',
|
content: _t("Customize any block through this menu. Try to change the background of the banner."),
|
||||||
title: _t("Customize the banner"),
|
popover: { next: _t("Continue") },
|
||||||
content: _t("Customize any block through this menu. Try to change the background of the banner."),
|
},
|
||||||
popover: { next: _t("Continue") },
|
{
|
||||||
},
|
waitNot: '.popover.tour',
|
||||||
{
|
element: 'button[data-action=snippet]',
|
||||||
waitNot: '.popover.tour',
|
placement: 'bottom',
|
||||||
element: 'button[data-action=snippet]',
|
title: _t("Add Another Block"),
|
||||||
placement: 'bottom',
|
content: _t("Let's add another building block to your page."),
|
||||||
title: _t("Add Another Block"),
|
popover: { fixed: true },
|
||||||
content: _t("Let's add another building block to your page."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
snippet: '#snippet_structure .oe_snippet:eq(6)',
|
||||||
{
|
placement: 'bottom',
|
||||||
snippet: '#snippet_structure .oe_snippet:eq(6)',
|
title: _t("Drag & Drop This Block"),
|
||||||
placement: 'bottom',
|
content: _t("Drag the <em>'Features'</em> block and drop it below the banner."),
|
||||||
title: _t("Drag & Drop This Block"),
|
popover: { fixed: true },
|
||||||
content: _t("Drag the <em>'Features'</em> block and drop it below the banner."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
waitFor: '.oe_overlay_options .oe_options:visible',
|
||||||
{
|
element: 'button[data-action=save]',
|
||||||
waitFor: '.oe_overlay_options .oe_options:visible',
|
placement: 'right',
|
||||||
element: 'button[data-action=save]',
|
title: _t("Save your modifications"),
|
||||||
placement: 'right',
|
content: _t("Publish your page by clicking on the <em>'Save'</em> button."),
|
||||||
title: _t("Save your modifications"),
|
popover: { fixed: true },
|
||||||
content: _t("Publish your page by clicking on the <em>'Save'</em> button."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
waitFor: 'button[data-action=edit]:visible',
|
||||||
{
|
title: _t("Good Job!"),
|
||||||
waitFor: 'button[data-action=edit]:visible',
|
content: _t("Well done, you created your homepage."),
|
||||||
title: _t("Good Job!"),
|
popover: { next: _t("Continue") },
|
||||||
content: _t("Well done, you created your homepage."),
|
},
|
||||||
popover: { next: _t("Continue") },
|
{
|
||||||
},
|
waitNot: '.popover.tour',
|
||||||
{
|
element: 'a[data-action=show-mobile-preview]',
|
||||||
waitNot: '.popover.tour',
|
placement: 'bottom',
|
||||||
element: 'a[data-action=show-mobile-preview]',
|
title: _t("Test Your Mobile Version"),
|
||||||
placement: 'bottom',
|
content: _t("Let's check how your homepage looks like on mobile devices."),
|
||||||
title: _t("Test Your Mobile Version"),
|
popover: { fixed: true },
|
||||||
content: _t("Let's check how your homepage looks like on mobile devices."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
element: '.modal:has(#mobile-viewport) button[data-dismiss=modal]',
|
||||||
{
|
placement: 'right',
|
||||||
element: '.modal:has(#mobile-viewport) button[data-dismiss=modal]',
|
title: _t("Check Mobile Preview"),
|
||||||
placement: 'right',
|
content: _t("Scroll to check rendering and then close the mobile preview."),
|
||||||
title: _t("Check Mobile Preview"),
|
popover: { next: _t("Continue") },
|
||||||
content: _t("Scroll to check rendering and then close the mobile preview."),
|
},
|
||||||
popover: { next: _t("Continue") },
|
{
|
||||||
},
|
waitNot: '.modal',
|
||||||
{
|
element: '#content-menu-button',
|
||||||
waitNot: '.modal',
|
placement: 'left',
|
||||||
element: '#content-menu-button',
|
title: _t("Add new pages and menus"),
|
||||||
placement: 'left',
|
content: _t("The 'Content' menu allows you to add pages or add the top menu."),
|
||||||
title: _t("Add new pages and menus"),
|
popover: { next: _t("Close Tutorial") },
|
||||||
content: _t("The 'Content' menu allows you to add pages or add the top menu."),
|
},
|
||||||
popover: { next: _t("Close Tutorial") },
|
]
|
||||||
},
|
|
||||||
];
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -6,7 +6,7 @@ if (typeof openerp === "undefined") {
|
||||||
var error = "openerp is undefined"
|
var error = "openerp is undefined"
|
||||||
+ "\nhref: " + window.location.href
|
+ "\nhref: " + window.location.href
|
||||||
+ "\nreferrer: " + document.referrer
|
+ "\nreferrer: " + document.referrer
|
||||||
+ "\nlocalStorage: " + JSON.stringify(window.localStorage);
|
+ "\nlocalStorage: " + window.localStorage.getItem("tour");
|
||||||
if (typeof $ !== "undefined") {
|
if (typeof $ !== "undefined") {
|
||||||
error += '\n\n' + $("body").html();
|
error += '\n\n' + $("body").html();
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ if (typeof openerp === "undefined") {
|
||||||
|
|
||||||
var website = window.openerp.website;
|
var website = window.openerp.website;
|
||||||
|
|
||||||
// don't rewrite website.Tour in test mode
|
// don't rewrite T in test mode
|
||||||
if (typeof website.Tour !== "undefined") {
|
if (typeof website.Tour !== "undefined") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -23,40 +23,26 @@ if (typeof website.Tour !== "undefined") {
|
||||||
// don't need template to use bootstrap Tour in automatic mode
|
// don't need template to use bootstrap Tour in automatic mode
|
||||||
if (typeof QWeb2 !== "undefined") {
|
if (typeof QWeb2 !== "undefined") {
|
||||||
website.add_template_file('/website/static/src/xml/website.tour.xml');
|
website.add_template_file('/website/static/src/xml/website.tour.xml');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't need to use bootstrap Tour to launch an automatic tour
|
|
||||||
function bootstrap_tour_stub () {
|
|
||||||
if (typeof Tour === "undefined") {
|
|
||||||
window.Tour = function Tour() {};
|
|
||||||
Tour.prototype.addSteps = function () {};
|
|
||||||
Tour.prototype.end = function () {};
|
|
||||||
Tour.prototype.goto = function () {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (website.EditorBar) {
|
if (website.EditorBar) {
|
||||||
website.EditorBar.include({
|
website.EditorBar.include({
|
||||||
tours: [],
|
tours: [],
|
||||||
start: function () {
|
start: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var menu = $('#help-menu');
|
var menu = $('#help-menu');
|
||||||
_.each(this.tours, function (tour) {
|
_.each(T.tours, function (tour) {
|
||||||
|
if (tour.mode === "test") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var $menuItem = $($.parseHTML('<li><a href="#">'+tour.name+'</a></li>'));
|
var $menuItem = $($.parseHTML('<li><a href="#">'+tour.name+'</a></li>'));
|
||||||
$menuItem.click(function () {
|
$menuItem.click(function () {
|
||||||
tour.reset();
|
T.reset();
|
||||||
tour.run();
|
T.run(tour.id);
|
||||||
});
|
});
|
||||||
menu.append($menuItem);
|
menu.append($menuItem);
|
||||||
});
|
});
|
||||||
return this._super();
|
return this._super();
|
||||||
},
|
|
||||||
registerTour: function (tour) {
|
|
||||||
website.Tour.add(tour);
|
|
||||||
this.tours.push(tour);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -94,351 +80,401 @@ $.ajaxSetup({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
website.Tour = openerp.Class.extend({
|
/////////////////////////////////////////////////
|
||||||
steps: [],
|
|
||||||
defaultDelay: 50, //ms
|
|
||||||
defaultOverLaps: 5000, //ms
|
|
||||||
localStorage: window.localStorage,
|
|
||||||
init: function () {},
|
|
||||||
|
|
||||||
run: function (automatic) {
|
var localStorage = window.localStorage;
|
||||||
this.reset();
|
|
||||||
|
|
||||||
for (var k in this.localStorage) {
|
var T = website.Tour = {
|
||||||
if (!k.indexOf("tour-") && k.indexOf("-test") > -1) return;
|
tours: {},
|
||||||
}
|
defaultDelay: 50,
|
||||||
|
retryRunningDelay: 1000,
|
||||||
website.Tour.busy = true;
|
errorDelay: 5000,
|
||||||
|
state: null,
|
||||||
if (automatic) {
|
$element: null,
|
||||||
this.localStorage.setItem("tour-"+this.id+"-test-automatic", true);
|
timer: null,
|
||||||
|
testtimer: null,
|
||||||
|
currentTimer: null,
|
||||||
|
register: function (tour) {
|
||||||
|
if (tour.mode !== "test") tour.mode = "tutorial";
|
||||||
|
T.tours[tour.id] = tour;
|
||||||
|
},
|
||||||
|
run: function (tour_id, mode) {
|
||||||
|
var tour = T.tours[tour_id];
|
||||||
|
this.time = new Date().getTime();
|
||||||
|
if (tour.path && !window.location.href.match(new RegExp("("+T.getLang()+")?"+tour.path+"#?$", "i"))) {
|
||||||
|
var href = "/"+T.getLang()+tour.path;
|
||||||
|
console.log("Tour Begin from run method (redirection to "+href+")");
|
||||||
|
T.saveState(tour.id, mode || tour.mode, -1);
|
||||||
|
window.location.href = href;
|
||||||
} else {
|
} else {
|
||||||
this.localStorage.removeItem("tour-"+this.id+"-test-automatic");
|
console.log("Tour Begin from run method");
|
||||||
|
T.saveState(tour.id, mode || tour.mode, 0);
|
||||||
|
T.running();
|
||||||
}
|
}
|
||||||
this.automatic = automatic;
|
|
||||||
|
|
||||||
if (this.path) {
|
|
||||||
// redirect to begin of the tour in function of the language
|
|
||||||
if (!this.testUrl(this.path+"(#.*)?$")) {
|
|
||||||
var path = this.path.split('#');
|
|
||||||
window.location.href = "/"+this.getLang()+path[0] + "#tutorial."+this.id+"=true&" + path.slice(1, path.length).join("#");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
this.localStorage.setItem("tour-"+this.id+"-test", 0);
|
|
||||||
website.Tour.waitReady.call(this, function () {self._running();});
|
|
||||||
},
|
},
|
||||||
running: function () {
|
registerSteps: function (tour) {
|
||||||
var self = this;
|
if (tour.register) {
|
||||||
if (+this.localStorage.getItem("tour-"+this.id+"-test") >= this.steps.length-1) {
|
|
||||||
this.endTour();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
tour.register = true;
|
||||||
|
|
||||||
if (website.Tour.is_busy()) return;
|
for (var index=0, len=tour.steps.length; index<len; index++) {
|
||||||
|
var step = tour.steps[index];
|
||||||
|
step.id = index;
|
||||||
|
|
||||||
// launch tour with url
|
if (!step.waitNot && index > 0 && tour.steps[index-1] &&
|
||||||
this.checkRunningUrl();
|
tour.steps[index-1].popover && tour.steps[index-1].popover.next) {
|
||||||
|
step.waitNot = '.popover.tour.fade.in:visible';
|
||||||
// mark tour as busy (only one test running)
|
|
||||||
if (this.localStorage.getItem("tour-"+this.id+"-test") != null) {
|
|
||||||
website.Tour.busy = true;
|
|
||||||
this.automatic = !!this.localStorage.getItem("tour-"+this.id+"-test-automatic");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.testPathUrl()) {
|
|
||||||
if (this.automatic) {
|
|
||||||
this.timer = setTimeout(function () {
|
|
||||||
self.reset();
|
|
||||||
throw new Error("Wrong url for running " + self.id
|
|
||||||
+ '\ntestPath: ' + self.testPath
|
|
||||||
+ '\nhref: ' + window.location.href
|
|
||||||
+ "\nreferrer: " + document.referrer
|
|
||||||
);
|
|
||||||
},this.defaultOverLaps);
|
|
||||||
}
|
}
|
||||||
return;
|
if (!step.waitFor && index > 0 && tour.steps[index-1].snippet) {
|
||||||
}
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
website.Tour.waitReady.call(this, function () {self._running();});
|
|
||||||
},
|
|
||||||
_running: function () {
|
|
||||||
var stepId = this.localStorage.getItem("tour-"+this.id+"-test");
|
|
||||||
|
|
||||||
if (stepId != null) {
|
|
||||||
this.registerTour();
|
|
||||||
this.nextStep(stepId, this.automatic ? this.autoNextStep : null, this.automatic ? this.defaultOverLaps : null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
reset: function () {
|
|
||||||
website.Tour.busy = false;
|
|
||||||
for (var k in this.steps) {
|
|
||||||
this.steps[k].busy = false;
|
|
||||||
}
|
|
||||||
clearTimeout(self.timer);
|
|
||||||
clearTimeout(self.testtimer);
|
|
||||||
|
|
||||||
for (var k in this.localStorage) {
|
|
||||||
if (!k.indexOf("tour-") || !k.indexOf(this.id)) {
|
|
||||||
this.localStorage.removeItem(k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$('.popover.tour').remove();
|
|
||||||
},
|
|
||||||
|
|
||||||
getLang: function () {
|
|
||||||
return $("html").attr("lang").replace(/-/, '_');
|
|
||||||
},
|
|
||||||
testUrl: function (url) {
|
|
||||||
return new RegExp("(/"+this.getLang()+")?"+url, "i").test(window.location.href);
|
|
||||||
},
|
|
||||||
testPathUrl: function () {
|
|
||||||
if (!this.testPath || this.testUrl(this.testPath)) return true;
|
|
||||||
},
|
|
||||||
checkRunningUrl: function () {
|
|
||||||
if (window.location.hash.indexOf("tutorial."+this.id+"=true") > -1) {
|
|
||||||
this.localStorage.setItem("tour-"+this.id+"-test", 0);
|
|
||||||
window.location.hash = window.location.hash.replace(/tutorial.+=true&?/, '');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
registerTour: function () {
|
|
||||||
if (this.automatic) {
|
|
||||||
bootstrap_tour_stub();
|
|
||||||
}
|
|
||||||
this.tour = new Tour({
|
|
||||||
name: this.id,
|
|
||||||
storage: this.tourStorage,
|
|
||||||
keyboard: false,
|
|
||||||
template: this.popover(),
|
|
||||||
onHide: function () {
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.registerSteps();
|
|
||||||
},
|
|
||||||
registerSteps: function () {
|
|
||||||
for (var index=0, len=this.steps.length; index<len; index++) {
|
|
||||||
var step = this.steps[index];
|
|
||||||
step.stepId = step.stepId || ""+index;
|
|
||||||
|
|
||||||
if (!step.waitNot && index > 0 && this.steps[index-1] &&
|
|
||||||
this.steps[index-1].popover && this.steps[index-1].popover.next) {
|
|
||||||
step.waitNot = '.popover.tour:visible';
|
|
||||||
}
|
|
||||||
if (!step.waitFor && index > 0 && this.steps[index-1].snippet) {
|
|
||||||
step.waitFor = '.oe_overlay_options .oe_options:visible';
|
step.waitFor = '.oe_overlay_options .oe_options:visible';
|
||||||
}
|
}
|
||||||
|
|
||||||
step._title = step._title || step.title;
|
|
||||||
step.title = this.popoverTitle({ title: step._title });
|
|
||||||
step.template = step.template || this.popover( step.popover );
|
|
||||||
|
|
||||||
if (!step.element) step.orphan = true;
|
var snippet = step.element && step.element.match(/#oe_snippets (.*) \.oe_snippet_thumbnail/);
|
||||||
if (step.snippet) {
|
if (snippet) {
|
||||||
|
step.snippet = snippet[1];
|
||||||
|
} else if (step.snippet) {
|
||||||
step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail';
|
step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!step.element) {
|
||||||
|
step.element = "body";
|
||||||
|
step.orphan = true;
|
||||||
|
step.backdrop = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (tour.steps[index-1] &&
|
||||||
if (this.steps[index-1] &&
|
tour.steps[index-1].popover && tour.steps[index-1].popover.next) {
|
||||||
this.steps[index-1].popover && this.steps[index-1].popover.next) {
|
|
||||||
var step = {
|
var step = {
|
||||||
stepId: ""+index,
|
_title: "",
|
||||||
waitNot: '.popover.tour:visible'
|
id: index,
|
||||||
|
waitNot: '.popover.tour.fade.in:visible'
|
||||||
};
|
};
|
||||||
this.steps.push(step);
|
tour.steps.push(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tour.addSteps(this.steps);
|
// rendering bootstrap tour and popover
|
||||||
|
if (tour.mode !== "test") {
|
||||||
|
for (var index=0, len=tour.steps.length; index<len; index++) {
|
||||||
|
var step = tour.steps[index];
|
||||||
|
step._title = step._title || step.title;
|
||||||
|
step.title = T.popoverTitle(tour, { title: step._title });
|
||||||
|
step.template = step.template || T.popover( step.popover );
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
closePopover: function () {
|
||||||
popoverTitle: function (options) {
|
if (T.$element) {
|
||||||
try {
|
T.$element.popover('destroy');
|
||||||
return openerp.qweb.render('website.tour_popover_title', options);
|
T.$element.removeData("tour");
|
||||||
} catch (e) {
|
T.$element.removeData("tour-step");
|
||||||
if (!this.automatic) throw e;
|
$(".tour-backdrop").remove();
|
||||||
return options.title;
|
$(".popover.tour").remove();
|
||||||
|
T.$element = null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
autoTogglePopover: function () {
|
||||||
|
var state = T.getState();
|
||||||
|
var step = state.step;
|
||||||
|
|
||||||
|
if (T.$element &&
|
||||||
|
T.$element.is(":visible") &&
|
||||||
|
T.$element.data("tour") === state.id &&
|
||||||
|
T.$element.data("tour-step") === step.id) {
|
||||||
|
T.repositionPopover();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.busy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
T.closePopover();
|
||||||
|
|
||||||
|
var $element = $(step.element).first();
|
||||||
|
if (!step.element || !$element.size() || !$element.is(":visible")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
T.$element = $element;
|
||||||
|
$element.data("tour", state.id);
|
||||||
|
$element.data("tour-step", step.id);
|
||||||
|
$element.popover({
|
||||||
|
placement: step.placement || "auto",
|
||||||
|
animation: true,
|
||||||
|
trigger: "manual",
|
||||||
|
title: step.title,
|
||||||
|
content: step.content,
|
||||||
|
html: true,
|
||||||
|
container: "body",
|
||||||
|
template: step.template,
|
||||||
|
orphan: step.orphan
|
||||||
|
}).popover("show");
|
||||||
|
|
||||||
|
|
||||||
|
var $tip = $element.data("bs.popover").tip();
|
||||||
|
|
||||||
|
|
||||||
|
// add popover style (orphan, static, backdrop)
|
||||||
|
if (step.orphan) {
|
||||||
|
$tip.addClass("orphan");
|
||||||
|
}
|
||||||
|
|
||||||
|
var node = $element[0];
|
||||||
|
var css;
|
||||||
|
do {
|
||||||
|
css = window.getComputedStyle(node);
|
||||||
|
if (!css || css.position == "fixed") {
|
||||||
|
$tip.addClass("fixed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((node = node.parentNode) && node !== document);
|
||||||
|
|
||||||
|
if (step.backdrop) {
|
||||||
|
$("body").append('<div class="tour-backdrop"></div>');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step.backdrop || $element.parents("#website-top-navbar, .modal").size()) {
|
||||||
|
$tip.css("z-index", 2010);
|
||||||
|
}
|
||||||
|
|
||||||
|
// button click event
|
||||||
|
$tip.find("button")
|
||||||
|
.one("click", function () {
|
||||||
|
step.busy = true;
|
||||||
|
if (!$(this).is("[data-role='next']")) {
|
||||||
|
clearTimeout(T.timer);
|
||||||
|
T.endTour();
|
||||||
|
}
|
||||||
|
T.closePopover();
|
||||||
|
});
|
||||||
|
|
||||||
|
T.repositionPopover();
|
||||||
|
},
|
||||||
|
repositionPopover: function() {
|
||||||
|
var popover = T.$element.data("bs.popover");
|
||||||
|
var $tip = T.$element.data("bs.popover").tip();
|
||||||
|
|
||||||
|
if (popover.options.orphan) {
|
||||||
|
return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (popover.options.placement === "bottom" || popover.options.placement === "top") {
|
||||||
|
var left = T.$element.offset().left + T.$element.outerWidth()/2 - tipOffset.left;
|
||||||
|
$tip.find(".arrow").css("left", left ? left + "px" : "");
|
||||||
|
} else if (popover.options.placement !== "auto") {
|
||||||
|
var top = T.$element.offset().top + T.$element.outerHeight()/2 - tipOffset.top;
|
||||||
|
$tip.find(".arrow").css("top", top ? top + "px" : "");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
popoverTitle: function (tour, options) {
|
||||||
|
return openerp.qweb ? openerp.qweb.render('website.tour_popover_title', options) : options.title;
|
||||||
|
},
|
||||||
popover: function (options) {
|
popover: function (options) {
|
||||||
try {
|
return openerp.qweb ? openerp.qweb.render('website.tour_popover', options) : options.title;
|
||||||
return openerp.qweb.render('website.tour_popover', options);
|
},
|
||||||
} catch (e) {
|
getLang: function () {
|
||||||
if (!this.automatic) throw e;
|
return $("html").attr("lang").replace(/-/, '_');
|
||||||
return "";
|
},
|
||||||
}
|
getState: function () {
|
||||||
|
var state = JSON.parse(localStorage.getItem("tour") || 'false') || {};
|
||||||
|
if (state) { this.time = state.time; }
|
||||||
|
var tour_id,mode,step_id;
|
||||||
|
if (!state.id && window.location.href.indexOf("#tutorial.") > -1) {
|
||||||
|
state = {
|
||||||
|
"id": window.location.href.match(/#tutorial\.(.*)=true/)[1],
|
||||||
|
"mode": "tutorial",
|
||||||
|
"step_id": 0
|
||||||
|
};
|
||||||
|
window.location.hash = "";
|
||||||
|
console.log("Tour Begin from url hash");
|
||||||
|
T.saveState(state.id, state.mode, state.step_id);
|
||||||
|
}
|
||||||
|
if (!state.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.tour = T.tours[state.id];
|
||||||
|
state.step = state.tour && state.tour.steps[state.step_id === -1 ? 0 : state.step_id];
|
||||||
|
return state;
|
||||||
|
},
|
||||||
|
error: function (step, message) {
|
||||||
|
var state = T.getState();
|
||||||
|
message += '\n tour: ' + state.id
|
||||||
|
+ '\n step: ' + step.id + ": '" + (step._title || step.title) + "'"
|
||||||
|
+ '\n href: ' + window.location.href
|
||||||
|
+ '\n referrer: ' + document.referrer
|
||||||
|
+ '\n element: ' + Boolean(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden")))
|
||||||
|
+ '\n waitNot: ' + Boolean(!step.waitNot || !$(step.waitNot).size())
|
||||||
|
+ '\n waitFor: ' + Boolean(!step.waitFor || $(step.waitFor).size())
|
||||||
|
+ "\n localStorage: " + JSON.stringify(localStorage)
|
||||||
|
+ '\n\n' + $("body").html();
|
||||||
|
T.reset();
|
||||||
|
throw new Error(message);
|
||||||
|
},
|
||||||
|
lists: function () {
|
||||||
|
var tour_ids = [];
|
||||||
|
for (var k in T.tours) {
|
||||||
|
tour_ids.push(k);
|
||||||
|
}
|
||||||
|
return tour_ids;
|
||||||
|
},
|
||||||
|
saveState: function (tour_id, mode, step_id) {
|
||||||
|
localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id || 0, "time": this.time}));
|
||||||
|
},
|
||||||
|
reset: function () {
|
||||||
|
var state = T.getState();
|
||||||
|
if (state) {
|
||||||
|
for (var k in state.tour.steps) {
|
||||||
|
state.tour.steps[k].busy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localStorage.removeItem("tour");
|
||||||
|
clearTimeout(T.timer);
|
||||||
|
clearTimeout(T.testtimer);
|
||||||
|
T.closePopover();
|
||||||
|
},
|
||||||
|
running: function () {
|
||||||
|
function run () {
|
||||||
|
var state = T.getState();
|
||||||
|
if (!state) return;
|
||||||
|
if (state.tour) {
|
||||||
|
console.log("Tour '"+state.id+"' is running");
|
||||||
|
T.registerSteps(state.tour);
|
||||||
|
T.nextStep();
|
||||||
|
} else {
|
||||||
|
console.log("Tour '"+state.id+"' wait for running (tour undefined)");
|
||||||
|
setTimeout(T.running, state.mode === "test" ? T.defaultDelay : T.retryRunningDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(function () {
|
||||||
|
if ($.ajaxBusy) {
|
||||||
|
$(document).ajaxStop(run);
|
||||||
|
} else {
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
},0);
|
||||||
},
|
},
|
||||||
|
|
||||||
timer: null,
|
|
||||||
testtimer: null,
|
|
||||||
check: function (step) {
|
check: function (step) {
|
||||||
return (step &&
|
return (step &&
|
||||||
(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) &&
|
(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) &&
|
||||||
(!step.waitNot || !$(step.waitNot).size()) &&
|
(!step.waitNot || !$(step.waitNot).size()) &&
|
||||||
(!step.waitFor || $(step.waitFor).size()));
|
(!step.waitFor || $(step.waitFor).size()));
|
||||||
},
|
},
|
||||||
waitNextStep: function (step, callback, overlaps) {
|
waitNextStep: function () {
|
||||||
var self = this;
|
var state = T.getState();
|
||||||
var time = new Date().getTime();
|
var time = new Date().getTime();
|
||||||
var timer;
|
var timer;
|
||||||
|
var next = state.tour.steps[state.step.id+1];
|
||||||
|
var overlaps = state.mode === "test" ? T.errorDelay : 0;
|
||||||
|
|
||||||
window.onbeforeunload = function () {
|
window.onbeforeunload = function () {
|
||||||
clearTimeout(self.timer);
|
clearTimeout(T.timer);
|
||||||
clearTimeout(self.testtimer);
|
clearTimeout(T.testtimer);
|
||||||
};
|
};
|
||||||
|
|
||||||
// check popover activity
|
|
||||||
$(".popover.tour button")
|
|
||||||
.off()
|
|
||||||
.on("click", function () {
|
|
||||||
var help = $("#help-menu-button");
|
|
||||||
var offset = help.offset();
|
|
||||||
var left = (offset.left > 0) ? (offset.left + help.width()) : offset.left;
|
|
||||||
var top = (help.height() > 0) ? (offset.top + help.height()) : offset.top;
|
|
||||||
|
|
||||||
if ($(this).is("[data-role='next']") && step.element) {
|
|
||||||
$(".popover.tour").remove();
|
|
||||||
}
|
|
||||||
if (step.busy) return;
|
|
||||||
if (!$(this).is("[data-role='next']") || !step.element) {
|
|
||||||
$('.popover.tour')
|
|
||||||
.animate({
|
|
||||||
left: left,
|
|
||||||
top: top,
|
|
||||||
width: '1px',
|
|
||||||
height: '1px',
|
|
||||||
opacity: 0
|
|
||||||
}, 800,
|
|
||||||
function(){
|
|
||||||
$(".popover.tour").remove();
|
|
||||||
clearTimeout(self.timer);
|
|
||||||
step.busy = true;
|
|
||||||
self.tour.end();
|
|
||||||
self.endTour(callback);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function checkNext () {
|
function checkNext () {
|
||||||
clearTimeout(self.timer);
|
T.autoTogglePopover();
|
||||||
if (step.busy) return;
|
|
||||||
if (self.check(step)) {
|
clearTimeout(T.timer);
|
||||||
step.busy = true;
|
if (T.check(next)) {
|
||||||
|
clearTimeout(T.currentTimer);
|
||||||
// use an other timeout for cke dom loading
|
// use an other timeout for cke dom loading
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
self.nextStep(step.stepId, callback, overlaps);
|
T.nextStep(next);
|
||||||
}, self.defaultDelay);
|
}, T.defaultDelay);
|
||||||
} else if (!overlaps || new Date().getTime() - time < overlaps) {
|
} else if (!overlaps || new Date().getTime() - time < overlaps) {
|
||||||
if (self.current.element) {
|
T.timer = setTimeout(checkNext, T.defaultDelay);
|
||||||
var $popover = $(".popover.tour");
|
|
||||||
if(!$(self.current.element).is(":visible")) {
|
|
||||||
$popover.data("hide", true).fadeOut(300);
|
|
||||||
} else if($popover.data("hide")) {
|
|
||||||
$popover.data("hide", false).fadeIn(150);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.timer = setTimeout(checkNext, self.defaultDelay);
|
|
||||||
} else {
|
} else {
|
||||||
self.reset();
|
T.error(next, "Can't reach the next step");
|
||||||
throw new Error("Can't arrive to step " + step.stepId + ": '" + step._title + "'"
|
|
||||||
+ '\nhref: ' + window.location.href
|
|
||||||
+ '\nelement: ' + Boolean(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden")))
|
|
||||||
+ '\nwaitNot: ' + Boolean(!step.waitNot || !$(step.waitNot).size())
|
|
||||||
+ '\nwaitFor: ' + Boolean(!step.waitFor || $(step.waitFor).size())
|
|
||||||
+ '\n\n' + $("body").html()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
checkNext();
|
checkNext();
|
||||||
},
|
},
|
||||||
step: function (stepId) {
|
nextStep: function (step) {
|
||||||
var steps = this.steps.slice(0,this.steps.length),
|
var state = T.getState();
|
||||||
step;
|
|
||||||
while (step = steps.shift()) {
|
if (!state) {
|
||||||
if (!stepId || step.stepId === stepId)
|
return;
|
||||||
return step;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
},
|
step = step || state.step;
|
||||||
next: function (stepId) {
|
T.saveState(state.id, state.mode, step.id);
|
||||||
var steps = this.steps.slice(0,this.steps.length),
|
|
||||||
step, next, index=0;
|
if (step.id !== state.step_id) {
|
||||||
while (step = steps.shift()) {
|
console.log("Tour Step: '" + (step._title || step.title) + "' (" + (new Date().getTime() - this.time) + "ms)");
|
||||||
if (!stepId || step.stepId === stepId) {
|
|
||||||
// clear popover (fix for boostrap tour if the element is removed before destroy popover)
|
|
||||||
$(".popover.tour").remove();
|
|
||||||
// go to step in bootstrap tour
|
|
||||||
this.tour.goto(index);
|
|
||||||
if (step.onload) step.onload();
|
|
||||||
next = steps.shift();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
}
|
||||||
return next;
|
|
||||||
},
|
|
||||||
nextStep: function (stepId, callback, overlaps) {
|
|
||||||
var self = this;
|
|
||||||
if (!this.localStorage.getItem("tour-"+this.id+"-test")) return;
|
|
||||||
|
|
||||||
this.localStorage.setItem("tour-"+this.id+"-test", stepId || 0);
|
T.autoTogglePopover(true);
|
||||||
|
|
||||||
this.current = this.step(stepId);
|
if (step.onload) {
|
||||||
var next = this.next(stepId);
|
step.onload();
|
||||||
|
}
|
||||||
|
|
||||||
|
var next = state.tour.steps[step.id+1];
|
||||||
if (next) {
|
if (next) {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
self.waitNextStep(next, callback, overlaps);
|
T.waitNextStep();
|
||||||
if (callback) setTimeout(function(){callback.call(self, next);}, self.defaultDelay);
|
if (state.mode === "test") {
|
||||||
}, next && next.wait || 0);
|
setTimeout(function(){
|
||||||
|
T.autoNextStep(state.tour, step);
|
||||||
|
}, T.defaultDelay);
|
||||||
|
}
|
||||||
|
}, next.wait || 0);
|
||||||
} else {
|
} else {
|
||||||
this.endTour();
|
T.endTour();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
endTour: function () {
|
endTour: function () {
|
||||||
var test = parseInt(this.localStorage.getItem("tour-"+this.id+"-test"),10) >= this.steps.length-1;
|
var state = T.getState();
|
||||||
this.reset();
|
var test = state.step.id >= state.tour.steps.length-1;
|
||||||
|
T.reset();
|
||||||
if (test) {
|
if (test) {
|
||||||
console.log('ok');
|
console.log('ok');
|
||||||
} else {
|
} else {
|
||||||
console.log('error');
|
console.log('error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
autoNextStep: function () {
|
autoNextStep: function (tour, step) {
|
||||||
var self = this;
|
clearTimeout(T.testtimer);
|
||||||
clearTimeout(self.testtimer);
|
|
||||||
|
|
||||||
function autoStep () {
|
function autoStep () {
|
||||||
var step = self.current;
|
|
||||||
if (!step) return;
|
if (!step) return;
|
||||||
|
|
||||||
if (step.autoComplete) {
|
if (step.autoComplete) {
|
||||||
step.autoComplete(tour);
|
step.autoComplete(tour);
|
||||||
}
|
}
|
||||||
|
|
||||||
var $popover = $(".popover.tour");
|
$(".popover.tour [data-role='next']").click();
|
||||||
if ($popover.find("button[data-role='next']:visible").size()) {
|
|
||||||
$popover.find("button[data-role='next']:visible").click();
|
|
||||||
$popover.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
var $element = $(step.element);
|
var $element = $(step.element);
|
||||||
if (!$element.size()) return;
|
if (!$element.size()) return;
|
||||||
|
|
||||||
if (step.snippet) {
|
if (step.snippet) {
|
||||||
|
|
||||||
var selector = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail';
|
T.autoDragAndDropSnippet($element);
|
||||||
self.autoDragAndDropSnippet(selector);
|
|
||||||
|
|
||||||
} else if (step.element.match(/#oe_snippets .* \.oe_snippet_thumbnail/)) {
|
|
||||||
|
|
||||||
self.autoDragAndDropSnippet($element);
|
|
||||||
|
|
||||||
} else if ($element.is(":visible")) {
|
} else if ($element.is(":visible")) {
|
||||||
|
|
||||||
|
@ -473,7 +509,7 @@ website.Tour = openerp.Class.extend({
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.testtimer = setTimeout(autoStep, 100);
|
T.testtimer = setTimeout(autoStep, 100);
|
||||||
},
|
},
|
||||||
autoDragAndDropSnippet: function (selector) {
|
autoDragAndDropSnippet: function (selector) {
|
||||||
var $thumbnail = $(selector).first();
|
var $thumbnail = $(selector).first();
|
||||||
|
@ -483,64 +519,11 @@ website.Tour = openerp.Class.extend({
|
||||||
var $dropZone = $(".oe_drop_zone").first();
|
var $dropZone = $(".oe_drop_zone").first();
|
||||||
var dropPosition = $dropZone.position();
|
var dropPosition = $dropZone.position();
|
||||||
$dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top }));
|
$dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top }));
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
website.Tour.tours = {};
|
|
||||||
website.Tour.busy = false;
|
|
||||||
website.Tour.add = function (tour) {
|
|
||||||
website.Tour.waitReady(function () {
|
|
||||||
tour = tour.id ? tour : new tour();
|
|
||||||
if (!website.Tour.tours[tour.id]) {
|
|
||||||
website.Tour.tours[tour.id] = tour;
|
|
||||||
tour.running();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
website.Tour.get = function (id) {
|
|
||||||
return website.Tour.tours[id];
|
|
||||||
};
|
|
||||||
website.Tour.each = function (callback) {
|
|
||||||
website.Tour.waitReady(function () {
|
|
||||||
for (var k in website.Tour.tours) {
|
|
||||||
callback.call(website.Tour.tours[k]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
website.Tour.waitReady = function (callback) {
|
|
||||||
var self = this;
|
|
||||||
$(document).ready(function () {
|
|
||||||
if ($.ajaxBusy) {
|
|
||||||
$(document).ajaxStop(function() {
|
|
||||||
setTimeout(function () {
|
|
||||||
callback.call(self);
|
|
||||||
},0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setTimeout(function () {
|
|
||||||
callback.call(self);
|
|
||||||
},0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
website.Tour.run_test = function (id) {
|
|
||||||
website.Tour.waitReady(function () {
|
|
||||||
if (!website.Tour.is_busy()) {
|
|
||||||
website.Tour.tours[id].run(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
website.Tour.is_busy = function () {
|
|
||||||
for (var k in this.localStorage) {
|
|
||||||
if (!k.indexOf("tour-")) {
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return website.Tour.busy;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//$(document).ready(T.running);
|
||||||
|
website.ready().then(T.running);
|
||||||
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -8,6 +8,6 @@ class TestUi(openerp.tests.HttpCase):
|
||||||
self.phantom_js("/", "console.log('ok')", "openerp.website.editor", login='admin')
|
self.phantom_js("/", "console.log('ok')", "openerp.website.editor", login='admin')
|
||||||
|
|
||||||
def test_04_admin_tour_banner(self):
|
def test_04_admin_tour_banner(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('banner')", "openerp.website.Tour.tours.banner", login='admin')
|
self.phantom_js("/", "openerp.website.Tour.run('banner', 'test')", "openerp.website.Tour.tours.banner", login='admin')
|
||||||
|
|
||||||
# vim:et:
|
# vim:et:
|
||||||
|
|
|
@ -256,7 +256,6 @@
|
||||||
<xpath expr='//script[@src="/web/static/lib/bootstrap/js/bootstrap.js"]' position="before">
|
<xpath expr='//script[@src="/web/static/lib/bootstrap/js/bootstrap.js"]' position="before">
|
||||||
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
|
<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/src/css/editor.css'/>
|
||||||
<link rel='stylesheet' href='/website/static/lib/bootstrap-tour/bootstrap-tour.css'/>
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/web/static/lib/select2/select2.css"/>
|
<link rel="stylesheet" href="/web/static/lib/select2/select2.css"/>
|
||||||
|
@ -268,7 +267,6 @@
|
||||||
<script t-if="not translatable" type="text/javascript" src="/website/static/lib/ace/ace.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="/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>
|
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
|
||||||
<script type="text/javascript" src="/website/static/lib/bootstrap-tour/bootstrap-tour.js"></script>
|
|
||||||
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
|
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
|
||||||
<script type="text/javascript" src="/website/static/lib//jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
|
<script type="text/javascript" src="/website/static/lib//jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
|
||||||
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
|
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
|
||||||
|
|
|
@ -4,117 +4,105 @@
|
||||||
var website = openerp.website;
|
var website = openerp.website;
|
||||||
var _t = openerp._t;
|
var _t = openerp._t;
|
||||||
|
|
||||||
website.EditorBar.include({
|
website.Tour.register({
|
||||||
start: function () {
|
id: 'blog',
|
||||||
this.registerTour(new website.Tour.Blog(this));
|
name: _t("Create a blog post"),
|
||||||
return this._super();
|
steps: [
|
||||||
},
|
{
|
||||||
});
|
title: _t("New Blog Post"),
|
||||||
|
content: _t("Let's go through the first steps to write beautiful blog posts."),
|
||||||
website.Tour.Blog = website.Tour.extend({
|
popover: { next: _t("Start Tutorial"), end: _t("Skip") },
|
||||||
id: 'blog',
|
},
|
||||||
name: "Create a blog post",
|
{
|
||||||
testPath: '/(blog|blogpost)',
|
element: '#content-menu-button',
|
||||||
init: function () {
|
placement: 'left',
|
||||||
var self = this;
|
title: _t("Add Content"),
|
||||||
self.steps = [
|
content: _t("Use this <em>'Content'</em> menu to create a new blog post like any other document (page, menu, products, event, ...)."),
|
||||||
{
|
popover: { fixed: true },
|
||||||
title: _t("New Blog Post"),
|
},
|
||||||
content: _t("Let's go through the first steps to write beautiful blog posts."),
|
{
|
||||||
popover: { next: _t("Start Tutorial"), end: _t("Skip") },
|
element: 'a[data-action=new_blog_post]',
|
||||||
},
|
placement: 'left',
|
||||||
{
|
title: _t("New Blog Post"),
|
||||||
element: '#content-menu-button',
|
content: _t("Select this menu item to create a new blog post."),
|
||||||
placement: 'left',
|
popover: { fixed: true },
|
||||||
title: _t("Add Content"),
|
},
|
||||||
content: _t("Use this <em>'Content'</em> menu to create a new blog post like any other document (page, menu, products, event, ...)."),
|
{
|
||||||
popover: { fixed: true },
|
element: '.modal:has(#editor_new_blog) button.btn-primary',
|
||||||
},
|
placement: 'right',
|
||||||
{
|
title: _t("Create Blog Post"),
|
||||||
element: 'a[data-action=new_blog_post]',
|
content: _t("Click <em>Continue</em> to create the blog post."),
|
||||||
placement: 'left',
|
},
|
||||||
title: _t("New Blog Post"),
|
{
|
||||||
content: _t("Select this menu item to create a new blog post."),
|
waitFor: 'body:has(button[data-action=save]:visible):has(.js_blog)',
|
||||||
popover: { fixed: true },
|
title: _t("Blog Post Created"),
|
||||||
},
|
content: _t("This is your new blog post. Let's edit it."),
|
||||||
{
|
popover: { next: _t("Continue") },
|
||||||
element: '.modal:has(#editor_new_blog) button.btn-primary',
|
},
|
||||||
placement: 'right',
|
{
|
||||||
title: _t("Create Blog Post"),
|
element: 'h1[data-oe-expression="blog_post.name"]',
|
||||||
content: _t("Click <em>Continue</em> to create the blog post."),
|
placement: 'bottom',
|
||||||
},
|
sampleText: 'New Blog',
|
||||||
{
|
title: _t("Set a Title"),
|
||||||
waitFor: 'body:has(button[data-action=save]:visible):has(.js_blog)',
|
content: _t("Click on this area and set a catchy title for your blog post."),
|
||||||
title: _t("Blog Post Created"),
|
},
|
||||||
content: _t("This is your new blog post. Let's edit it."),
|
{
|
||||||
popover: { next: _t("Continue") },
|
waitNot: '#wrap h1[data-oe-model="blog.post"]:contains("Blog Post Title")',
|
||||||
},
|
element: 'button[data-action=snippet]',
|
||||||
{
|
placement: 'left',
|
||||||
element: 'h1[data-oe-expression="blog_post.name"]',
|
title: _t("Layout Your Blog Post"),
|
||||||
placement: 'bottom',
|
content: _t("Use well designed building blocks to structure the content of your blog. Click 'Insert Blocks' to add new content."),
|
||||||
sampleText: 'New Blog',
|
popover: { fixed: true },
|
||||||
title: _t("Set a Title"),
|
},
|
||||||
content: _t("Click on this area and set a catchy title for your blog post."),
|
{
|
||||||
},
|
snippet: '#snippet_structure .oe_snippet:eq(2)',
|
||||||
{
|
placement: 'bottom',
|
||||||
waitNot: '#wrap h1[data-oe-model="blog.post"]:contains("Blog Post Title")',
|
title: _t("Drag & Drop a Block"),
|
||||||
element: 'button[data-action=snippet]',
|
content: _t("Drag this block and drop it in your page."),
|
||||||
placement: 'left',
|
popover: { fixed: true },
|
||||||
title: _t("Layout Your Blog Post"),
|
},
|
||||||
content: _t("Use well designed building blocks to structure the content of your blog. Click 'Insert Blocks' to add new content."),
|
{
|
||||||
popover: { fixed: true },
|
element: 'button[data-action=snippet]',
|
||||||
},
|
placement: 'bottom',
|
||||||
{
|
title: _t("Add Another Block"),
|
||||||
snippet: '#snippet_structure .oe_snippet:eq(2)',
|
content: _t("Let's add another block to your post."),
|
||||||
placement: 'bottom',
|
popover: { fixed: true },
|
||||||
title: _t("Drag & Drop a Block"),
|
},
|
||||||
content: _t("Drag this block and drop it in your page."),
|
{
|
||||||
popover: { fixed: true },
|
snippet: '#snippet_structure .oe_snippet:eq(4)',
|
||||||
},
|
placement: 'bottom',
|
||||||
{
|
title: _t("Drag & Drop a block"),
|
||||||
element: 'button[data-action=snippet]',
|
content: _t("Drag this block and drop it below the image block."),
|
||||||
placement: 'bottom',
|
popover: { fixed: true },
|
||||||
title: _t("Add Another Block"),
|
},
|
||||||
content: _t("Let's add another block to your post."),
|
{
|
||||||
popover: { fixed: true },
|
element: '.oe_active .oe_snippet_remove',
|
||||||
},
|
placement: 'top',
|
||||||
{
|
title: _t("Delete the block"),
|
||||||
snippet: '#snippet_structure .oe_snippet:eq(4)',
|
content: _t("From this toolbar you can move, duplicate or delete the selected zone. Click on the garbage can image to delete the block. Or click on the Title and delete it."),
|
||||||
placement: 'bottom',
|
},
|
||||||
title: _t("Drag & Drop a block"),
|
{
|
||||||
content: _t("Drag this block and drop it below the image block."),
|
waitNot: '.oe_active .oe_snippet_remove:visible',
|
||||||
popover: { fixed: true },
|
element: 'button[data-action=save]',
|
||||||
},
|
placement: 'right',
|
||||||
{
|
title: _t("Save Your Blog"),
|
||||||
element: '.oe_active .oe_snippet_remove',
|
content: _t("Click the <em>Save</em> button to record changes on the page."),
|
||||||
placement: 'top',
|
popover: { fixed: true },
|
||||||
title: _t("Delete the block"),
|
},
|
||||||
content: _t("From this toolbar you can move, duplicate or delete the selected zone. Click on the garbage can image to delete the block. Or click on the Title and delete it."),
|
{
|
||||||
},
|
waitFor: 'button[data-action=edit]:visible',
|
||||||
{
|
element: 'button.btn-danger.js_publish_btn',
|
||||||
waitNot: '.oe_active .oe_snippet_remove:visible',
|
placement: 'top',
|
||||||
element: 'button[data-action=save]',
|
title: _t("Publish Your Post"),
|
||||||
placement: 'right',
|
content: _t("Your blog post is not yet published. You can update this draft version and publish it once you are ready."),
|
||||||
title: _t("Save Your Blog"),
|
},
|
||||||
content: _t("Click the <em>Save</em> button to record changes on the page."),
|
{
|
||||||
popover: { fixed: true },
|
waitFor: '.js_publish_management button.js_publish_btn.btn-success:visible',
|
||||||
},
|
title: "Thanks!",
|
||||||
{
|
content: _t("This tutorial is finished. To discover more features, improve the content of this page and try the <em>Promote</em> button in the top right menu."),
|
||||||
waitFor: 'button[data-action=edit]:visible',
|
popover: { next: _t("Close Tutorial") },
|
||||||
element: 'button.btn-danger.js_publish_btn',
|
},
|
||||||
placement: 'top',
|
]
|
||||||
title: _t("Publish Your Post"),
|
|
||||||
content: _t("Your blog post is not yet published. You can update this draft version and publish it once you are ready."),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
waitFor: '.js_publish_management button.js_publish_btn.btn-success:visible',
|
|
||||||
title: "Thanks!",
|
|
||||||
content: _t("This tutorial is finished. To discover more features, improve the content of this page and try the <em>Promote</em> button in the top right menu."),
|
|
||||||
popover: { next: _t("Close Tutorial") },
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -2,5 +2,5 @@ import openerp.tests
|
||||||
|
|
||||||
class TestUi(openerp.tests.HttpCase):
|
class TestUi(openerp.tests.HttpCase):
|
||||||
def test_admin(self):
|
def test_admin(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('blog')", "openerp.website.Tour")
|
self.phantom_js("/", "openerp.website.Tour.run('blog', 'test')", "openerp.website.Tour.tours.blog")
|
||||||
|
|
||||||
|
|
|
@ -4,115 +4,103 @@
|
||||||
var website = openerp.website;
|
var website = openerp.website;
|
||||||
var _t = openerp._t;
|
var _t = openerp._t;
|
||||||
|
|
||||||
website.EditorBar.include({
|
website.Tour.register({
|
||||||
start: function () {
|
id: 'event',
|
||||||
this.registerTour(new website.EventTour(this));
|
name: _t("Create an event"),
|
||||||
return this._super();
|
steps: [
|
||||||
},
|
{
|
||||||
});
|
title: _t("Create an Event"),
|
||||||
|
content: _t("Let's go through the first steps to publish a new event."),
|
||||||
website.EventTour = website.Tour.extend({
|
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
||||||
id: 'event',
|
},
|
||||||
name: "Create an event",
|
{
|
||||||
testPath: '/event(/[0-9]+/register)?',
|
element: '#content-menu-button',
|
||||||
init: function (editor) {
|
placement: 'left',
|
||||||
var self = this;
|
title: _t("Add Content"),
|
||||||
self.steps = [
|
content: _t("The <em>Content</em> menu allows you to create new pages, events, menus, etc."),
|
||||||
{
|
popover: { fixed: true },
|
||||||
title: _t("Create an Event"),
|
},
|
||||||
content: _t("Let's go through the first steps to publish a new event."),
|
{
|
||||||
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
element: 'a[data-action=new_event]',
|
||||||
},
|
placement: 'left',
|
||||||
{
|
title: _t("New Event"),
|
||||||
element: '#content-menu-button',
|
content: _t("Click here to create a new event."),
|
||||||
placement: 'left',
|
popover: { fixed: true },
|
||||||
title: _t("Add Content"),
|
},
|
||||||
content: _t("The <em>Content</em> menu allows you to create new pages, events, menus, etc."),
|
{
|
||||||
popover: { fixed: true },
|
element: '.modal #editor_new_event input[type=text]',
|
||||||
},
|
sampleText: 'Advanced Technical Training',
|
||||||
{
|
placement: 'right',
|
||||||
element: 'a[data-action=new_event]',
|
title: _t("Create an Event Name"),
|
||||||
placement: 'left',
|
content: _t("Create a name for your new event and click <em>'Continue'</em>. e.g: Technical Training"),
|
||||||
title: _t("New Event"),
|
},
|
||||||
content: _t("Click here to create a new event."),
|
{
|
||||||
popover: { fixed: true },
|
waitNot: '.modal input[type=text]:not([value!=""])',
|
||||||
},
|
element: '.modal button.btn-primary',
|
||||||
{
|
placement: 'right',
|
||||||
element: '.modal #editor_new_event input[type=text]',
|
title: _t("Create Event"),
|
||||||
sampleText: 'Advanced Technical Training',
|
content: _t("Click <em>Continue</em> to create the event."),
|
||||||
placement: 'right',
|
},
|
||||||
title: _t("Create an Event Name"),
|
{
|
||||||
content: _t("Create a name for your new event and click <em>'Continue'</em>. e.g: Technical Training"),
|
waitFor: 'body:has(button[data-action=save]:visible):has(.js_event)',
|
||||||
},
|
title: _t("New Event Created"),
|
||||||
{
|
content: _t("This is your new event page. We will edit the event presentation page."),
|
||||||
waitNot: '.modal input[type=text]:not([value!=""])',
|
popover: { next: _t("Continue") },
|
||||||
element: '.modal button.btn-primary',
|
},
|
||||||
placement: 'right',
|
{
|
||||||
title: _t("Create Event"),
|
element: 'button[data-action=snippet]',
|
||||||
content: _t("Click <em>Continue</em> to create the event."),
|
placement: 'bottom',
|
||||||
},
|
title: _t("Layout your event"),
|
||||||
{
|
content: _t("Insert blocks to layout the body of your event."),
|
||||||
waitFor: 'body:has(button[data-action=save]:visible):has(.js_event)',
|
popover: { fixed: true },
|
||||||
title: _t("New Event Created"),
|
},
|
||||||
content: _t("This is your new event page. We will edit the event presentation page."),
|
{
|
||||||
popover: { next: _t("Continue") },
|
snippet: '#snippet_structure .oe_snippet:eq(2)',
|
||||||
},
|
placement: 'bottom',
|
||||||
{
|
title: _t("Drag & Drop a block"),
|
||||||
element: 'button[data-action=snippet]',
|
content: _t("Drag the 'Image-Text' block and drop it in your page."),
|
||||||
placement: 'bottom',
|
popover: { fixed: true },
|
||||||
title: _t("Layout your event"),
|
},
|
||||||
content: _t("Insert blocks to layout the body of your event."),
|
{
|
||||||
popover: { fixed: true },
|
|
||||||
},
|
element: 'button[data-action=snippet]',
|
||||||
{
|
placement: 'bottom',
|
||||||
snippet: '#snippet_structure .oe_snippet:eq(2)',
|
title: _t("Layout your event"),
|
||||||
placement: 'bottom',
|
content: _t("Insert another block to your event."),
|
||||||
title: _t("Drag & Drop a block"),
|
popover: { fixed: true },
|
||||||
content: _t("Drag the 'Image-Text' block and drop it in your page."),
|
},
|
||||||
popover: { fixed: true },
|
{
|
||||||
},
|
snippet: '#snippet_structure .oe_snippet:eq(4)',
|
||||||
{
|
placement: 'bottom',
|
||||||
|
title: _t("Drag & Drop a block"),
|
||||||
element: 'button[data-action=snippet]',
|
content: _t("Drag the 'Text Block' in your event page."),
|
||||||
placement: 'bottom',
|
popover: { fixed: true },
|
||||||
title: _t("Layout your event"),
|
},
|
||||||
content: _t("Insert another block to your event."),
|
{
|
||||||
popover: { fixed: true },
|
element: 'button[data-action=save]',
|
||||||
},
|
placement: 'right',
|
||||||
{
|
title: _t("Save your modifications"),
|
||||||
snippet: '#snippet_structure .oe_snippet:eq(4)',
|
content: _t("Once you click on save, your event is updated."),
|
||||||
placement: 'bottom',
|
popover: { fixed: true },
|
||||||
title: _t("Drag & Drop a block"),
|
},
|
||||||
content: _t("Drag the 'Text Block' in your event page."),
|
{
|
||||||
popover: { fixed: true },
|
waitFor: 'button[data-action=edit]:visible',
|
||||||
},
|
element: 'button.btn-danger.js_publish_btn',
|
||||||
{
|
placement: 'top',
|
||||||
element: 'button[data-action=save]',
|
title: _t("Publish your event"),
|
||||||
placement: 'right',
|
content: _t("Click to publish your event."),
|
||||||
title: _t("Save your modifications"),
|
},
|
||||||
content: _t("Once you click on save, your event is updated."),
|
{
|
||||||
popover: { fixed: true },
|
waitFor: '.js_publish_management button.js_publish_btn.btn-success:visible',
|
||||||
},
|
element: '.js_publish_management button[data-toggle="dropdown"]',
|
||||||
{
|
placement: 'left',
|
||||||
waitFor: 'button[data-action=edit]:visible',
|
title: _t("Customize your event"),
|
||||||
element: 'button.btn-danger.js_publish_btn',
|
content: _t("Click here to customize your event further."),
|
||||||
placement: 'top',
|
},
|
||||||
title: _t("Publish your event"),
|
{
|
||||||
content: _t("Click to publish your event."),
|
element: '.js_publish_management ul>li>a:last:visible',
|
||||||
},
|
},
|
||||||
{
|
]
|
||||||
waitFor: '.js_publish_management button.js_publish_btn.btn-success:visible',
|
|
||||||
element: '.js_publish_management button[data-toggle="dropdown"]',
|
|
||||||
placement: 'left',
|
|
||||||
title: _t("Customize your event"),
|
|
||||||
content: _t("Click here to customize your event further."),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: '.js_publish_management ul>li>a:last:visible',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return this._super();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -2,5 +2,5 @@ import openerp.tests
|
||||||
|
|
||||||
class TestUi(openerp.tests.HttpCase):
|
class TestUi(openerp.tests.HttpCase):
|
||||||
def test_admin(self):
|
def test_admin(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('event')", "openerp.website.Tour")
|
self.phantom_js("/", "openerp.website.Tour.run('event', 'test')", "openerp.website.Tour.tours.event")
|
||||||
|
|
||||||
|
|
|
@ -3,77 +3,63 @@
|
||||||
|
|
||||||
var website = openerp.website;
|
var website = openerp.website;
|
||||||
|
|
||||||
website.Tour.EventSaleTest = website.Tour.extend({
|
website.Tour.register({
|
||||||
id: 'event_buy_tickets',
|
id: 'event_buy_tickets',
|
||||||
name: "Try to buy tickets for event",
|
name: "Try to buy tickets for event",
|
||||||
path: '/event',
|
path: '/event',
|
||||||
init: function () {
|
mode: 'test',
|
||||||
var self = this;
|
steps: [
|
||||||
self.steps = [
|
{
|
||||||
{
|
title: "select event",
|
||||||
title: "select event",
|
element: 'a[href*="/event"]:contains("Conference on Business Applications"):first',
|
||||||
element: 'a[href*="/event"]:contains("Open Days in Los Angeles")',
|
},
|
||||||
|
{
|
||||||
|
waitNot: 'a[href*="/event"]:contains("Conference on Business Applications")',
|
||||||
|
title: "select 2 Standard tickets",
|
||||||
|
element: 'select:eq(0)',
|
||||||
|
sampleText: '2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "select 3 VIP tickets",
|
||||||
|
waitFor: 'select:eq(0) option:contains(2):selected',
|
||||||
|
element: 'select:eq(1)',
|
||||||
|
sampleText: '3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Order Now",
|
||||||
|
waitFor: 'select:eq(1) option:contains(3):selected',
|
||||||
|
element: '.btn-primary:contains("Order Now")',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Complete checkout",
|
||||||
|
waitFor: '#top_menu .my_cart_quantity:contains(5)',
|
||||||
|
element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")',
|
||||||
|
autoComplete: function (tour) {
|
||||||
|
if ($("input[name='name']").val() === "")
|
||||||
|
$("input[name='name']").val("website_sale-test-shoptest");
|
||||||
|
if ($("input[name='email']").val() === "")
|
||||||
|
$("input[name='email']").val("website_event_sale_test_shoptest@websiteeventsaletest.optenerp.com");
|
||||||
|
$("input[name='phone']").val("123");
|
||||||
|
$("input[name='street']").val("123");
|
||||||
|
$("input[name='city']").val("123");
|
||||||
|
$("input[name='zip']").val("123");
|
||||||
|
$("select[name='country_id']").val("21");
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
title: "go to register page",
|
{
|
||||||
waitNot: 'a[href*="/event"]:contains("Functional Webinar")',
|
title: "select payment",
|
||||||
onload: function () {
|
element: '#payment_method label:has(img[title="Wire Transfer"]) input',
|
||||||
// use onload if website_event_track is installed
|
},
|
||||||
if (!$('form:contains("Ticket Type")').size()) {
|
{
|
||||||
window.location.href = $('a[href*="/event"][href*="/register"]').attr("href");
|
title: "Pay Now",
|
||||||
}
|
waitFor: '#payment_method label:has(input:checked):has(img[title="Wire Transfer"])',
|
||||||
},
|
element: '.oe_sale_acquirer_button .btn[name="submit"]:visible',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "select 2 Standard tickets",
|
title: "finish",
|
||||||
element: 'select[name="ticket-1"]',
|
waitFor: '.oe_website_sale:contains("Thank you for your order")',
|
||||||
sampleText: '2',
|
}
|
||||||
},
|
]
|
||||||
{
|
|
||||||
title: "select 3 VIP tickets",
|
|
||||||
waitFor: 'select[name="ticket-1"] option:contains(2):selected',
|
|
||||||
element: 'select[name="ticket-2"]',
|
|
||||||
sampleText: '3',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Order Now",
|
|
||||||
waitFor: 'select[name="ticket-2"] option:contains(3):selected',
|
|
||||||
element: '.btn-primary:contains("Order Now")',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Complete checkout",
|
|
||||||
waitFor: '#top_menu .my_cart_quantity:contains(5)',
|
|
||||||
element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")',
|
|
||||||
onload: function (tour) {
|
|
||||||
if ($("input[name='name']").val() === "")
|
|
||||||
$("input[name='name']").val("website_sale-test-shoptest");
|
|
||||||
if ($("input[name='email']").val() === "")
|
|
||||||
$("input[name='email']").val("website_event_sale_test_shoptest@websiteeventsaletest.optenerp.com");
|
|
||||||
$("input[name='phone']").val("123");
|
|
||||||
$("input[name='street']").val("123");
|
|
||||||
$("input[name='city']").val("123");
|
|
||||||
$("input[name='zip']").val("123");
|
|
||||||
$("select[name='country_id']").val("21");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "select payment",
|
|
||||||
element: '#payment_method label:has(img[title="transfer"]) input',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Pay Now",
|
|
||||||
waitFor: '#payment_method label:has(input:checked):has(img[title="transfer"])',
|
|
||||||
element: '.oe_sale_acquirer_button .btn[name="submit"]:visible',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "finish",
|
|
||||||
waitFor: '.oe_website_sale:contains("Thank you for your order")',
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// for test without editor bar
|
|
||||||
website.Tour.add(website.Tour.EventSaleTest);
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#import test_ui
|
import test_ui
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
|
import os
|
||||||
|
|
||||||
import openerp.tests
|
import openerp.tests
|
||||||
|
|
||||||
inject = [
|
inject = [
|
||||||
"./../../../website/static/src/js/website.tour.test.js",
|
("openerp.website.Tour", os.path.join(os.path.dirname(__file__), '../../website/static/src/js/website.tour.js')),
|
||||||
"./../../../website_event_sale/static/src/js/website.tour.event_sale.js",
|
("openerp.website.Tour.ShopTest", os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.event_sale.js")),
|
||||||
]
|
]
|
||||||
|
|
||||||
@openerp.tests.common.at_install(False)
|
@openerp.tests.common.at_install(False)
|
||||||
@openerp.tests.common.post_install(True)
|
@openerp.tests.common.post_install(True)
|
||||||
class TestUi(openerp.tests.HttpCase):
|
class TestUi(openerp.tests.HttpCase):
|
||||||
def test_admin(self):
|
def test_admin(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('event_buy_tickets')", "openerp.website.Tour", inject=inject)
|
self.phantom_js("/", "openerp.website.Tour.run('event_buy_tickets', 'test')", "openerp.website.Tour.tours.event_buy_tickets", inject=inject)
|
||||||
|
|
||||||
def test_demo(self):
|
def test_demo(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('event_buy_tickets')", "openerp.website.Tour", login="demo", password="demo", inject=inject);
|
self.phantom_js("/", "openerp.website.Tour.run('event_buy_tickets', 'test')", "openerp.website.Tour.tours.event_buy_tickets", login="demo", password="demo", inject=inject);
|
||||||
|
|
||||||
def test_public(self):
|
def test_public(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('event_buy_tickets')", "openerp.website.Tour", login=None, inject=inject);
|
self.phantom_js("/", "openerp.website.Tour.run('event_buy_tickets', 'test')", "openerp.website.Tour.tours.event_buy_tickets", login=None, inject=inject);
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
<xpath expr='//t[@name="layout_head"]' position="before">
|
<xpath expr='//t[@name="layout_head"]' position="before">
|
||||||
<link rel='stylesheet' href='/website/static/src/css/snippets.css'/>
|
<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/src/css/editor.css'/>
|
||||||
<link rel='stylesheet' href='/website/static/lib/bootstrap-tour/bootstrap-tour.css'/>
|
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/web/static/lib/select2/select2.css"/>
|
<link rel="stylesheet" href="/web/static/lib/select2/select2.css"/>
|
||||||
|
@ -50,7 +49,6 @@
|
||||||
<script t-if="not translatable" type="text/javascript" src="/website/static/lib/ace/ace.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="/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>
|
<script type="text/javascript" src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
|
||||||
<script type="text/javascript" src="/website/static/lib/bootstrap-tour/bootstrap-tour.js"></script>
|
|
||||||
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
|
<!-- mutation observers shim backed by mutation events (8 < IE < 11, Safari < 6, FF < 14, Chrome < 17) -->
|
||||||
<script type="text/javascript" src="/website/static/lib//jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
|
<script type="text/javascript" src="/website/static/lib//jquery.mjs.nestedSortable/jquery.mjs.nestedSortable.js"></script>
|
||||||
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
|
<script type="text/javascript" src="/website/static/lib/MutationObservers/test/sidetable.js"></script>
|
||||||
|
|
|
@ -3,92 +3,87 @@
|
||||||
|
|
||||||
var website = openerp.website;
|
var website = openerp.website;
|
||||||
|
|
||||||
website.Tour.ShopTest = website.Tour.extend({
|
website.Tour.register({
|
||||||
id: 'shop_buy_product',
|
id: 'shop_buy_product',
|
||||||
name: "Try to buy products",
|
name: "Try to buy products",
|
||||||
path: '/shop',
|
path: '/shop',
|
||||||
init: function () {
|
mode: 'test',
|
||||||
var self = this;
|
steps: [
|
||||||
self.steps = [
|
{
|
||||||
{
|
title: "select ipod",
|
||||||
title: "select ipod",
|
element: '.oe_product_cart a:contains("iPod")',
|
||||||
element: '.oe_product_cart a:contains("iPod")',
|
},
|
||||||
|
{
|
||||||
|
title: "select ipod 32Go",
|
||||||
|
element: 'input[name="product_id"]:not([checked])',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "click on add to cart",
|
||||||
|
waitFor: 'input[name="product_id"]:eq(1)[checked]',
|
||||||
|
element: 'form[action="/shop/add_cart"] .btn',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "add suggested",
|
||||||
|
element: 'form[action="/shop/add_cart"] .btn-link:contains("Add to Cart")',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "add one more iPod",
|
||||||
|
waitFor: '.my_cart_quantity:contains(2)',
|
||||||
|
element: '#mycart_products tr:contains("iPod: 32 Gb") a.js_add_cart_json:eq(1)',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "remove Headphones",
|
||||||
|
waitFor: '#mycart_products tr:contains("iPod: 32 Gb") input.js_quantity[value=2]',
|
||||||
|
element: '#mycart_products tr:contains("Apple In-Ear Headphones") a.js_add_cart_json:first',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "set one iPod",
|
||||||
|
waitNot: '#mycart_products tr:contains("Apple In-Ear Headphones")',
|
||||||
|
element: '#mycart_products input.js_quantity',
|
||||||
|
sampleText: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "go to checkout",
|
||||||
|
waitFor: '#mycart_products input.js_quantity[value=1]',
|
||||||
|
element: 'a[href="/shop/checkout"]',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "test with input error",
|
||||||
|
element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")',
|
||||||
|
onload: function (tour) {
|
||||||
|
$("input[name='phone']").val("");
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
title: "select ipod 32Go",
|
{
|
||||||
element: 'input[name="product_id"]:not([checked])',
|
title: "test without input error",
|
||||||
|
waitFor: 'form[action="/shop/confirm_order"] .has-error',
|
||||||
|
element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")',
|
||||||
|
onload: function (tour) {
|
||||||
|
if ($("input[name='name']").val() === "")
|
||||||
|
$("input[name='name']").val("website_sale-test-shoptest");
|
||||||
|
if ($("input[name='email']").val() === "")
|
||||||
|
$("input[name='email']").val("website_sale_test_shoptest@websitesaletest.optenerp.com");
|
||||||
|
$("input[name='phone']").val("123");
|
||||||
|
$("input[name='street']").val("123");
|
||||||
|
$("input[name='city']").val("123");
|
||||||
|
$("input[name='zip']").val("123");
|
||||||
|
$("select[name='country_id']").val("21");
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
title: "click on add to cart",
|
{
|
||||||
waitFor: 'input[name="product_id"]:eq(1)[checked]',
|
title: "select payment",
|
||||||
element: 'form[action="/shop/add_cart"] .btn',
|
element: '#payment_method label:has(img[title="Wire Transfer"]) input',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "add suggested",
|
title: "Pay Now",
|
||||||
element: 'form[action="/shop/add_cart"] .btn-link:contains("Add to Cart")',
|
waitFor: '#payment_method label:has(input:checked):has(img[title="Wire Transfer"])',
|
||||||
},
|
element: '.oe_sale_acquirer_button .btn[name="submit"]:visible',
|
||||||
{
|
},
|
||||||
title: "add one more iPod",
|
{
|
||||||
waitFor: '.my_cart_quantity:contains(2)',
|
title: "finish",
|
||||||
element: '#mycart_products tr:contains("iPod: 32 Gb") a.js_add_cart_json:eq(1)',
|
waitFor: '.oe_website_sale:contains("Thank you for your order")',
|
||||||
},
|
}
|
||||||
{
|
]
|
||||||
title: "remove Headphones",
|
|
||||||
waitFor: '#mycart_products tr:contains("iPod: 32 Gb") input.js_quantity[value=2]',
|
|
||||||
element: '#mycart_products tr:contains("Apple In-Ear Headphones") a.js_add_cart_json:first',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "set one iPod",
|
|
||||||
waitNot: '#mycart_products tr:contains("Apple In-Ear Headphones")',
|
|
||||||
element: '#mycart_products input.js_quantity',
|
|
||||||
sampleText: '1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "go to checkout",
|
|
||||||
waitFor: '#mycart_products input.js_quantity[value=1]',
|
|
||||||
element: 'a[href="/shop/checkout"]',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "test with input error",
|
|
||||||
element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")',
|
|
||||||
onload: function (tour) {
|
|
||||||
$("input[name='phone']").val("");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "test without input error",
|
|
||||||
waitFor: 'form[action="/shop/confirm_order"] .has-error',
|
|
||||||
element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")',
|
|
||||||
onload: function (tour) {
|
|
||||||
if ($("input[name='name']").val() === "")
|
|
||||||
$("input[name='name']").val("website_sale-test-shoptest");
|
|
||||||
if ($("input[name='email']").val() === "")
|
|
||||||
$("input[name='email']").val("website_sale_test_shoptest@websitesaletest.optenerp.com");
|
|
||||||
$("input[name='phone']").val("123");
|
|
||||||
$("input[name='street']").val("123");
|
|
||||||
$("input[name='city']").val("123");
|
|
||||||
$("input[name='zip']").val("123");
|
|
||||||
$("select[name='country_id']").val("21");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "select payment",
|
|
||||||
element: '#payment_method label:has(img[title="Wire Transfer"]) input',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Pay Now",
|
|
||||||
waitFor: '#payment_method label:has(input:checked):has(img[title="Wire Transfer"])',
|
|
||||||
element: '.oe_sale_acquirer_button .btn[name="submit"]:visible',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "finish",
|
|
||||||
waitFor: '.oe_website_sale:contains("Thank you for your order")',
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// for test without editor bar
|
|
||||||
website.Tour.add(website.Tour.ShopTest);
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -4,125 +4,114 @@
|
||||||
var website = openerp.website;
|
var website = openerp.website;
|
||||||
var _t = openerp._t;
|
var _t = openerp._t;
|
||||||
|
|
||||||
website.EditorBar.include({
|
website.Tour.register({
|
||||||
start: function () {
|
|
||||||
this.registerTour(new website.Tour.Shop(this));
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
website.Tour.Shop = website.Tour.extend({
|
|
||||||
id: 'shop',
|
id: 'shop',
|
||||||
name: "Create a product",
|
name: _t("Create a product"),
|
||||||
testPath: '/shop',
|
steps: [
|
||||||
init: function () {
|
{
|
||||||
var self = this;
|
title: _t("Welcome to your shop"),
|
||||||
self.steps = [
|
content: _t("You successfully installed the e-commerce. This guide will help you to create your product and promote your sales."),
|
||||||
{
|
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
||||||
title: _t("Welcome to your shop"),
|
},
|
||||||
content: _t("You successfully installed the e-commerce. This guide will help you to create your product and promote your sales."),
|
{
|
||||||
popover: { next: _t("Start Tutorial"), end: _t("Skip It") },
|
element: '#content-menu-button',
|
||||||
},
|
placement: 'left',
|
||||||
{
|
title: _t("Create your first product"),
|
||||||
element: '#content-menu-button',
|
content: _t("Click here to add a new product."),
|
||||||
placement: 'left',
|
popover: { fixed: true },
|
||||||
title: _t("Create your first product"),
|
},
|
||||||
content: _t("Click here to add a new product."),
|
{
|
||||||
popover: { fixed: true },
|
element: 'a[data-action=new_product]',
|
||||||
},
|
placement: 'left',
|
||||||
{
|
title: _t("Create a new product"),
|
||||||
element: 'a[data-action=new_product]',
|
content: _t("Select 'New Product' to create it and manage its properties to boost your sales."),
|
||||||
placement: 'left',
|
popover: { fixed: true },
|
||||||
title: _t("Create a new product"),
|
},
|
||||||
content: _t("Select 'New Product' to create it and manage its properties to boost your sales."),
|
{
|
||||||
popover: { fixed: true },
|
element: '.modal #editor_new_product input[type=text]',
|
||||||
},
|
sampleText: 'New Product',
|
||||||
{
|
placement: 'right',
|
||||||
element: '.modal #editor_new_product input[type=text]',
|
title: _t("Choose name"),
|
||||||
sampleText: 'New Product',
|
content: _t("Enter a name for your new product then click 'Continue'."),
|
||||||
placement: 'right',
|
},
|
||||||
title: _t("Choose name"),
|
{
|
||||||
content: _t("Enter a name for your new product then click 'Continue'."),
|
waitNot: '.modal input[type=text]:not([value!=""])',
|
||||||
},
|
element: '.modal button.btn-primary',
|
||||||
{
|
placement: 'right',
|
||||||
waitNot: '.modal input[type=text]:not([value!=""])',
|
title: _t("Create Product"),
|
||||||
element: '.modal button.btn-primary',
|
content: _t("Click <em>Continue</em> to create the product."),
|
||||||
placement: 'right',
|
},
|
||||||
title: _t("Create Product"),
|
{
|
||||||
content: _t("Click <em>Continue</em> to create the product."),
|
waitFor: 'body:has(button[data-action=save]:visible):has(.js_sale)',
|
||||||
},
|
title: _t("New product created"),
|
||||||
{
|
content: _t("This page contains all the information related to the new product."),
|
||||||
waitFor: 'body:has(button[data-action=save]:visible):has(.js_sale)',
|
popover: { next: _t("Continue") },
|
||||||
title: _t("New product created"),
|
},
|
||||||
content: _t("This page contains all the information related to the new product."),
|
{
|
||||||
popover: { next: _t("Continue") },
|
element: '.product_price .oe_currency_value',
|
||||||
},
|
sampleText: '20.50',
|
||||||
{
|
placement: 'left',
|
||||||
element: '.product_price .oe_currency_value',
|
title: _t("Change the price"),
|
||||||
sampleText: '20.50',
|
content: _t("Edit the price of this product by clicking on the amount."),
|
||||||
placement: 'left',
|
},
|
||||||
title: _t("Change the price"),
|
|
||||||
content: _t("Edit the price of this product by clicking on the amount."),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
waitNot: '.product_price .oe_currency_value:containsExact(1.00)',
|
|
||||||
element: '#wrap img.product_detail_img',
|
|
||||||
placement: 'top',
|
|
||||||
title: _t("Update image"),
|
|
||||||
content: _t("Click here to set an image describing your product."),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: 'img[alt=ipad]',
|
|
||||||
placement: 'top',
|
|
||||||
title: _t("Select an Image"),
|
|
||||||
content: _t("Let's select an ipad image."),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
waitFor: '.media_selected img[alt=ipad]',
|
|
||||||
element: '.modal-content button.save',
|
|
||||||
placement: 'top',
|
|
||||||
title: _t("Save this Image"),
|
|
||||||
content: _t("Click on save to add the image to the product decsription."),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
waitNot: '.modal-content:visible',
|
|
||||||
element: 'button[data-action=snippet]',
|
|
||||||
placement: 'bottom',
|
|
||||||
title: _t("Describe the Product"),
|
|
||||||
content: _t("Insert blocks like text-image, or gallery to fully describe the product."),
|
|
||||||
popover: { fixed: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
snippet: '#snippet_structure .oe_snippet:eq(7)',
|
|
||||||
placement: 'bottom',
|
|
||||||
title: _t("Drag & Drop a block"),
|
|
||||||
content: _t("Drag the 'Big Picture' block and drop it in your page."),
|
|
||||||
popover: { fixed: true },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
element: 'button[data-action=save]',
|
|
||||||
placement: 'right',
|
|
||||||
title: _t("Save your modifications"),
|
|
||||||
content: _t("Once you click on save, your product is updated."),
|
|
||||||
popover: { fixed: true },
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
waitFor: '#website-top-navbar button[data-action="edit"]:visible',
|
waitNot: '.product_price .oe_currency_value:containsExact(1.00)',
|
||||||
element: '.js_publish_management button.js_publish_btn.btn-danger',
|
element: '#wrap img.product_detail_img',
|
||||||
placement: 'top',
|
placement: 'top',
|
||||||
title: _t("Publish your product"),
|
title: _t("Update image"),
|
||||||
content: _t("Click to publish your product so your customers can see it."),
|
content: _t("Click here to set an image describing your product."),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
waitFor: '.js_publish_management button.js_publish_btn.btn-success:visible',
|
element: 'img[alt=ipad]',
|
||||||
title: _t("Congratulations"),
|
placement: 'top',
|
||||||
content: _t("Congratulations! You just created and published your first product."),
|
title: _t("Select an Image"),
|
||||||
popover: { next: _t("Close Tutorial") },
|
content: _t("Let's select an ipad image."),
|
||||||
},
|
},
|
||||||
];
|
{
|
||||||
return this._super();
|
waitFor: '.media_selected img[alt=ipad]',
|
||||||
}
|
element: '.modal-content button.save',
|
||||||
|
placement: 'top',
|
||||||
|
title: _t("Save this Image"),
|
||||||
|
content: _t("Click on save to add the image to the product decsription."),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
waitNot: '.modal-content:visible',
|
||||||
|
element: 'button[data-action=snippet]',
|
||||||
|
placement: 'bottom',
|
||||||
|
title: _t("Describe the Product"),
|
||||||
|
content: _t("Insert blocks like text-image, or gallery to fully describe the product."),
|
||||||
|
popover: { fixed: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
snippet: '#snippet_structure .oe_snippet:eq(7)',
|
||||||
|
placement: 'bottom',
|
||||||
|
title: _t("Drag & Drop a block"),
|
||||||
|
content: _t("Drag the 'Big Picture' block and drop it in your page."),
|
||||||
|
popover: { fixed: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
element: 'button[data-action=save]',
|
||||||
|
placement: 'right',
|
||||||
|
title: _t("Save your modifications"),
|
||||||
|
content: _t("Once you click on save, your product is updated."),
|
||||||
|
popover: { fixed: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
waitFor: '#website-top-navbar button[data-action="edit"]:visible',
|
||||||
|
element: '.js_publish_management button.js_publish_btn.btn-danger',
|
||||||
|
placement: 'top',
|
||||||
|
title: _t("Publish your product"),
|
||||||
|
content: _t("Click to publish your product so your customers can see it."),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
waitFor: '.js_publish_management button.js_publish_btn.btn-success:visible',
|
||||||
|
title: _t("Congratulations"),
|
||||||
|
content: _t("Congratulations! You just created and published your first product."),
|
||||||
|
popover: { next: _t("Close Tutorial") },
|
||||||
|
},
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -11,13 +11,13 @@ inject = [
|
||||||
@openerp.tests.common.post_install(True)
|
@openerp.tests.common.post_install(True)
|
||||||
class TestUi(openerp.tests.HttpCase):
|
class TestUi(openerp.tests.HttpCase):
|
||||||
def test_01_admin_shop_tour(self):
|
def test_01_admin_shop_tour(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('shop')", "openerp.website.Tour.Shop", login="admin")
|
self.phantom_js("/", "openerp.website.Tour.run('shop', 'test')", "openerp.website.Tour.tours.shop", login="admin")
|
||||||
|
|
||||||
def test_02_admin_checkout(self):
|
def test_02_admin_checkout(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('shop_buy_product')", "openerp.website.Tour.ShopTest", login="admin", inject=inject)
|
self.phantom_js("/", "openerp.website.Tour.run('shop_buy_product', 'test')", "openerp.website.Tour.tours.shop_buy_product", login="admin", inject=inject)
|
||||||
|
|
||||||
def test_03_demo_checkout(self):
|
def test_03_demo_checkout(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('shop_buy_product')", "openerp.website.Tour.ShopTest", login="demo", inject=inject)
|
self.phantom_js("/", "openerp.website.Tour.run('shop_buy_product', 'test')", "openerp.website.Tour.tours.shop_buy_product", login="demo", inject=inject)
|
||||||
|
|
||||||
def test_04_public_checkout(self):
|
def test_04_public_checkout(self):
|
||||||
self.phantom_js("/", "openerp.website.Tour.run_test('shop_buy_product')", "openerp.website.Tour.ShopTest", inject=inject)
|
self.phantom_js("/", "openerp.website.Tour.run('shop_buy_product', 'test')", "openerp.website.Tour.tours.shop_buy_product", inject=inject)
|
||||||
|
|
Loading…
Reference in New Issue