This commit prevents from erasing the origin part of the url
when the tour manager does a redirection. This was an issue in
phantomjs if it allows local url as in this case, it will try to
load file://<tour_url> instead of <origin><tour_url>.
Since commit 8ac1c19fac7615fecd51e670f798d13158a4e53c the odoo brand primary color
changed, which also changed the color of tips. The problem
was that they lose a lot of contrast in the appswitcher.
When users switch from one version to another, the localstorage is not
cleared and users can get errors because the tour manager is trying to
load steps (according to the localstorage content) which could not
exist anymore.
This could also happen when a module which extends another module tour
is installed.
* The debug manager contains a feature to launch tours, adapt it
to new web_tour.tour system
* The website help menu allowed to relaunch tutorial tour in debug
mode. This feature is not adapted to new tour system and was useless
in the first place (debug mode in frontend is barely used anyway).
-> remove the website help menu and the feature
Previous implementation was checking if the element we want to click
on is a link and if this is the case, only forced a redirection. This
had been done because the redirection was not working by simulating a
click, but in fact it works, the click simulation only had to be
improved.
Also, only forcing a redirection is wrong as some links have both a
real redirection link and a event handler binded to them.
When checking for a DOM element in a run method thanks to the action
helper, visible elements are now considered first, then, if none is
found, we take the first invisible one.
Previous implementation allowed to run tour as a non-superuser but
this was only working in the backend where the static file tip.xml
is always loaded. In the frontend or in other non-backend context,
this file has to be loaded just before trying to launch the tour as
a non superuser (indeed, previous implementation loaded the file in
the frontend only if the user is a superuser).
* crm, project, website, website_event, website_blog, website_forum,
website_sale
Eg: the tour 'shop_buy_product' is extended by the website_sale_options
addons to add a step to close a modal.
The current solution was requiring the module that defines the tour
to extend, then add/remove steps in the "step" key of the tour
definition.
Some of the problems with this method were:
* The "register" method calls the "update" method to immediately
search for tip to place once registered (as register may be called
after the DOM is ready). So extensions of tours were happening after
the tours were started (and the tours were not restarted).
* The addition/removal of steps was happening after they were filtered
according to the "edition" key.
To allow extension, the system is changed as follow:
* The "register" method now only saves the steps and options without
modifying them and does not call the "update" method.
* Once the DOM was ready, the tour service started listening to DOM
mutations and called the "update" tour method. Now, this "update" call
is replaced by a "_register_all" call, on DOM ready and at the end of
the current call stack (which makes sure all modules are loaded). This
"_register_all" method marks the registered tours as ready after having
filtered the steps according to the "edition" key and initialized the
current step to trigger.
* Also, tours can now define a "wait_for" option which allow them to
be marked as ready for run and update after the given deferred. Those
tours can now also be extended without having to wait for the deferred.
PhamtomJS must wait for the "ready" key to be true to run the tour.
If a tour step action induces a direct redirection the _consume_tip
method was called while the redirection was being done. Now,
_consume_tip is always called before any redirection really begins.
Note: as the run method also has to detect redirections and do actions
according to if there is one or not, a function has been created to
implement the redirection detection.
The change event has to be triggered when changing an input, a select
and even another DOM element with contentEditable attribute.
When changing an input, the "keydown" and "keyup" events also had to
be triggered.
Previous simulation was "mousedown" then "mouseup" then "click". It is
not enough for some feature (like bootstrap, web_editor...). These rely
to have a "mouseenter" before and a "mouseleave" after the click.
The default action for a tour step whose trigger is a <a/> tag is:
* Redirection to the a href if it is a valid link
* Clicking on it if the <a/> is used as a handler-binded button
The previous condition forgot to consider href="javascript:void(0)" as
a non-valid redirection link.
When checking the consume type of an input element, the type attribute
was checked. Indeed a "text" input has a "input" consume event, while
a "button" input has a "mousedown" consume event. The problem here was
that when the input has no type, the "mousedown" consume event was
chosen while the default type for input is "text" for browsers.
When searching the ideal location for a tip on the body or the html
element, the previous implementation was wrong. In that case, the ideal
location is always the body.
Instead of logging "Killing tour x" when calling the run method a
second time and then logging "ok" when consuming the old running tour,
the message "Killing tour x" is now logged as an error for phamtomJS.
Also, let "x" be the tour which is killed and not the one which wanted
to be runned.
The previous implementation took the parent of the element to begin
the check, which was wrong when the initial element was the html root.
This commit changes the method to a recursive implementation, which is
clearer.
When checking the DOM for tour step trigger, the ":visible" jQuery
filter was used to get the visible elements. The problem is that this
filter does not care about the visibility css property. So, for jQuery,
a display:block and visibility:hidden element is visible.
This was an issue as kanban ghosts or settings panels in odoo are
hidden thanks to the visibility property instead of display.
When a modal is open, we only activate tips that are inside the modal.
The former solution didn't work when the tip's selector contains ','
(often used when the selector is different in community and enterprise,
e.g. selectors for apps), because the modal restriction was only
applied on the first part of the selector.
Changes the api of the consume method on the web_tour.tour model so that it
now takes in argument an array of tour names instead of a single tour name.
This is done in order to enable the tour service only for the
superuser. Commit 6ef1644a7b changed the meaning of `is_admin`
to achieve this but broke the fact that some features of the debug
manager are available to admin and not only to the superuser. Anyway
a `is_admin` key should mean that the user is in the admin group.
We could have checked client side that the uid is equal to 1 but
adding a `is_superuser` key is more elegant and easier to grep.
Also fix the only occurence of a uid check in the weblcient.
This reverts commit 6ef1644a7b.
Force tooltip content font style (size, family, line-height, weight)
so that it does not depend on where the tooltip is in the DOM.
This fixes a problem where the style changed when opening/closing the
tooltip. Indeed, the content dimensions, computed in javascript when
the tooltip is closed were wrong because of the style and the opening
/ closing rely on these values.
Tours can now be launched flawlessly thanks to the run method of the
tour service.
In a tour definition, here what you might have to do to make it
functionnal in auto mode:
* If actions are required between two steps of an onboarding tour:
* If the actions have to wait for elements to appear on the screen,
define new tour steps with no content and add the "auto" key
and set it to "true".
* If the actions concern elements which are already on the screen,
you can use the "run" key in a step to make the tour faster to
execute actions after the step.
The "run" key may take several values:
* A string with the values "click", "text" or "drag_and_drop". By
default, you will not have to specify "click" for normal elements
or "text" for form elements as they are the default values for
those. Note: the "text" value can be followed by the text to enter
(default to "Test") and the "drag_and_drop" value can be followed
by a jQuery selector to specify where to drop the element (default
to the body element).
* A function which takes an "actions" parameter. This allowed to do
anything but here are common uses in the run definition :
* a call to "actions.auto()" will do the default action on the
step element (click on normal element and add text on form
elements).
* a call to "actions.auto(element)" will do the default action on
the given element. Note: this.$anchor is a reference to the
step jQuery element.
* a call to "actions.text([text], [element])" will add the optional
text (default to "Test") to the optional given element (default
to the step element).
* a call to "actions.click([element])" will click on the optional
given element (default to the step element).
* a call to "actions.drag_and_drop([to], [element])" will drag and
drop the optional given element (default to the step element) in
the optional given "to" element (default to the body element).
Note 1: all the "element" parameters can be given as a jQuery selector,
a DOM node or a jQuery element.
Note 2: the run method is designed to do actions on elements which are
already on the screen. If this is not the case for some of them,
consider using an "auto: true" step as explained above.
Note 3: "auto: true" steps can also contain a run definition.
When defining a tour, you can also add predefined steps (auto or not).
These are defined in the object STEPS of the tour service object. These
include opening the "More" menu if any in community before clicking on
an app, opening the appswitcher in enterprise, ...
The full list is accessible in the tour_manager.js file.
Backport of 1 second late commit in master.
* Remove the "?" content
* Use a background gradient
* Use a bottom transparent box-shadow instead of a surrounding opaque one
* Reduce tip size and reshape the arrow
The tip was currently placed in the first parent which can scroll.
This is wrong if there is a parent which is position:fixed in that
element which scrolls (as it would not follow the scrolling as it is
fixed).
The ideal location is now the first parent which can scroll or which
is position:fixed.
Note: there are still two cases which may not work but they are
considered rare enough to not handle them :
* A position:fixed element which is overflow:hidden too
* A position:absolute element whose relative ancestor is an ancestor
of the ancestor element which can scroll.
Allows to define steps that only apply either in community or enterprise, by
setting the step's attribute 'edition' to 'community' or 'enterprise'.
If the attribute is not set, the step applies on both edition.
Before this commit, tours were disabled for mobile mode by returning
an undefined value in the web_tour.tour JS module. This made the use
of "tour.register" or "tour.run" crash, thus making the runbot go red
if this happened while phamtomJS was running.
As it happened, some of the frontend tours goes by "preview the site
on mobile mode" which then trigger this JS crash.
This commit makes the web_tour.tour module return a fake tour object
with a register method which does nothing and a run method which
warns the user that tours cannot be launched in mobile mode.
Choosing where to place a tip is a difficult problem.
If placed in the body element, the tip have to be repositionned on each
scroll event which is performance-consuming and induces bugs (firefox
scroll event, tips which is over an element while the anchor is under,
...).
If placed in the anchor parent which scrolls, all the above problems
are solved but when the tip opens it cannot overflow its parent
boundaries, which is not possible in many contexts (modals, ...).
The solution here is to change the tip location when it opens/closes.
When closed, it is placed in the anchor parent which scrolls. This
allows to not have to reposition the tip on each scroll. The tip is
also naturally hidden when its anchor is not visible on the screen.
When opened, the tip is placed in the body, where it can be placed
on the top of anything in the DOM.
The transition from one state to another is not noticable as the
position does not have to be computed when the tip is moved in the
DOM and the animation is purely CSS.
Note: however, this commit does not solve the firefox bug of closing
the tip when the window scrolls. Here, the temporary solution is to
let the tip be wrongly position if the user scrolls when a tip is
opened (this only occurs when using the mouse wheel anyway).
Before being positionned, the tip is at the end of the body, thus
adding a scrollbar... which prevents to calculate the correct x
position of the tip.
The chosen solution is to place the tip at the center of the screen
in LESS before the first positionning. This also prevents the content
to overflow the body and does not break animation of the tip as its
display property is always block.
* Correctly bind "input" (instead of "change") or "mousedown" event
according to the anchor type. Also, only valids left clicks.
* Correctly unbind these events.
* Adapt code to handle position/width/padding with pixel-precision
* Adapt overlay to not overflow the screen
* Do not let the content overflow the tip when closed