From be4aba7d8f6dccd1ab7e1152d8c00378b69359fe Mon Sep 17 00:00:00 2001 From: Darshan Kalola Date: Mon, 19 Aug 2013 14:13:04 +0530 Subject: [PATCH 001/248] [IMP]improve onchange behaviour when creating partner or contact bzr revid: darshankalola@gmail.com-20130819084304-5jxrvmu8on3fzm2j --- openerp/addons/base/res/res_partner_view.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/res/res_partner_view.xml b/openerp/addons/base/res/res_partner_view.xml index f02021313c0..a032ecfe4db 100644 --- a/openerp/addons/base/res/res_partner_view.xml +++ b/openerp/addons/base/res/res_partner_view.xml @@ -140,8 +140,7 @@ + attrs="{'invisible': [('is_company','=', True),('parent_id', '=', False)]}"/>
@@ -188,7 +187,7 @@ - + From a0ab757537f00b84eee25c837b86bb7df64ebe91 Mon Sep 17 00:00:00 2001 From: "ajay javiya (OpenERP)" Date: Thu, 22 Aug 2013 14:52:59 +0530 Subject: [PATCH 002/248] [REM] : remove wizard of schedule/log a call , [IMP] : Rename in Opportunity and in Partner form the 'Meeting' into 'Schedule a Meeting' , bzr revid: aja@tinyerp.com-20130822092259-it5a1e1v1ed9s60a --- addons/crm/__openerp__.py | 2 - addons/crm/crm_lead_view.xml | 17 ++-- addons/crm/res_config.py | 3 + addons/crm/res_config_view.xml | 4 + addons/crm/res_partner_view.xml | 2 +- addons/crm/security/crm_security.xml | 5 ++ addons/crm/test/lead2opportunity2win.yml | 2 +- addons/crm/wizard/__init__.py | 1 - .../wizard/crm_opportunity_to_phonecall.py | 77 ------------------- .../crm_opportunity_to_phonecall_view.xml | 52 ------------- 10 files changed, 23 insertions(+), 142 deletions(-) delete mode 100644 addons/crm/wizard/crm_opportunity_to_phonecall.py delete mode 100644 addons/crm/wizard/crm_opportunity_to_phonecall_view.xml diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py index 1b4ba191b82..ad82595715a 100644 --- a/addons/crm/__openerp__.py +++ b/addons/crm/__openerp__.py @@ -71,8 +71,6 @@ Dashboard for CRM will include: 'wizard/crm_phonecall_to_phonecall_view.xml', - 'wizard/crm_opportunity_to_phonecall_view.xml', - 'wizard/crm_merge_opportunities_view.xml', 'crm_view.xml', diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 849cecaac85..0e5c819f2d2 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -103,9 +103,9 @@
-
diff --git a/addons/crm/res_partner_view.xml b/addons/crm/res_partner_view.xml index 8b941a395dd..9755f938bec 100644 --- a/addons/crm/res_partner_view.xml +++ b/addons/crm/res_partner_view.xml @@ -95,7 +95,7 @@ name="%(crm.crm_case_category_act_oppor11)d" context="{'search_default_partner_id': active_id}"/> ", - 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 - }; +(function($, window) { + var Tour, document; + document = window.document; + Tour = (function() { + function Tour(options) { + this._options = $.extend({ + name: "tour", + steps: [], + container: "body", + keyboard: true, + storage: window.localStorage, + debug: false, + backdrop: false, + redirect: true, + orphan: false, + duration: false, + basePath: "", + template: "

", + 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) {}, + onPause: function(tour, duration) {}, + onResume: function(tour, duration) {} + }, options); + this._force = false; + this._inited = false; + this.backdrop = { + overlay: null, + $element: null, + $background: null, + backgroundShown: false, + overlayElementShown: false + }; + this; + } + + Tour.prototype.addSteps = function(steps) { + var step, _i, _len; + for (_i = 0, _len = steps.length; _i < _len; _i++) { + step = steps[_i]; + this.addStep(step); } + return this; + }; - 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.addStep = function(step) { + this._options.steps.push(step); + return this; + }; - 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.getStep = function(i) { + if (this._options.steps[i] != null) { + return $.extend({ + id: "step-" + i, + path: "", + placement: "right", + title: "", + content: "

", + next: i === this._options.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, + duration: this._options.duration, + 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, + onPause: this._options.onPause, + onResume: this._options.onResume + }, this._options.steps[i]); + } + }; - 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: "

", - 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() { + Tour.prototype.init = function(force) { + this._force = force; + if (this.ended()) { + this._debug("Tour ended, init prevented."); + return this; + } + this.setCurrentStep(); + this._initMouseNavigation(); + this._initKeyboardNavigation(); + this._onResize((function(_this) { + return function() { return _this.showStep(_this._current); - }); - this._setupKeyboardNavigation(); + }; + })(this)); + if (this._current !== null) { + this.showStep(this._current); + } + this._inited = true; + return this; + }; + + Tour.prototype.start = function(force) { + var promise; + if (force == null) { + force = false; + } + if (!this._inited) { + this.init(force); + } + if (this._current === null) { promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0); - return this._callOnPromiseDone(promise, this.showStep, this._current); - }; + this._callOnPromiseDone(promise, this.showStep, 0); + } + return this; + }; - 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.next = function() { + var promise; + 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.prev = function() { + var promise; + 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.goTo = function(i) { + var promise; + promise = this.hideStep(this._current); + return this._callOnPromiseDone(promise, this.showStep, i); + }; - Tour.prototype.end = function() { - var endHelper, hidePromise, - _this = this; - endHelper = function(e) { + Tour.prototype.end = function() { + var endHelper, promise; + endHelper = (function(_this) { + return 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"); + _this._setState("end", "yes"); + _this._inited = false; + _this._force = false; + _this._clearTimer(); if (_this._options.onEnd != null) { return _this._options.onEnd(_this); } }; - hidePromise = this.hideStep(this._current); - return this._callOnPromiseDone(hidePromise, endHelper); - }; + })(this); + promise = this.hideStep(this._current); + return this._callOnPromiseDone(promise, endHelper); + }; - Tour.prototype.ended = function() { - return !!this.getState("end"); - }; + Tour.prototype.ended = function() { + return !this._force && !!this._getState("end"); + }; - Tour.prototype.restart = function() { - this.removeState("current_step"); - this.removeState("end"); - this.setCurrentStep(0); - return this.start(); - }; + 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) { + Tour.prototype.pause = function() { + var step; + step = this.getStep(this._current); + if (!(step && step.duration)) { + return this; + } + this._paused = true; + this._duration -= new Date().getTime() - this._start; + window.clearTimeout(this._timer); + this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining)."); + if (step.onPause != null) { + return step.onPause(this, this._duration); + } + }; + + Tour.prototype.resume = function() { + var step; + step = this.getStep(this._current); + if (!(step && step.duration)) { + return this; + } + this._paused = false; + this._start = new Date().getTime(); + this._duration = this._duration || step.duration; + this._timer = window.setTimeout((function(_this) { + return function() { + if (_this._isLast()) { + return _this.next(); + } else { + return _this.end(); + } + }; + })(this), this._duration); + this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration); + if ((step.onResume != null) && this._duration !== step.duration) { + return step.onResume(this, this._duration); + } + }; + + Tour.prototype.hideStep = function(i) { + var hideStepHelper, promise, step; + step = this.getStep(i); + if (!step) { + return; + } + this._clearTimer(); + promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0); + hideStepHelper = (function(_this) { + return function(e) { var $element; - $element = _this._isOrphan(step) ? $("body") : $(step.element); - $element.popover("destroy"); + $element = $(step.element); + if (!($element.data("bs.popover") || $element.data("popover"))) { + $element = $("body"); + } + $element.popover("destroy").removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element"); if (step.reflex) { $element.css("cursor", "").off("click.tour-" + _this._options.name); } @@ -240,23 +253,37 @@ return step.onHidden(_this); } }; - this._callOnPromiseDone(promise, hideStepHelper); - return promise; - }; + })(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) { + Tour.prototype.showStep = function(i) { + var promise, showStepHelper, skipToPrevious, step; + if (this.ended()) { + this._debug("Tour ended, showStep prevented."); + return 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(_this) { + return function(e) { var current_path, path; _this.setCurrentStep(i); - path = $.isFunction(step.path) ? step.path.call() : _this._options.basePath + step.path; + path = (function() { + switch ({}.toString.call(step.path)) { + case "[object Function]": + return step.path(); + case "[object String]": + return this._options.basePath + step.path; + default: + return step.path; + } + }).call(_this); current_path = [document.location.pathname, document.location.hash].join(""); if (_this._isRedirect(path, current_path)) { _this._redirect(step, path); @@ -277,283 +304,413 @@ if (step.backdrop) { _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0); } - _this._showPopover(step, i); - if (step.onShown != null) { - step.onShown(_this); + _this._scrollIntoView(step.element, function() { + if ((step.element != null) && step.backdrop) { + _this._showOverlayElement(step.element); + } + _this._showPopover(step, i); + if (step.onShown != null) { + step.onShown(_this); + } + return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length); + }); + if (step.duration) { + return _this.resume(); } - return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length); }; - return this._callOnPromiseDone(promise, showStepHelper); - }; + })(this); + this._callOnPromiseDone(promise, showStepHelper); + return promise; + }; - 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.getCurrentStep = function() { + return this._current; + }; + + Tour.prototype.setCurrentStep = function(value) { + if (value != null) { + this._current = value; + this._setState("current_step", value); + } else { + this._current = this._getState("current_step"); + this._current = this._current === null ? null : parseInt(this._current, 10); + } + return this; + }; + + Tour.prototype._setState = function(key, value) { + var e, keyName; + if (this._options.storage) { + keyName = "" + this._options.name + "_" + key; + try { + this._options.storage.setItem(keyName, value); + } catch (_error) { + e = _error; + if (e.code === DOMException.QUOTA_EXCEEDED_ERR) { + this.debug("LocalStorage quota exceeded. State storage failed."); + } } - }; + return this._options.afterSetState(keyName, value); + } else { + if (this._state == null) { + this._state = {}; + } + return this._state[key] = value; + } + }; - Tour.prototype._showNextStep = function() { - var promise, showNextStepHelper, step, - _this = this; - step = this.getStep(this._current); - showNextStepHelper = function(e) { + 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._showNextStep = function() { + var promise, showNextStepHelper, step; + step = this.getStep(this._current); + showNextStepHelper = (function(_this) { + return function(e) { return _this.showStep(step.next); }; - promise = this._makePromise((step.onNext != null ? step.onNext(this) : void 0)); - return this._callOnPromiseDone(promise, showNextStepHelper); - }; + })(this); + 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) { + Tour.prototype._showPrevStep = function() { + var promise, showPrevStepHelper, step; + step = this.getStep(this._current); + showPrevStepHelper = (function(_this) { + return function(e) { return _this.showStep(step.prev); }; - promise = this._makePromise((step.onPrev != null ? step.onPrev(this) : void 0)); - return this._callOnPromiseDone(promise, showPrevStepHelper); - }; + })(this); + 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._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._isRedirect = function(path, currentPath) { + return (path != null) && path !== "" && ((toString.call(path) === "[object RegExp]" && !path.test(currentPath)) || (toString.call(path) === "[object String]" && 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._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._isOrphan = function(step) { + return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg"); + }; - 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) { + Tour.prototype._isLast = function() { + return this._current < this._options.steps.length - 1; + }; + + Tour.prototype._showPopover = function(step, i) { + var $element, $navigation, $template, $tip, isOrphan, options; + 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>*:last"; + step.placement = "top"; + $template = $template.addClass("orphan"); + } + $element = $(step.element); + $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i); + $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element"); + if (step.options) { + $.extend(options, step.options); + } + if (step.reflex) { + $element.css("cursor", "pointer").on("click.tour-" + this._options.name, (function(_this) { + return function() { + if (_this._isLast()) { 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("
").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); - } - }; + }; + })(this)); + } + if (step.prev < 0) { + $navigation.find("[data-role='prev']").addClass("disabled"); + } + if (step.next < 0) { + $navigation.find("[data-role='next']").addClass("disabled"); + } + if (!step.duration) { + $navigation.find("[data-role='pause-resume']").remove(); + } + step.template = $template.clone().wrap("
").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._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; + 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"); } - offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth(); - if (offsetRight < 0) { - tipOffset.left = tipOffset.left + offsetRight; + } else { + if (originalTop !== tipOffset.top) { + return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top"); } - 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"); + } + }; + + 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(element, callback) { + var $element, $window, counter, offsetTop, scrollTop, windowHeight; + $element = $(element); + if (!$element.length) { + return callback(); + } + $window = $(window); + offsetTop = $element.offset().top; + windowHeight = $window.height(); + scrollTop = Math.max(0, offsetTop - (windowHeight / 2)); + this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + "."); + counter = 0; + return $("body,html").stop(true, true).animate({ + scrollTop: Math.ceil(scrollTop) + }, (function(_this) { + return function() { + if (++counter === 2) { + callback(); + return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + "."); } + }; + })(this)); + }; + + Tour.prototype._onResize = function(callback, timeout) { + return $(window).on("resize.tour-" + this._options.name, function() { + clearTimeout(timeout); + return timeout = setTimeout(callback, 100); + }); + }; + + Tour.prototype._initMouseNavigation = function() { + var _this; + _this = this; + return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)", (function(_this) { + return function(e) { + e.preventDefault(); + return _this.next(); + }; + })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)", (function(_this) { + return function(e) { + e.preventDefault(); + return _this.prev(); + }; + })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) { + return function(e) { + e.preventDefault(); + return _this.end(); + }; + })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) { + var $this; + e.preventDefault(); + $this = $(this); + $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text")); + if (_this._paused) { + return _this.resume(); } else { - if (originalTop !== tipOffset.top) { - return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top"); - } + return _this.pause(); } - }; + }); + }; - 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(); + Tour.prototype._initKeyboardNavigation = function() { + if (!this._options.keyboard) { + return; + } + return $(document).on("keyup.tour-" + this._options.name, (function(_this) { + return function(e) { + if (!e.which) { + return; + } + switch (e.which) { + case 39: + e.preventDefault(); + if (_this._isLast()) { + 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(); + } + }; + })(this)); + }; - Tour.prototype._makePromise = function(result) { - if (result && $.isFunction(result.then)) { - return result; - } else { - return null; - } - }; + 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) { + Tour.prototype._callOnPromiseDone = function(promise, cb, arg) { + if (promise) { + return promise.then((function(_this) { + return function(e) { return cb.call(_this, arg); - }); - } else { - return cb.call(this, arg); - } - }; + }; + })(this)); + } 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._showBackdrop = function(element) { + if (this.backdrop.backgroundShown) { + return; + } + this.backdrop = $("
", { + "class": "tour-backdrop" + }); + this.backdrop.backgroundShown = true; + return $("body").append(this.backdrop); + }; - Tour.prototype._hideBackdrop = function() { - if (this.backdrop.overlay === null) { - return; - } - if (this.backdrop.$element) { - this._hideOverlayElement(); - } - return this._hideOverlay(); - }; + Tour.prototype._hideBackdrop = function() { + this._hideOverlayElement(); + return this._hideBackground(); + }; - Tour.prototype._showOverlay = function() { - this.backdrop = $("
", { - "class": "tour-backdrop" - }); - return $("body").append(this.backdrop); - }; + Tour.prototype._hideBackground = function() { + this.backdrop.remove(); + this.backdrop.overlay = null; + return this.backdrop.backgroundShown = false; + }; - Tour.prototype._hideOverlay = function() { - this.backdrop.remove(); - return this.backdrop.overlay = null; - }; + Tour.prototype._showOverlayElement = function(element) { + var $background, $element, offset; + $element = $(element); + if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) { + return; + } + this.backdrop.overlayElementShown = true; + $background = $("
"); + 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._showOverlayElement = function(element) { - var $background, $element, offset; - $element = $(element); - $background = $("
"); - 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() { + if (!this.backdrop.overlayElementShown) { + return; + } + this.backdrop.$element.removeClass("tour-step-backdrop"); + this.backdrop.$background.remove(); + this.backdrop.$element = null; + this.backdrop.$background = null; + return this.backdrop.overlayElementShown = false; + }; - Tour.prototype._hideOverlayElement = function() { - this.backdrop.$element.removeClass("tour-step-backdrop"); - this.backdrop.$background.remove(); - this.backdrop.$element = null; - return this.backdrop.$background = null; - }; + Tour.prototype._clearTimer = function() { + window.clearTimeout(this._timer); + this._timer = null; + return this._duration = null; + }; - return Tour; + return Tour; - })(); - return window.Tour = Tour; - })(jQuery, window); - -}).call(this); + })(); + return window.Tour = Tour; +})(jQuery, window); diff --git a/addons/website/static/src/js/website.tour.banner.js b/addons/website/static/src/js/website.tour.banner.js index 65099d03986..443405e2401 100644 --- a/addons/website/static/src/js/website.tour.banner.js +++ b/addons/website/static/src/js/website.tour.banner.js @@ -15,7 +15,6 @@ popover: { next: _t("Start Tutorial"), end: _t("Skip It") }, }, { - waitNot: '.popover.tour', element: 'button[data-action=edit]', placement: 'bottom', title: _t("Edit this page"), @@ -52,7 +51,6 @@ popover: { next: _t("Continue") }, }, { - waitNot: '.popover.tour', element: 'button[data-action=snippet]', placement: 'bottom', title: _t("Add Another Block"), @@ -81,7 +79,6 @@ popover: { next: _t("Continue") }, }, { - waitNot: '.popover.tour', element: 'a[data-action=show-mobile-preview]', placement: 'bottom', title: _t("Test Your Mobile Version"), diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index fc0dd513cf2..df6108e0278 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -32,7 +32,7 @@ if (website.EditorBar) { var self = this; var menu = $('#help-menu'); _.each(website.Tour.tours, function (tour) { - if (tour.mode != "tutorial") { + if (tour.mode === "test") { return; } var $menuItem = $($.parseHTML('
  • '+tour.name+'
  • ')); @@ -90,16 +90,19 @@ website.Tour = {}; website.Tour.tours = {}; website.Tour.state = null; website.Tour.register = function (tour) { + if (tour.mode !== "test") tour.mode = "tutorial"; website.Tour.tours[tour.id] = tour; }; website.Tour.run = function (tour_id, mode) { - if (localStorage.getItem("tour")) { // only one test running + if (localStorage.getItem("tour") && mode === "test") { // only one test running return; } var tour = website.Tour.tours[tour_id]; - website.Tour.save_state(tour.id, mode || tour.mode, 0); - if (tour.path) { + website.Tour.saveState(tour.id, mode || tour.mode, 0); + if (tour.path && !window.location.href.match(new RegExp("("+website.Tour.getLang()+")?"+tour.path+"#?$", "i"))) { window.location.href = "/"+website.Tour.getLang()+tour.path; + } else { + website.Tour.running(); } }; website.Tour.registerSteps = function (tour) { @@ -114,48 +117,82 @@ website.Tour.registerSteps = function (tour) { if (!step.waitNot && index > 0 && tour.steps[index-1] && tour.steps[index-1].popover && tour.steps[index-1].popover.next) { - step.waitNot = '.popover.tour:visible'; + step.waitNot = '.popover.tour.fade.in:visible'; } if (!step.waitFor && index > 0 && tour.steps[index-1].snippet) { step.waitFor = '.oe_overlay_options .oe_options:visible'; } - if (!step.element) step.orphan = true; - - var snippet = step.element.match(/#oe_snippets (.*) \.oe_snippet_thumbnail/); + var snippet = step.element && step.element.match(/#oe_snippets (.*) \.oe_snippet_thumbnail/); if (snippet) { step.snippet = snippet[1]; } else if (step.snippet) { step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail'; } + + if (!step.element) step.orphan = true; } if (tour.steps[index-1] && tour.steps[index-1].popover && tour.steps[index-1].popover.next) { var step = { - step_id: index, - waitNot: '.popover.tour:visible' + id: index, + waitNot: '.popover.tour.fade.in:visible' }; tour.steps.push(step); } // rendering bootstrap tour and popover - if (tour.mode != "test" || typeof Tour !== "undefined") { + if (tour.mode !== "test" || typeof Tour !== "undefined") { tour.tour = new Tour({ - name: this.id, + debug: true, + name: tour.id, storage: localStorage, keyboard: false, - template: this.popover(), + template: website.Tour.popover(), onHide: function () { window.scrollTo(0, 0); } }); + for (var index=0, len=tour.steps.length; index -1) { - tour_id = window.location.href.match(/#tutorial\.(.*)=true/)[1]; - mode = "tutorial"; - step_id = 0; +website.Tour.getState = function () { + var state = JSON.parse(localStorage.getItem("tour") || 'false') || {}; + 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 + }; } - if (!tour_id) { + if (!state.id) { return; } - var tour = website.Tour.tours[tour_id]; - return {'tour': tour, 'tour_id': tour_id, 'mode': mode, 'step_id': step_id}; + state.tour = website.Tour.tours[state.id]; + state.step = state.tour.steps[state.step_id]; + return state; }; website.Tour.error = function (tour, step, message) { website.Tour.reset(); throw new Error(message + - + "\ntour:" + tour.id + - + "\nstep:" + step.id + ": '" + (step._title || step.title) + "'" + + "\ntour: " + tour.id + + + "\nstep: " + step.id + ": '" + (step._title || step.title) + "'" + '\nhref: ' + window.location.href + '\nreferrer: ' + document.referrer + '\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()) - + "\nlocalStorage: " + localStorage.getItem("tour") + + "\nlocalStorage: " + JSON.stringify(localStorage) + '\n\n' + $("body").html() ); }; @@ -206,24 +242,39 @@ website.Tour.lists = function () { } return tour_ids; }; -website.Tour.save_state = function (tour_id, mode, step_id) { - localStorage.setItem("tour", '{tour_id:'+tour_id+', mode:'+mode+', step_id:'+step_id+'}'); +website.Tour.saveState = function (tour_id, mode, step_id) { + localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id})); }; website.Tour.reset = function () { - var running = website.Tour.get_state(); - for (var k in running.tour.steps) { - running.tour.steps[k].busy = false; + var state = website.Tour.getState(); + if (state) { + for (var k in state.tour.steps) { + state.tour.steps[k].busy = false; + } + if (state.tour.tour) { + state.tour.tour.end(); + } } localStorage.removeItem("tour"); clearTimeout(website.Tour.timer); clearTimeout(website.Tour.testtimer); - $('.popover.tour').remove(); + $(".popover.tour").remove(); }; website.Tour.running = function () { - var running = website.Tour.get_state(); - website.Tour.registerSteps(running.tour); - website.Tour.nextStep( running.tour, running.step_id ); + var state = website.Tour.getState(); + if (state) { + website.Tour.registerSteps(state.tour); + if ($.ajaxBusy) { + $(document).ajaxStop(function() { + setTimeout(function () { + website.Tour.nextStep( state.tour, state.step, state.mode === "test" ? 5000 : 0 ); + },0); + }); + } else { + website.Tour.nextStep( state.tour, state.step, state.mode === "test" ? 5000 : 0 ); + } + } }; website.Tour.timer = null; @@ -238,83 +289,62 @@ website.Tour.check = function (step) { website.Tour.waitNextStep = function (tour, step, overlaps) { var time = new Date().getTime(); var timer; + var next = tour.steps[step.id+1]; window.onbeforeunload = function () { clearTimeout(website.Tour.timer); clearTimeout(website.Tour.testtimer); }; - // check popover activity - $(".popover.tour button") - .off() - .on("click", function () { - $(".popover.tour").remove(); - if (step.busy) return; - if (!$(this).is("[data-role='next']")) { - clearTimeout(website.Tour.timer); - step.busy = true; - if (tour.tour) { - tour.tour.end(); - } - tour.endTour(tour); - } - }); - function checkNext () { + website.Tour.autoToggleBootstrapTour(); + clearTimeout(website.Tour.timer); - if (step.busy) return; - if (website.Tour.check(step)) { - step.busy = true; + if (next.busy) return; + if (website.Tour.check(next)) { + next.busy = true; + clearTimeout(website.Tour.currentTimer); // use an other timeout for cke dom loading setTimeout(function () { - website.Tour.nextStep(tour, step, overlaps); + website.Tour.nextStep(tour, next, overlaps); }, website.Tour.defaultDelay); } else if (!overlaps || new Date().getTime() - time < overlaps) { - if (self.current.element) { - 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); - } - } website.Tour.timer = setTimeout(checkNext, website.Tour.defaultDelay); } else { - website.Tour.error(tour, step, "Can't arrive to the next step"); + website.Tour.error(tour, next, "Can't arrive to the next step"); } } checkNext(); }; +website.Tour.currentTimer = null; website.Tour.nextStep = function (tour, step, overlaps) { - var state = website.Tour.get_state(); - website.Tour.save_state(tour.id, state.mode, step.id); + var state = website.Tour.getState(); + website.Tour.saveState(state.id, state.mode, step.id); - // clear popover (fix for boostrap tour if the element is removed before destroy popover) - $(".popover.tour").remove(); - // go to step in bootstrap tour - if (tour.tour) { - tour.tour.goto(step.id); + website.Tour.autoToggleBootstrapTour(); + + if (step.onload) { + step.onload(); } - step.onload(); var next = tour.steps[step.id+1]; if (next) { setTimeout(function () { - website.Tour.waitNextStep(tour, next, overlaps); + website.Tour.waitNextStep(tour, step, overlaps); if (state.mode === "test") { setTimeout(function(){ website.Tour.autoNextStep(tour, step); }, website.Tour.defaultDelay); } - }, next && next.wait || 0); + }, next.wait || 0); } else { website.Tour.endTour(tour); } }; website.Tour.endTour = function (tour) { - var state = website.Tour.get_state(); - var test = state.step_id >= tour.steps.length-1; - this.reset(); + var state = website.Tour.getState(); + var test = state.step.id >= state.tour.steps.length-1; + website.Tour.reset(); if (test) { console.log('ok'); } else { @@ -388,7 +418,8 @@ website.Tour.autoDragAndDropSnippet = function (selector) { $dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top })); }; -website.ready(website.Tour.running); +//$(document).ready(website.Tour.running); +website.ready().then(website.Tour.running); }()); From 58b6aeb01d489922f8311e6a390805d9cb1c877f Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 12:07:50 +0100 Subject: [PATCH 069/248] [IMP] website tour: remove bootstrap Tour lib bzr revid: chm@openerp.com-20140321110750-ew8rj3nv2jcort1x --- .../lib/bootstrap-tour/bootstrap-tour.css | 65 -- .../lib/bootstrap-tour/bootstrap-tour.js | 716 ------------------ addons/website/static/src/css/editor.css | 24 +- addons/website/static/src/css/editor.sass | 19 +- .../static/src/js/website.tour.banner.js | 2 + addons/website/static/src/js/website.tour.js | 349 +++++---- 6 files changed, 258 insertions(+), 917 deletions(-) delete mode 100644 addons/website/static/lib/bootstrap-tour/bootstrap-tour.css delete mode 100644 addons/website/static/lib/bootstrap-tour/bootstrap-tour.js diff --git a/addons/website/static/lib/bootstrap-tour/bootstrap-tour.css b/addons/website/static/lib/bootstrap-tour/bootstrap-tour.css deleted file mode 100644 index 5449158e7f4..00000000000 --- a/addons/website/static/lib/bootstrap-tour/bootstrap-tour.css +++ /dev/null @@ -1,65 +0,0 @@ -/* =========================================================== -# bootstrap-tour - v0.9.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. -*/ -.tour-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1100; - background-color: #000; - opacity: 0.8; -} -.tour-step-backdrop { - position: relative; - z-index: 1101; - background: inherit; -} -.tour-step-background { - position: absolute; - z-index: 1100; - background: inherit; - border-radius: 6px; -} -.popover[class*="tour-"] { - z-index: 1100; -} -.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; -} diff --git a/addons/website/static/lib/bootstrap-tour/bootstrap-tour.js b/addons/website/static/lib/bootstrap-tour/bootstrap-tour.js deleted file mode 100644 index a0172c718c0..00000000000 --- a/addons/website/static/lib/bootstrap-tour/bootstrap-tour.js +++ /dev/null @@ -1,716 +0,0 @@ -/* =========================================================== -# bootstrap-tour - v0.9.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($, window) { - var Tour, document; - document = window.document; - Tour = (function() { - function Tour(options) { - this._options = $.extend({ - name: "tour", - steps: [], - container: "body", - keyboard: true, - storage: window.localStorage, - debug: false, - backdrop: false, - redirect: true, - orphan: false, - duration: false, - basePath: "", - template: "

    ", - 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) {}, - onPause: function(tour, duration) {}, - onResume: function(tour, duration) {} - }, options); - this._force = false; - this._inited = false; - this.backdrop = { - overlay: null, - $element: null, - $background: null, - backgroundShown: false, - overlayElementShown: false - }; - this; - } - - Tour.prototype.addSteps = function(steps) { - var step, _i, _len; - for (_i = 0, _len = steps.length; _i < _len; _i++) { - step = steps[_i]; - this.addStep(step); - } - return this; - }; - - Tour.prototype.addStep = function(step) { - this._options.steps.push(step); - return this; - }; - - Tour.prototype.getStep = function(i) { - if (this._options.steps[i] != null) { - return $.extend({ - id: "step-" + i, - path: "", - placement: "right", - title: "", - content: "

    ", - next: i === this._options.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, - duration: this._options.duration, - 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, - onPause: this._options.onPause, - onResume: this._options.onResume - }, this._options.steps[i]); - } - }; - - Tour.prototype.init = function(force) { - this._force = force; - if (this.ended()) { - this._debug("Tour ended, init prevented."); - return this; - } - this.setCurrentStep(); - this._initMouseNavigation(); - this._initKeyboardNavigation(); - this._onResize((function(_this) { - return function() { - return _this.showStep(_this._current); - }; - })(this)); - if (this._current !== null) { - this.showStep(this._current); - } - this._inited = true; - return this; - }; - - Tour.prototype.start = function(force) { - var promise; - if (force == null) { - force = false; - } - if (!this._inited) { - this.init(force); - } - if (this._current === null) { - promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0); - this._callOnPromiseDone(promise, this.showStep, 0); - } - return this; - }; - - Tour.prototype.next = function() { - var promise; - promise = this.hideStep(this._current); - return this._callOnPromiseDone(promise, this._showNextStep); - }; - - Tour.prototype.prev = function() { - var promise; - promise = this.hideStep(this._current); - return this._callOnPromiseDone(promise, this._showPrevStep); - }; - - Tour.prototype.goTo = function(i) { - var promise; - promise = this.hideStep(this._current); - return this._callOnPromiseDone(promise, this.showStep, i); - }; - - Tour.prototype.end = function() { - var endHelper, promise; - endHelper = (function(_this) { - return 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"); - _this._inited = false; - _this._force = false; - _this._clearTimer(); - if (_this._options.onEnd != null) { - return _this._options.onEnd(_this); - } - }; - })(this); - promise = this.hideStep(this._current); - return this._callOnPromiseDone(promise, endHelper); - }; - - Tour.prototype.ended = function() { - return !this._force && !!this._getState("end"); - }; - - Tour.prototype.restart = function() { - this._removeState("current_step"); - this._removeState("end"); - this.setCurrentStep(0); - return this.start(); - }; - - Tour.prototype.pause = function() { - var step; - step = this.getStep(this._current); - if (!(step && step.duration)) { - return this; - } - this._paused = true; - this._duration -= new Date().getTime() - this._start; - window.clearTimeout(this._timer); - this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining)."); - if (step.onPause != null) { - return step.onPause(this, this._duration); - } - }; - - Tour.prototype.resume = function() { - var step; - step = this.getStep(this._current); - if (!(step && step.duration)) { - return this; - } - this._paused = false; - this._start = new Date().getTime(); - this._duration = this._duration || step.duration; - this._timer = window.setTimeout((function(_this) { - return function() { - if (_this._isLast()) { - return _this.next(); - } else { - return _this.end(); - } - }; - })(this), this._duration); - this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration); - if ((step.onResume != null) && this._duration !== step.duration) { - return step.onResume(this, this._duration); - } - }; - - Tour.prototype.hideStep = function(i) { - var hideStepHelper, promise, step; - step = this.getStep(i); - if (!step) { - return; - } - this._clearTimer(); - promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0); - hideStepHelper = (function(_this) { - return function(e) { - var $element; - $element = $(step.element); - if (!($element.data("bs.popover") || $element.data("popover"))) { - $element = $("body"); - } - $element.popover("destroy").removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element"); - 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); - this._callOnPromiseDone(promise, hideStepHelper); - return promise; - }; - - Tour.prototype.showStep = function(i) { - var promise, showStepHelper, skipToPrevious, step; - if (this.ended()) { - this._debug("Tour ended, showStep prevented."); - return 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(_this) { - return function(e) { - var current_path, path; - _this.setCurrentStep(i); - path = (function() { - switch ({}.toString.call(step.path)) { - case "[object Function]": - return step.path(); - case "[object String]": - return this._options.basePath + step.path; - default: - return step.path; - } - }).call(_this); - 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._scrollIntoView(step.element, function() { - if ((step.element != null) && step.backdrop) { - _this._showOverlayElement(step.element); - } - _this._showPopover(step, i); - if (step.onShown != null) { - step.onShown(_this); - } - return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length); - }); - if (step.duration) { - return _this.resume(); - } - }; - })(this); - this._callOnPromiseDone(promise, showStepHelper); - return promise; - }; - - Tour.prototype.getCurrentStep = function() { - return this._current; - }; - - Tour.prototype.setCurrentStep = function(value) { - if (value != null) { - this._current = value; - this._setState("current_step", value); - } else { - this._current = this._getState("current_step"); - this._current = this._current === null ? null : parseInt(this._current, 10); - } - return this; - }; - - Tour.prototype._setState = function(key, value) { - var e, keyName; - if (this._options.storage) { - keyName = "" + this._options.name + "_" + key; - try { - this._options.storage.setItem(keyName, value); - } catch (_error) { - e = _error; - if (e.code === DOMException.QUOTA_EXCEEDED_ERR) { - this.debug("LocalStorage quota exceeded. State storage failed."); - } - } - 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._showNextStep = function() { - var promise, showNextStepHelper, step; - step = this.getStep(this._current); - showNextStepHelper = (function(_this) { - return function(e) { - return _this.showStep(step.next); - }; - })(this); - promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0); - return this._callOnPromiseDone(promise, showNextStepHelper); - }; - - Tour.prototype._showPrevStep = function() { - var promise, showPrevStepHelper, step; - step = this.getStep(this._current); - showPrevStepHelper = (function(_this) { - return function(e) { - return _this.showStep(step.prev); - }; - })(this); - 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 !== "" && ((toString.call(path) === "[object RegExp]" && !path.test(currentPath)) || (toString.call(path) === "[object String]" && 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") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg"); - }; - - Tour.prototype._isLast = function() { - return this._current < this._options.steps.length - 1; - }; - - Tour.prototype._showPopover = function(step, i) { - var $element, $navigation, $template, $tip, isOrphan, options; - 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>*:last"; - step.placement = "top"; - $template = $template.addClass("orphan"); - } - $element = $(step.element); - $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i); - $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element"); - if (step.options) { - $.extend(options, step.options); - } - if (step.reflex) { - $element.css("cursor", "pointer").on("click.tour-" + this._options.name, (function(_this) { - return function() { - if (_this._isLast()) { - return _this.next(); - } else { - return _this.end(); - } - }; - })(this)); - } - if (step.prev < 0) { - $navigation.find("[data-role='prev']").addClass("disabled"); - } - if (step.next < 0) { - $navigation.find("[data-role='next']").addClass("disabled"); - } - if (!step.duration) { - $navigation.find("[data-role='pause-resume']").remove(); - } - step.template = $template.clone().wrap("
    ").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._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(element, callback) { - var $element, $window, counter, offsetTop, scrollTop, windowHeight; - $element = $(element); - if (!$element.length) { - return callback(); - } - $window = $(window); - offsetTop = $element.offset().top; - windowHeight = $window.height(); - scrollTop = Math.max(0, offsetTop - (windowHeight / 2)); - this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + "."); - counter = 0; - return $("body,html").stop(true, true).animate({ - scrollTop: Math.ceil(scrollTop) - }, (function(_this) { - return function() { - if (++counter === 2) { - callback(); - return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + "."); - } - }; - })(this)); - }; - - Tour.prototype._onResize = function(callback, timeout) { - return $(window).on("resize.tour-" + this._options.name, function() { - clearTimeout(timeout); - return timeout = setTimeout(callback, 100); - }); - }; - - Tour.prototype._initMouseNavigation = function() { - var _this; - _this = this; - return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)", (function(_this) { - return function(e) { - e.preventDefault(); - return _this.next(); - }; - })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)", (function(_this) { - return function(e) { - e.preventDefault(); - return _this.prev(); - }; - })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) { - return function(e) { - e.preventDefault(); - return _this.end(); - }; - })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) { - var $this; - e.preventDefault(); - $this = $(this); - $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text")); - if (_this._paused) { - return _this.resume(); - } else { - return _this.pause(); - } - }); - }; - - Tour.prototype._initKeyboardNavigation = function() { - if (!this._options.keyboard) { - return; - } - return $(document).on("keyup.tour-" + this._options.name, (function(_this) { - return function(e) { - if (!e.which) { - return; - } - switch (e.which) { - case 39: - e.preventDefault(); - if (_this._isLast()) { - 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(); - } - }; - })(this)); - }; - - Tour.prototype._makePromise = function(result) { - if (result && $.isFunction(result.then)) { - return result; - } else { - return null; - } - }; - - Tour.prototype._callOnPromiseDone = function(promise, cb, arg) { - if (promise) { - return promise.then((function(_this) { - return function(e) { - return cb.call(_this, arg); - }; - })(this)); - } else { - return cb.call(this, arg); - } - }; - - Tour.prototype._showBackdrop = function(element) { - if (this.backdrop.backgroundShown) { - return; - } - this.backdrop = $("
    ", { - "class": "tour-backdrop" - }); - this.backdrop.backgroundShown = true; - return $("body").append(this.backdrop); - }; - - Tour.prototype._hideBackdrop = function() { - this._hideOverlayElement(); - return this._hideBackground(); - }; - - Tour.prototype._hideBackground = function() { - this.backdrop.remove(); - this.backdrop.overlay = null; - return this.backdrop.backgroundShown = false; - }; - - Tour.prototype._showOverlayElement = function(element) { - var $background, $element, offset; - $element = $(element); - if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) { - return; - } - this.backdrop.overlayElementShown = true; - $background = $("
    "); - 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() { - if (!this.backdrop.overlayElementShown) { - return; - } - this.backdrop.$element.removeClass("tour-step-backdrop"); - this.backdrop.$background.remove(); - this.backdrop.$element = null; - this.backdrop.$background = null; - return this.backdrop.overlayElementShown = false; - }; - - Tour.prototype._clearTimer = function() { - window.clearTimeout(this._timer); - this._timer = null; - return this._duration = null; - }; - - return Tour; - - })(); - return window.Tour = Tour; -})(jQuery, window); diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css index da0fad43caf..0bd20bdcca9 100644 --- a/addons/website/static/src/css/editor.css +++ b/addons/website/static/src/css/editor.css @@ -484,10 +484,30 @@ div.tour-backdrop { z-index: 2009; } -.popover.tour { - z-index: 2010; +.popover.tour.orphan .arrow { + 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 { position: fixed; } + +.tour-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1100; + background-color: black; + opacity: 0.8; +} diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass index 4571dcd257e..bd0f4628009 100644 --- a/addons/website/static/src/css/editor.sass +++ b/addons/website/static/src/css/editor.sass @@ -424,9 +424,26 @@ $editorbar_height: 30px div.tour-backdrop z-index: 2009 .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 position: fixed +.tour-backdrop + position: fixed + top: 0 + right: 0 + bottom: 0 + left: 0 + z-index: 1100 + background-color: #000 + opacity: 0.8 + // }}} diff --git a/addons/website/static/src/js/website.tour.banner.js b/addons/website/static/src/js/website.tour.banner.js index 443405e2401..a8abbcf59e2 100644 --- a/addons/website/static/src/js/website.tour.banner.js +++ b/addons/website/static/src/js/website.tour.banner.js @@ -13,6 +13,7 @@ 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."), popover: { next: _t("Start Tutorial"), end: _t("Skip It") }, + backdrop: true, }, { element: 'button[data-action=edit]', @@ -77,6 +78,7 @@ title: _t("Good Job!"), content: _t("Well done, you created your homepage."), popover: { next: _t("Continue") }, + backdrop: true, }, { element: 'a[data-action=show-mobile-preview]', diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index df6108e0278..3bfd4e06da0 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -15,8 +15,8 @@ if (typeof openerp === "undefined") { var website = window.openerp.website; -// don't rewrite website.Tour in test mode -if (typeof website.Tour !== "undefined") { +// don't rewrite T in test mode +if (typeof T !== "undefined") { return; } @@ -31,14 +31,14 @@ if (website.EditorBar) { start: function () { var self = this; var menu = $('#help-menu'); - _.each(website.Tour.tours, function (tour) { + _.each(T.tours, function (tour) { if (tour.mode === "test") { return; } var $menuItem = $($.parseHTML('
  • '+tour.name+'
  • ')); $menuItem.click(function () { - website.Tour.reset(); - website.Tour.run(tour.id); + T.reset(); + T.run(tour.id); }); menu.append($menuItem); }); @@ -80,32 +80,36 @@ $.ajaxSetup({ } }); - ///////////////////////////////////////////////// - var localStorage = window.localStorage; -website.Tour = {}; -website.Tour.tours = {}; -website.Tour.state = null; -website.Tour.register = function (tour) { +var T = website.Tour = {}; +T.tours = {}; +T.defaultDelay = 50; +T.errorDelay = 5000; +T.state = null; +T.$element = null; +T.timer = null; +T.testtimer = null; +T.currentTimer = null; +T.register = function (tour) { if (tour.mode !== "test") tour.mode = "tutorial"; - website.Tour.tours[tour.id] = tour; + T.tours[tour.id] = tour; }; -website.Tour.run = function (tour_id, mode) { +T.run = function (tour_id, mode) { if (localStorage.getItem("tour") && mode === "test") { // only one test running return; } - var tour = website.Tour.tours[tour_id]; - website.Tour.saveState(tour.id, mode || tour.mode, 0); - if (tour.path && !window.location.href.match(new RegExp("("+website.Tour.getLang()+")?"+tour.path+"#?$", "i"))) { - window.location.href = "/"+website.Tour.getLang()+tour.path; + var tour = T.tours[tour_id]; + T.saveState(tour.id, mode || tour.mode, 0); + if (tour.path && !window.location.href.match(new RegExp("("+T.getLang()+")?"+tour.path+"#?$", "i"))) { + window.location.href = "/"+T.getLang()+tour.path; } else { - website.Tour.running(); + T.running(); } }; -website.Tour.registerSteps = function (tour) { +T.registerSteps = function (tour) { if (tour.register) { return; } @@ -130,7 +134,10 @@ website.Tour.registerSteps = function (tour) { step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail'; } - if (!step.element) step.orphan = true; + if (!step.element) { + step.element = "body"; + step.orphan = true; + } } if (tour.steps[index-1] && tour.steps[index-1].popover && tour.steps[index-1].popover.next) { @@ -142,69 +149,151 @@ website.Tour.registerSteps = function (tour) { } // rendering bootstrap tour and popover - if (tour.mode !== "test" || typeof Tour !== "undefined") { - tour.tour = new Tour({ - debug: true, - name: tour.id, - storage: localStorage, - keyboard: false, - template: website.Tour.popover(), - onHide: function () { - window.scrollTo(0, 0); - } - }); - + if (tour.mode !== "test") { for (var index=0, len=tour.steps.length; index
    '); + } + + 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(); +}; +T.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 { - tour.end(); + var top = T.$element.offset().top + T.$element.outerHeight()/2 - tipOffset.top; + $tip.find(".arrow").css("top", top ? top + "px" : ""); } }; -website.Tour.popoverTitle = function (tour, options) { +T.popoverTitle = function (tour, options) { return openerp.qweb.render('website.tour_popover_title', options); }; -website.Tour.popover = function (options) { +T.popover = function (options) { return openerp.qweb.render('website.tour_popover', options); }; -website.Tour.getLang = function () { +T.getLang = function () { return $("html").attr("lang").replace(/-/, '_'); }; -website.Tour.getState = function () { +T.getState = function () { var state = JSON.parse(localStorage.getItem("tour") || 'false') || {}; var tour_id,mode,step_id; if (!state.id && window.location.href.indexOf("#tutorial.") > -1) { @@ -217,15 +306,16 @@ website.Tour.getState = function () { if (!state.id) { return; } - state.tour = website.Tour.tours[state.id]; + state.tour = T.tours[state.id]; state.step = state.tour.steps[state.step_id]; return state; }; -website.Tour.error = function (tour, step, message) { - website.Tour.reset(); +T.error = function (message) { + var state = T.getState(); + T.reset(); throw new Error(message + - + "\ntour: " + tour.id + - + "\nstep: " + step.id + ": '" + (step._title || step.title) + "'" + + "\ntour: " + state.tour.id + + + "\nstep: " + state.step.id + ": '" + (state.step._title || state.step.title) + "'" + '\nhref: ' + window.location.href + '\nreferrer: ' + document.referrer + '\nelement: ' + Boolean(!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) @@ -235,124 +325,121 @@ website.Tour.error = function (tour, step, message) { + '\n\n' + $("body").html() ); }; -website.Tour.lists = function () { +T.lists = function () { var tour_ids = []; - for (var k in website.Tour.tours) { + for (var k in T.tours) { tour_ids.push(k); } return tour_ids; }; -website.Tour.saveState = function (tour_id, mode, step_id) { - localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id})); +T.saveState = function (tour_id, mode, step_id) { + localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id || 0})); }; -website.Tour.reset = function () { - var state = website.Tour.getState(); +T.reset = function () { + var state = T.getState(); if (state) { for (var k in state.tour.steps) { state.tour.steps[k].busy = false; } - if (state.tour.tour) { - state.tour.tour.end(); - } } localStorage.removeItem("tour"); - clearTimeout(website.Tour.timer); - clearTimeout(website.Tour.testtimer); - - $(".popover.tour").remove(); + clearTimeout(T.timer); + clearTimeout(T.testtimer); + T.closePopover(); }; -website.Tour.running = function () { - var state = website.Tour.getState(); +T.running = function () { + var state = T.getState(); if (state) { - website.Tour.registerSteps(state.tour); + T.registerSteps(state.tour); if ($.ajaxBusy) { $(document).ajaxStop(function() { setTimeout(function () { - website.Tour.nextStep( state.tour, state.step, state.mode === "test" ? 5000 : 0 ); + T.nextStep(); },0); }); } else { - website.Tour.nextStep( state.tour, state.step, state.mode === "test" ? 5000 : 0 ); + T.nextStep(); } } }; - -website.Tour.timer = null; -website.Tour.testtimer = null; -website.Tour.defaultDelay = 50; -website.Tour.check = function (step) { +T.check = function (step) { return (step && (!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) && (!step.waitNot || !$(step.waitNot).size()) && (!step.waitFor || $(step.waitFor).size())); }; -website.Tour.waitNextStep = function (tour, step, overlaps) { +T.waitNextStep = function () { + var state = T.getState(); var time = new Date().getTime(); var timer; - var next = tour.steps[step.id+1]; + var next = state.tour.steps[state.step.id+1]; + var overlaps = state.mode === "test" ? T.errorDelay : 0; window.onbeforeunload = function () { - clearTimeout(website.Tour.timer); - clearTimeout(website.Tour.testtimer); + clearTimeout(T.timer); + clearTimeout(T.testtimer); }; function checkNext () { - website.Tour.autoToggleBootstrapTour(); + T.autoTogglePopover(); - clearTimeout(website.Tour.timer); - if (next.busy) return; - if (website.Tour.check(next)) { - next.busy = true; - clearTimeout(website.Tour.currentTimer); + clearTimeout(T.timer); + if (T.check(next)) { + clearTimeout(T.currentTimer); // use an other timeout for cke dom loading setTimeout(function () { - website.Tour.nextStep(tour, next, overlaps); - }, website.Tour.defaultDelay); + T.nextStep(next); + }, T.defaultDelay); } else if (!overlaps || new Date().getTime() - time < overlaps) { - website.Tour.timer = setTimeout(checkNext, website.Tour.defaultDelay); + T.timer = setTimeout(checkNext, T.defaultDelay); } else { - website.Tour.error(tour, next, "Can't arrive to the next step"); + T.error("Can't arrive to the next step"); } } checkNext(); }; -website.Tour.currentTimer = null; -website.Tour.nextStep = function (tour, step, overlaps) { - var state = website.Tour.getState(); - website.Tour.saveState(state.id, state.mode, step.id); +T.nextStep = function (step) { + var state = T.getState(); - website.Tour.autoToggleBootstrapTour(); + if (!state) { + return; + } + + step = step || state.step; + T.saveState(state.id, state.mode, step.id); + + T.autoTogglePopover(true); if (step.onload) { step.onload(); } - var next = tour.steps[step.id+1]; + var next = state.tour.steps[step.id+1]; if (next) { setTimeout(function () { - website.Tour.waitNextStep(tour, step, overlaps); + T.waitNextStep(); if (state.mode === "test") { setTimeout(function(){ - website.Tour.autoNextStep(tour, step); - }, website.Tour.defaultDelay); + T.autoNextStep(); + }, T.defaultDelay); } }, next.wait || 0); } else { - website.Tour.endTour(tour); + T.endTour(); } }; -website.Tour.endTour = function (tour) { - var state = website.Tour.getState(); +T.endTour = function () { + var state = T.getState(); var test = state.step.id >= state.tour.steps.length-1; - website.Tour.reset(); + T.reset(); if (test) { console.log('ok'); } else { console.log('error'); } }; -website.Tour.autoNextStep = function (tour, step) { - clearTimeout(website.Tour.testtimer); +T.autoNextStep = function (tour, step) { + clearTimeout(T.testtimer); function autoStep () { if (!step) return; @@ -361,18 +448,14 @@ website.Tour.autoNextStep = function (tour, step) { step.autoComplete(tour); } - var $popover = $(".popover.tour"); - if ($popover.find("button[data-role='next']:visible").size()) { - $popover.find("button[data-role='next']:visible").click(); - $popover.remove(); - } + T.closePopover(); var $element = $(step.element); if (!$element.size()) return; if (step.snippet) { - website.Tour.autoDragAndDropSnippet($element); + T.autoDragAndDropSnippet($element); } else if (step.sampleText) { @@ -388,7 +471,7 @@ website.Tour.autoNextStep = function (tour, step) { setTimeout(function () { $element.trigger($.Event("keyup", { srcElement: $element })); $element.trigger($.Event("change", { srcElement: $element })); - }, website.Tour.defaultDelay<<1); + }, T.defaultDelay<<1); } else if ($element.is(":visible")) { @@ -406,9 +489,9 @@ website.Tour.autoNextStep = function (tour, step) { }, 1000); } } - website.Tour.testtimer = setTimeout(autoStep, 100); + T.testtimer = setTimeout(autoStep, 100); }; -website.Tour.autoDragAndDropSnippet = function (selector) { +T.autoDragAndDropSnippet = function (selector) { var $thumbnail = $(selector).first(); var thumbnailPosition = $thumbnail.position(); $thumbnail.trigger($.Event("mousedown", { which: 1, pageX: thumbnailPosition.left, pageY: thumbnailPosition.top })); @@ -418,8 +501,8 @@ website.Tour.autoDragAndDropSnippet = function (selector) { $dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top })); }; -//$(document).ready(website.Tour.running); -website.ready().then(website.Tour.running); +//$(document).ready(T.running); +website.ready().then(T.running); }()); From 254b3a29fa80ffcaeec2da60a2a2b0abac8da925 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 12:18:15 +0100 Subject: [PATCH 070/248] [IMP] website tour: auto set backdrop if no selector element bzr revid: chm@openerp.com-20140321111815-t0312xxl7l83w9rx --- addons/website/static/src/js/website.tour.banner.js | 2 -- addons/website/static/src/js/website.tour.js | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/website/static/src/js/website.tour.banner.js b/addons/website/static/src/js/website.tour.banner.js index a8abbcf59e2..443405e2401 100644 --- a/addons/website/static/src/js/website.tour.banner.js +++ b/addons/website/static/src/js/website.tour.banner.js @@ -13,7 +13,6 @@ 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."), popover: { next: _t("Start Tutorial"), end: _t("Skip It") }, - backdrop: true, }, { element: 'button[data-action=edit]', @@ -78,7 +77,6 @@ title: _t("Good Job!"), content: _t("Well done, you created your homepage."), popover: { next: _t("Continue") }, - backdrop: true, }, { element: 'a[data-action=show-mobile-preview]', diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index 3bfd4e06da0..ce20bf69718 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -137,6 +137,7 @@ T.registerSteps = function (tour) { if (!step.element) { step.element = "body"; step.orphan = true; + step.backdrop = true; } } if (tour.steps[index-1] && From 429324999c9fe7149e34ec5f501c14aa7a8a7fdc Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 12:23:44 +0100 Subject: [PATCH 071/248] [IMP] website tour: remove tag script and css to lib bootstrap bzr revid: chm@openerp.com-20140321112344-mwh2p8pp02j9sdq0 --- addons/website/views/website_templates.xml | 2 -- addons/website_report/views/layouts.xml | 2 -- 2 files changed, 4 deletions(-) diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index 66a38f09651..7849c701bd4 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -253,7 +253,6 @@ - @@ -265,7 +264,6 @@ - diff --git a/addons/website_report/views/layouts.xml b/addons/website_report/views/layouts.xml index 091bb8dd3db..219780317c3 100644 --- a/addons/website_report/views/layouts.xml +++ b/addons/website_report/views/layouts.xml @@ -33,7 +33,6 @@ - @@ -42,7 +41,6 @@ - From d8f27686e5e70a626d12d4fcfdc6af5e5e642468 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 12:57:24 +0100 Subject: [PATCH 072/248] [IMP] website tour: fix test tour bzr revid: chm@openerp.com-20140321115724-iwu17fkzdzaksmrs --- addons/website/static/src/js/website.tour.js | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index ce20bf69718..26fa5af0b9f 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -313,18 +313,17 @@ T.getState = function () { }; T.error = function (message) { var state = T.getState(); + message += '\n tour: ' + state.id + + '\n step: ' + state.step_id + ": '" + (state.step._title || state.step.title) + "'" + + '\n href: ' + window.location.href + + '\n referrer: ' + document.referrer + + '\n element: ' + Boolean(!state.step.element || ($(state.step.element).size() && $(state.step.element).is(":visible") && !$(state.step.element).is(":hidden"))) + + '\n waitNot: ' + Boolean(!state.step.waitNot || !$(state.step.waitNot).size()) + + '\n waitFor: ' + Boolean(!state.step.waitFor || $(state.step.waitFor).size()) + + "\n localStorage: " + JSON.stringify(localStorage) + + '\n\n' + $("body").html(); T.reset(); - throw new Error(message + - + "\ntour: " + state.tour.id + - + "\nstep: " + state.step.id + ": '" + (state.step._title || state.step.title) + "'" - + '\nhref: ' + window.location.href - + '\nreferrer: ' + document.referrer - + '\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()) - + "\nlocalStorage: " + JSON.stringify(localStorage) - + '\n\n' + $("body").html() - ); + throw new Error(message); }; T.lists = function () { var tour_ids = []; @@ -421,7 +420,7 @@ T.nextStep = function (step) { T.waitNextStep(); if (state.mode === "test") { setTimeout(function(){ - T.autoNextStep(); + T.autoNextStep(state.tour, step); }, T.defaultDelay); } }, next.wait || 0); @@ -449,7 +448,7 @@ T.autoNextStep = function (tour, step) { step.autoComplete(tour); } - T.closePopover(); + $(".popover.tour [data-role='next']").click(); var $element = $(step.element); if (!$element.size()) return; From 89a6bd06495c4fe599756866828298331f375747 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 13:37:22 +0100 Subject: [PATCH 073/248] [IMP] website tour: fix auto test bzr revid: chm@openerp.com-20140321123722-dmfdckh59cvot00i --- addons/website/static/src/js/website.tour.js | 4 ++-- .../static/src/js/website.tour.event_sale.js | 4 ++-- addons/website_sale/static/src/js/website.tour.sale.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index 26fa5af0b9f..a033e6f1ecd 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -16,7 +16,7 @@ if (typeof openerp === "undefined") { var website = window.openerp.website; // don't rewrite T in test mode -if (typeof T !== "undefined") { +if (typeof website.Tour !== "undefined") { return; } @@ -393,7 +393,7 @@ T.waitNextStep = function () { } else if (!overlaps || new Date().getTime() - time < overlaps) { T.timer = setTimeout(checkNext, T.defaultDelay); } else { - T.error("Can't arrive to the next step"); + T.error("Can't reach the next step"); } } checkNext(); diff --git a/addons/website_event_sale/static/src/js/website.tour.event_sale.js b/addons/website_event_sale/static/src/js/website.tour.event_sale.js index 92e57638cc8..668a05001af 100644 --- a/addons/website_event_sale/static/src/js/website.tour.event_sale.js +++ b/addons/website_event_sale/static/src/js/website.tour.event_sale.js @@ -16,7 +16,7 @@ { title: "go to register page", waitNot: 'a[href*="/event"]:contains("Functional Webinar")', - onload: function () { + autoComplete: function () { // use onload if website_event_track is installed if (!$('form:contains("Ticket Type")').size()) { window.location.href = $('a[href*="/event"][href*="/register"]').attr("href"); @@ -43,7 +43,7 @@ title: "Complete checkout", waitFor: '#top_menu .my_cart_quantity:contains(5)', element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")', - onload: function (tour) { + autoComplete: function (tour) { if ($("input[name='name']").val() === "") $("input[name='name']").val("website_sale-test-shoptest"); if ($("input[name='email']").val() === "") diff --git a/addons/website_sale/static/src/js/website.tour.sale.js b/addons/website_sale/static/src/js/website.tour.sale.js index c7526b2468f..62455e0b811 100644 --- a/addons/website_sale/static/src/js/website.tour.sale.js +++ b/addons/website_sale/static/src/js/website.tour.sale.js @@ -50,7 +50,7 @@ { title: "test with input error", element: 'form[action="/shop/confirm_order"] .btn:contains("Confirm")', - onload: function (tour) { + autoComplete: function (tour) { $("input[name='phone']").val(""); }, }, @@ -58,7 +58,7 @@ 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) { + autoComplete: function (tour) { if ($("input[name='name']").val() === "") $("input[name='name']").val("website_sale-test-shoptest"); if ($("input[name='email']").val() === "") From f9b0c7469a7762bbba6d142e7799fc854aa01d24 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 14:42:07 +0100 Subject: [PATCH 074/248] [IMP] website tour: change syntax bzr revid: chm@openerp.com-20140321134207-y54uj2fynl5p0e8a --- addons/website/static/src/js/website.tour.js | 795 ++++++++++--------- 1 file changed, 399 insertions(+), 396 deletions(-) diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index a033e6f1ecd..6a5f8faab76 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -84,421 +84,424 @@ $.ajaxSetup({ var localStorage = window.localStorage; -var T = website.Tour = {}; -T.tours = {}; -T.defaultDelay = 50; -T.errorDelay = 5000; -T.state = null; -T.$element = null; -T.timer = null; -T.testtimer = null; -T.currentTimer = null; -T.register = function (tour) { - if (tour.mode !== "test") tour.mode = "tutorial"; - T.tours[tour.id] = tour; -}; -T.run = function (tour_id, mode) { - if (localStorage.getItem("tour") && mode === "test") { // only one test running - return; - } - var tour = T.tours[tour_id]; - T.saveState(tour.id, mode || tour.mode, 0); - if (tour.path && !window.location.href.match(new RegExp("("+T.getLang()+")?"+tour.path+"#?$", "i"))) { - window.location.href = "/"+T.getLang()+tour.path; - } else { - T.running(); - } -}; -T.registerSteps = function (tour) { - if (tour.register) { - return; - } - tour.register = true; - - for (var index=0, len=tour.steps.length; index 0 && tour.steps[index-1] && - tour.steps[index-1].popover && tour.steps[index-1].popover.next) { - step.waitNot = '.popover.tour.fade.in:visible'; +var T = website.Tour = { + tours: {}, + defaultDelay: 50, + errorDelay: 5000, + state: null, + $element: null, + 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) { + if (localStorage.getItem("tour") && mode === "test") { // only one test running + return; } - if (!step.waitFor && index > 0 && tour.steps[index-1].snippet) { - step.waitFor = '.oe_overlay_options .oe_options:visible'; + var tour = T.tours[tour_id]; + T.saveState(tour.id, mode || tour.mode, 0); + if (tour.path && !window.location.href.match(new RegExp("("+T.getLang()+")?"+tour.path+"#?$", "i"))) { + window.location.href = "/"+T.getLang()+tour.path; + } else { + T.running(); } - - var snippet = step.element && step.element.match(/#oe_snippets (.*) \.oe_snippet_thumbnail/); - if (snippet) { - step.snippet = snippet[1]; - } else if (step.snippet) { - step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail'; + }, + registerSteps: function (tour) { + if (tour.register) { + return; } + tour.register = true; - if (!step.element) { - step.element = "body"; - step.orphan = true; - step.backdrop = true; - } - } - if (tour.steps[index-1] && - tour.steps[index-1].popover && tour.steps[index-1].popover.next) { - var step = { - id: index, - waitNot: '.popover.tour.fade.in:visible' - }; - tour.steps.push(step); - } - - // rendering bootstrap tour and popover - if (tour.mode !== "test") { for (var index=0, len=tour.steps.length; index
    '); - } - - 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(); + if (!step.waitNot && index > 0 && tour.steps[index-1] && + tour.steps[index-1].popover && tour.steps[index-1].popover.next) { + step.waitNot = '.popover.tour.fade.in:visible'; + } + if (!step.waitFor && index > 0 && tour.steps[index-1].snippet) { + step.waitFor = '.oe_overlay_options .oe_options:visible'; } - T.closePopover(); - }); - T.repositionPopover(); -}; -T.repositionPopover = function() { - var popover = T.$element.data("bs.popover"); - var $tip = T.$element.data("bs.popover").tip(); + var snippet = step.element && step.element.match(/#oe_snippets (.*) \.oe_snippet_thumbnail/); + if (snippet) { + step.snippet = snippet[1]; + } else if (step.snippet) { + step.element = '#oe_snippets '+step.snippet+' .oe_snippet_thumbnail'; + } - 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 { - var top = T.$element.offset().top + T.$element.outerHeight()/2 - tipOffset.top; - $tip.find(".arrow").css("top", top ? top + "px" : ""); - } -}; -T.popoverTitle = function (tour, options) { - return openerp.qweb.render('website.tour_popover_title', options); -}; -T.popover = function (options) { - return openerp.qweb.render('website.tour_popover', options); -}; -T.getLang = function () { - return $("html").attr("lang").replace(/-/, '_'); -}; -T.getState = function () { - var state = JSON.parse(localStorage.getItem("tour") || 'false') || {}; - 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 - }; - } - if (!state.id) { - return; - } - state.tour = T.tours[state.id]; - state.step = state.tour.steps[state.step_id]; - return state; -}; -T.error = function (message) { - var state = T.getState(); - message += '\n tour: ' + state.id - + '\n step: ' + state.step_id + ": '" + (state.step._title || state.step.title) + "'" - + '\n href: ' + window.location.href - + '\n referrer: ' + document.referrer - + '\n element: ' + Boolean(!state.step.element || ($(state.step.element).size() && $(state.step.element).is(":visible") && !$(state.step.element).is(":hidden"))) - + '\n waitNot: ' + Boolean(!state.step.waitNot || !$(state.step.waitNot).size()) - + '\n waitFor: ' + Boolean(!state.step.waitFor || $(state.step.waitFor).size()) - + "\n localStorage: " + JSON.stringify(localStorage) - + '\n\n' + $("body").html(); - T.reset(); - throw new Error(message); -}; -T.lists = function () { - var tour_ids = []; - for (var k in T.tours) { - tour_ids.push(k); - } - return tour_ids; -}; -T.saveState = function (tour_id, mode, step_id) { - localStorage.setItem("tour", JSON.stringify({"id":tour_id, "mode":mode, "step_id":step_id || 0})); -}; -T.reset = function () { - var state = T.getState(); - if (state) { - for (var k in state.tour.steps) { - state.tour.steps[k].busy = false; + if (!step.element) { + step.element = "body"; + step.orphan = true; + step.backdrop = true; + } } - } - localStorage.removeItem("tour"); - clearTimeout(T.timer); - clearTimeout(T.testtimer); - T.closePopover(); -}; -T.running = function () { - var state = T.getState(); - if (state) { - T.registerSteps(state.tour); - if ($.ajaxBusy) { - $(document).ajaxStop(function() { - setTimeout(function () { - T.nextStep(); - },0); + if (tour.steps[index-1] && + tour.steps[index-1].popover && tour.steps[index-1].popover.next) { + var step = { + id: index, + waitNot: '.popover.tour.fade.in:visible' + }; + tour.steps.push(step); + } + + // rendering bootstrap tour and popover + if (tour.mode !== "test") { + for (var index=0, len=tour.steps.length; index
    '); + } + + 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(); }); - } else { - T.nextStep(); - } - } -}; -T.check = function (step) { - return (step && - (!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) && - (!step.waitNot || !$(step.waitNot).size()) && - (!step.waitFor || $(step.waitFor).size())); -}; -T.waitNextStep = function () { - var state = T.getState(); - var time = new Date().getTime(); - var timer; - var next = state.tour.steps[state.step.id+1]; - var overlaps = state.mode === "test" ? T.errorDelay : 0; - window.onbeforeunload = function () { + 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.render('website.tour_popover_title', options); + }, + popover: function (options) { + return openerp.qweb.render('website.tour_popover', options); + }, + getLang: function () { + return $("html").attr("lang").replace(/-/, '_'); + }, + getState: function () { + var state = JSON.parse(localStorage.getItem("tour") || 'false') || {}; + 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 = ""; + T.saveState(state.id, state.mode, state.step_id); + } + if (!state.id) { + return; + } + state.tour = T.tours[state.id]; + state.step = state.tour.steps[state.step_id]; + return state; + }, + error: function (message) { + var state = T.getState(); + message += '\n tour: ' + state.id + + '\n step: ' + state.step_id + ": '" + (state.step._title || state.step.title) + "'" + + '\n href: ' + window.location.href + + '\n referrer: ' + document.referrer + + '\n element: ' + Boolean(!state.step.element || ($(state.step.element).size() && $(state.step.element).is(":visible") && !$(state.step.element).is(":hidden"))) + + '\n waitNot: ' + Boolean(!state.step.waitNot || !$(state.step.waitNot).size()) + + '\n waitFor: ' + Boolean(!state.step.waitFor || $(state.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})); + }, + 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); - }; - - function checkNext () { - T.autoTogglePopover(); - - clearTimeout(T.timer); - if (T.check(next)) { - clearTimeout(T.currentTimer); - // use an other timeout for cke dom loading - setTimeout(function () { - T.nextStep(next); - }, T.defaultDelay); - } else if (!overlaps || new Date().getTime() - time < overlaps) { - T.timer = setTimeout(checkNext, T.defaultDelay); - } else { - T.error("Can't reach the next step"); - } - } - checkNext(); -}; -T.nextStep = function (step) { - var state = T.getState(); - - if (!state) { - return; - } - - step = step || state.step; - T.saveState(state.id, state.mode, step.id); - - T.autoTogglePopover(true); - - if (step.onload) { - step.onload(); - } - - var next = state.tour.steps[step.id+1]; - if (next) { - setTimeout(function () { - T.waitNextStep(); - if (state.mode === "test") { - setTimeout(function(){ - T.autoNextStep(state.tour, step); - }, T.defaultDelay); - } - }, next.wait || 0); - } else { - T.endTour(); - } -}; -T.endTour = function () { - var state = T.getState(); - var test = state.step.id >= state.tour.steps.length-1; - T.reset(); - if (test) { - console.log('ok'); - } else { - console.log('error'); - } -}; -T.autoNextStep = function (tour, step) { - clearTimeout(T.testtimer); - - function autoStep () { - if (!step) return; - - if (step.autoComplete) { - step.autoComplete(tour); - } - - $(".popover.tour [data-role='next']").click(); - - var $element = $(step.element); - if (!$element.size()) return; - - if (step.snippet) { - - T.autoDragAndDropSnippet($element); - - } else if (step.sampleText) { - - $element.trigger($.Event("keydown", { srcElement: $element })); - if ($element.is("input") ) { - $element.val(step.sampleText); - } if ($element.is("select")) { - $element.find("[value='"+step.sampleText+"'], option:contains('"+step.sampleText+"')").attr("selected", true); - $element.val(step.sampleText); + T.closePopover(); + }, + running: function () { + var state = T.getState(); + if (state) { + T.registerSteps(state.tour); + if ($.ajaxBusy) { + $(document).ajaxStop(function() { + setTimeout(function () { + T.nextStep(); + },0); + }); } else { - $element.html(step.sampleText); + T.nextStep(); } - setTimeout(function () { - $element.trigger($.Event("keyup", { srcElement: $element })); - $element.trigger($.Event("change", { srcElement: $element })); - }, T.defaultDelay<<1); - - } else if ($element.is(":visible")) { - - $element.trigger($.Event("mouseenter", { srcElement: $element[0] })); - $element.trigger($.Event("mousedown", { srcElement: $element[0] })); - - var evt = document.createEvent("MouseEvents"); - evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); - $element[0].dispatchEvent(evt); - - // trigger after for step like: mouseenter, next step click on button display with mouseenter - setTimeout(function () { - $element.trigger($.Event("mouseup", { srcElement: $element[0] })); - $element.trigger($.Event("mouseleave", { srcElement: $element[0] })); - }, 1000); } + }, + check: function (step) { + return (step && + (!step.element || ($(step.element).size() && $(step.element).is(":visible") && !$(step.element).is(":hidden"))) && + (!step.waitNot || !$(step.waitNot).size()) && + (!step.waitFor || $(step.waitFor).size())); + }, + waitNextStep: function () { + var state = T.getState(); + var time = new Date().getTime(); + var timer; + var next = state.tour.steps[state.step.id+1]; + var overlaps = state.mode === "test" ? T.errorDelay : 0; + + window.onbeforeunload = function () { + clearTimeout(T.timer); + clearTimeout(T.testtimer); + }; + + function checkNext () { + T.autoTogglePopover(); + + clearTimeout(T.timer); + if (T.check(next)) { + clearTimeout(T.currentTimer); + // use an other timeout for cke dom loading + setTimeout(function () { + T.nextStep(next); + }, T.defaultDelay); + } else if (!overlaps || new Date().getTime() - time < overlaps) { + T.timer = setTimeout(checkNext, T.defaultDelay); + } else { + T.error("Can't reach the next step"); + } + } + checkNext(); + }, + nextStep: function (step) { + var state = T.getState(); + + if (!state) { + return; + } + + step = step || state.step; + T.saveState(state.id, state.mode, step.id); + + T.autoTogglePopover(true); + + if (step.onload) { + step.onload(); + } + + var next = state.tour.steps[step.id+1]; + if (next) { + setTimeout(function () { + T.waitNextStep(); + if (state.mode === "test") { + setTimeout(function(){ + T.autoNextStep(state.tour, step); + }, T.defaultDelay); + } + }, next.wait || 0); + } else { + T.endTour(); + } + }, + endTour: function () { + var state = T.getState(); + var test = state.step.id >= state.tour.steps.length-1; + T.reset(); + if (test) { + console.log('ok'); + } else { + console.log('error'); + } + }, + autoNextStep: function (tour, step) { + clearTimeout(T.testtimer); + + function autoStep () { + if (!step) return; + + if (step.autoComplete) { + step.autoComplete(tour); + } + + $(".popover.tour [data-role='next']").click(); + + var $element = $(step.element); + if (!$element.size()) return; + + if (step.snippet) { + + T.autoDragAndDropSnippet($element); + + } else if (step.sampleText) { + + $element.trigger($.Event("keydown", { srcElement: $element })); + if ($element.is("input") ) { + $element.val(step.sampleText); + } if ($element.is("select")) { + $element.find("[value='"+step.sampleText+"'], option:contains('"+step.sampleText+"')").attr("selected", true); + $element.val(step.sampleText); + } else { + $element.html(step.sampleText); + } + setTimeout(function () { + $element.trigger($.Event("keyup", { srcElement: $element })); + $element.trigger($.Event("change", { srcElement: $element })); + }, T.defaultDelay<<1); + + } else if ($element.is(":visible")) { + + $element.trigger($.Event("mouseenter", { srcElement: $element[0] })); + $element.trigger($.Event("mousedown", { srcElement: $element[0] })); + + var evt = document.createEvent("MouseEvents"); + evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null); + $element[0].dispatchEvent(evt); + + // trigger after for step like: mouseenter, next step click on button display with mouseenter + setTimeout(function () { + $element.trigger($.Event("mouseup", { srcElement: $element[0] })); + $element.trigger($.Event("mouseleave", { srcElement: $element[0] })); + }, 1000); + } + } + T.testtimer = setTimeout(autoStep, 100); + }, + autoDragAndDropSnippet: function (selector) { + var $thumbnail = $(selector).first(); + var thumbnailPosition = $thumbnail.position(); + $thumbnail.trigger($.Event("mousedown", { which: 1, pageX: thumbnailPosition.left, pageY: thumbnailPosition.top })); + $thumbnail.trigger($.Event("mousemove", { which: 1, pageX: document.body.scrollWidth/2, pageY: document.body.scrollHeight/2 })); + var $dropZone = $(".oe_drop_zone").first(); + var dropPosition = $dropZone.position(); + $dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top })); } - T.testtimer = setTimeout(autoStep, 100); -}; -T.autoDragAndDropSnippet = function (selector) { - var $thumbnail = $(selector).first(); - var thumbnailPosition = $thumbnail.position(); - $thumbnail.trigger($.Event("mousedown", { which: 1, pageX: thumbnailPosition.left, pageY: thumbnailPosition.top })); - $thumbnail.trigger($.Event("mousemove", { which: 1, pageX: document.body.scrollWidth/2, pageY: document.body.scrollHeight/2 })); - var $dropZone = $(".oe_drop_zone").first(); - var dropPosition = $dropZone.position(); - $dropZone.trigger($.Event("mouseup", { which: 1, pageX: dropPosition.left, pageY: dropPosition.top })); }; //$(document).ready(T.running); From 24d37e284407a26987b1be3e539fa0243d81f656 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Fri, 21 Mar 2014 14:45:46 +0100 Subject: [PATCH 075/248] [FIX] website tour: template loading hide the real error bzr revid: chm@openerp.com-20140321134546-i5nw73en8thzrwc2 --- addons/website/static/src/js/website.tour.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index 6a5f8faab76..eed431e071b 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -286,10 +286,10 @@ var T = website.Tour = { } }, popoverTitle: function (tour, options) { - return openerp.qweb.render('website.tour_popover_title', options); + return openerp.qweb ? openerp.qweb.render('website.tour_popover_title', options) : options.title; }, popover: function (options) { - return openerp.qweb.render('website.tour_popover', options); + return openerp.qweb ? openerp.qweb.render('website.tour_popover', options) : options.title; }, getLang: function () { return $("html").attr("lang").replace(/-/, '_'); From 62814f9c2331340a5721331d652b0fdc0d2a201d Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Mon, 24 Mar 2014 09:11:12 +0100 Subject: [PATCH 076/248] [FIX] website: activate new tour tests bzr revid: chm@openerp.com-20140324081112-15n58puu29weydme --- addons/website/tests/test_ui.py | 2 +- addons/website_blog/tests/test_ui.py | 2 +- addons/website_event/tests/test_ui.py | 2 +- addons/website_event_sale/tests/test_ui.py | 6 +++--- addons/website_sale/tests/test_ui.py | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/website/tests/test_ui.py b/addons/website/tests/test_ui.py index 54cd8a73a67..7eb88d00df3 100644 --- a/addons/website/tests/test_ui.py +++ b/addons/website/tests/test_ui.py @@ -8,6 +8,6 @@ class TestUi(openerp.tests.HttpCase): self.phantom_js("/", "console.log('ok')", "openerp.website.editor", login='admin') 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: diff --git a/addons/website_blog/tests/test_ui.py b/addons/website_blog/tests/test_ui.py index e99884ba4b1..35b7fdc56e7 100644 --- a/addons/website_blog/tests/test_ui.py +++ b/addons/website_blog/tests/test_ui.py @@ -2,5 +2,5 @@ import openerp.tests class TestUi(openerp.tests.HttpCase): 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") diff --git a/addons/website_event/tests/test_ui.py b/addons/website_event/tests/test_ui.py index c4e884c0325..b59cdd94dcc 100644 --- a/addons/website_event/tests/test_ui.py +++ b/addons/website_event/tests/test_ui.py @@ -2,5 +2,5 @@ import openerp.tests class TestUi(openerp.tests.HttpCase): 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") diff --git a/addons/website_event_sale/tests/test_ui.py b/addons/website_event_sale/tests/test_ui.py index b5950aaec54..b204b2bad69 100644 --- a/addons/website_event_sale/tests/test_ui.py +++ b/addons/website_event_sale/tests/test_ui.py @@ -9,11 +9,11 @@ inject = [ @openerp.tests.common.post_install(True) class TestUi(openerp.tests.HttpCase): 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", inject=inject) 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", login="demo", password="demo", inject=inject); 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", login=None, inject=inject); diff --git a/addons/website_sale/tests/test_ui.py b/addons/website_sale/tests/test_ui.py index 0eb5daae97a..0cedf2d0409 100644 --- a/addons/website_sale/tests/test_ui.py +++ b/addons/website_sale/tests/test_ui.py @@ -11,13 +11,13 @@ inject = [ @openerp.tests.common.post_install(True) class TestUi(openerp.tests.HttpCase): 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.Shop", login="admin") 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.ShopTest", login="admin", inject=inject) 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.ShopTest", login="demo", inject=inject) 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.ShopTest", inject=inject) From 26f807fa025ca99a9d0cf4e0212d395bb726d570 Mon Sep 17 00:00:00 2001 From: Amit Dodiya Date: Tue, 25 Mar 2014 11:17:43 +0530 Subject: [PATCH 077/248] [FIX] account_voucher: forward port of 6.0 revision: 5094, for issue cancel_voucher method is unlinking the whole account_move_reconciliation record bzr revid: ado@tinyerp.com-20140325054743-opywyna9w1toyjp8 --- addons/account_voucher/account_voucher.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index f58c640b11c..86755ce17b6 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -947,19 +947,15 @@ class account_voucher(osv.osv): def cancel_voucher(self, cr, uid, ids, context=None): reconcile_pool = self.pool.get('account.move.reconcile') move_pool = self.pool.get('account.move') - + move_line_pool = self.pool.get('account.move.line') for voucher in self.browse(cr, uid, ids, context=context): - # refresh to make sure you don't unlink an already removed move - voucher.refresh() - recs = [] for line in voucher.move_ids: if line.reconcile_id: - recs += [line.reconcile_id.id] - if line.reconcile_partial_id: - recs += [line.reconcile_partial_id.id] - - reconcile_pool.unlink(cr, uid, recs) - + move_lines = [move_line.id for move_line in line.reconcile_id.line_id] + move_lines.remove(line.id) + reconcile_pool.unlink(cr, uid, [line.reconcile_id.id]) + if len(move_lines) >= 2: + move_line_pool.reconcile_partial(cr, uid, move_lines, 'auto',context=context) if voucher.move_id: move_pool.button_cancel(cr, uid, [voucher.move_id.id]) move_pool.unlink(cr, uid, [voucher.move_id.id]) From b28a32f6ef398347ed0a207762a75c98a2d5a5b1 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Wed, 26 Mar 2014 15:44:42 +0100 Subject: [PATCH 078/248] [FIX] website: test_ui running bzr revid: chm@openerp.com-20140326144442-ye2a51f03wyaxi8a --- addons/website_blog/tests/test_ui.py | 2 +- addons/website_event/tests/test_ui.py | 2 +- addons/website_event_sale/tests/test_ui.py | 6 +++--- addons/website_sale/tests/test_ui.py | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/website_blog/tests/test_ui.py b/addons/website_blog/tests/test_ui.py index 35b7fdc56e7..b34ef25c002 100644 --- a/addons/website_blog/tests/test_ui.py +++ b/addons/website_blog/tests/test_ui.py @@ -2,5 +2,5 @@ import openerp.tests class TestUi(openerp.tests.HttpCase): def test_admin(self): - self.phantom_js("/", "openerp.website.Tour.run('blog', 'test')", "openerp.website.Tour") + self.phantom_js("/", "openerp.website.Tour.run('blog', 'test')", "openerp.website.Tour.tours.blog") diff --git a/addons/website_event/tests/test_ui.py b/addons/website_event/tests/test_ui.py index b59cdd94dcc..96a17a91563 100644 --- a/addons/website_event/tests/test_ui.py +++ b/addons/website_event/tests/test_ui.py @@ -2,5 +2,5 @@ import openerp.tests class TestUi(openerp.tests.HttpCase): def test_admin(self): - self.phantom_js("/", "openerp.website.Tour.run('event', 'test')", "openerp.website.Tour") + self.phantom_js("/", "openerp.website.Tour.run('event', 'test')", "openerp.website.Tour.tours.event") diff --git a/addons/website_event_sale/tests/test_ui.py b/addons/website_event_sale/tests/test_ui.py index b204b2bad69..3e26fba5cf4 100644 --- a/addons/website_event_sale/tests/test_ui.py +++ b/addons/website_event_sale/tests/test_ui.py @@ -9,11 +9,11 @@ inject = [ @openerp.tests.common.post_install(True) class TestUi(openerp.tests.HttpCase): def test_admin(self): - self.phantom_js("/", "openerp.website.Tour.run('event_buy_tickets', 'test')", "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): - self.phantom_js("/", "openerp.website.Tour.run('event_buy_tickets', 'test')", "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): - self.phantom_js("/", "openerp.website.Tour.run('event_buy_tickets', 'test')", "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); diff --git a/addons/website_sale/tests/test_ui.py b/addons/website_sale/tests/test_ui.py index 0cedf2d0409..61b0e904abf 100644 --- a/addons/website_sale/tests/test_ui.py +++ b/addons/website_sale/tests/test_ui.py @@ -4,20 +4,20 @@ import openerp.tests inject = [ ("openerp.website.Tour", os.path.join(os.path.dirname(__file__), '../../website/static/src/js/website.tour.js')), - ("openerp.website.Tour.ShopTest", os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.sale.js")), + ("openerp.website.Tour.tours.shop_buy_product", os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.sale.js")), ] @openerp.tests.common.at_install(False) @openerp.tests.common.post_install(True) class TestUi(openerp.tests.HttpCase): def test_01_admin_shop_tour(self): - self.phantom_js("/", "openerp.website.Tour.run('shop', 'test')", "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): - self.phantom_js("/", "openerp.website.Tour.run('shop_buy_product', 'test')", "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): - self.phantom_js("/", "openerp.website.Tour.run('shop_buy_product', 'test')", "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): - self.phantom_js("/", "openerp.website.Tour.run('shop_buy_product', 'test')", "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) From d892a5b38e4d882a029378a3a331e38299dfd8cc Mon Sep 17 00:00:00 2001 From: Amit Vora Date: Fri, 28 Mar 2014 12:00:12 +0530 Subject: [PATCH 079/248] [IMP] improve code bzr revid: avo@tinyerp.com-20140328063012-mxvgudl5b3219j2i --- addons/crm/crm_lead.py | 4 +++- addons/crm/crm_lead_view.xml | 5 ++--- addons/crm/res_partner.py | 10 ++++++---- addons/crm/res_partner_view.xml | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 4da0a509ed1..0154a0c6977 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -79,7 +79,9 @@ class crm_lead(format_address, osv.osv): 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.fold and obj.stage_id.sequence > 1, }, } - + def schedule_meeting(self, cr, uid, id, context=None): + return self.pool.get('res.partner').schedule_meeting(cr, uid, id, context=context) + def get_empty_list_help(self, cr, uid, help, context=None): if context.get('default_type') == 'lead': context['empty_list_help_model'] = 'crm.case.section' diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 1c41643405d..76e97dfd354 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -392,9 +392,8 @@
    + - - @@ -142,7 +141,7 @@ - + diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index 33f737aa66e..457d8f33a07 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -203,7 +203,7 @@ - Products + Expense Categories product.product form kanban,tree,form diff --git a/addons/hr_payroll/hr_payroll_view.xml b/addons/hr_payroll/hr_payroll_view.xml index 4410784c63c..564edf57c02 100644 --- a/addons/hr_payroll/hr_payroll_view.xml +++ b/addons/hr_payroll/hr_payroll_view.xml @@ -500,11 +500,15 @@ hr.contribution.register.form hr.contribution.register -
    - - - - + + + + + + + + +
    diff --git a/addons/l10n_fr_rib/bank_view.xml b/addons/l10n_fr_rib/bank_view.xml index 414ad51954a..9a2b92c176a 100644 --- a/addons/l10n_fr_rib/bank_view.xml +++ b/addons/l10n_fr_rib/bank_view.xml @@ -22,11 +22,11 @@ - - + + - - + + diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index c5fa52afe29..dc2cd126fe0 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -427,12 +427,16 @@ - - - - + + + + + + + + - @@ -461,7 +465,7 @@ - + diff --git a/addons/product/pricelist_view.xml b/addons/product/pricelist_view.xml index 784a14228d5..8d725b3beee 100644 --- a/addons/product/pricelist_view.xml +++ b/addons/product/pricelist_view.xml @@ -12,15 +12,23 @@ product.pricelist.version
    - - - - - - - + + + + + + + + + + + - + + + + + diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml index 4946a71f80b..0746f261339 100644 --- a/addons/product/product_view.xml +++ b/addons/product/product_view.xml @@ -583,7 +583,7 @@ product.ul.form.view product.ul -
    + diff --git a/addons/purchase_requisition/purchase_requisition_view.xml b/addons/purchase_requisition/purchase_requisition_view.xml index da3a6d132ee..edb39de7637 100644 --- a/addons/purchase_requisition/purchase_requisition_view.xml +++ b/addons/purchase_requisition/purchase_requisition_view.xml @@ -37,15 +37,19 @@ -
    +
    +
    +
    -

    - -

    diff --git a/addons/resource/resource_view.xml b/addons/resource/resource_view.xml index 74f71ecfeea..752026005a3 100644 --- a/addons/resource/resource_view.xml +++ b/addons/resource/resource_view.xml @@ -216,7 +216,7 @@ - + diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml index e96652c11aa..f6c611e7a41 100644 --- a/addons/stock/stock_view.xml +++ b/addons/stock/stock_view.xml @@ -1557,7 +1557,7 @@ stock.incoterms.form stock.incoterms - + @@ -1690,7 +1690,7 @@ Stock Journals stock.journal - + From 3f7e567acc1542134d46aeb747a373588279d2f9 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Mon, 14 Apr 2014 10:14:51 +0200 Subject: [PATCH 099/248] [FIX] website bzr revid: chm@openerp.com-20140414081451-0hzjgaewtcok6rod --- addons/website/static/src/js/website.editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js index 365b8cf46ea..c2e2ed46783 100644 --- a/addons/website/static/src/js/website.editor.js +++ b/addons/website/static/src/js/website.editor.js @@ -544,7 +544,7 @@ observer.disconnect(); var editor = this.rte.editor; - var root = editor.element.$; + var root = editor.element && editor.element.$; editor.destroy(); // FIXME: select editables then filter by dirty? var defs = this.rte.fetch_editables(root) From a001e9c4bcadcd04a9c9dcd64b88aa6dc5bafb5c Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Mon, 14 Apr 2014 10:48:33 +0200 Subject: [PATCH 100/248] [FIX] website: tour for website_event_sale bzr revid: chm@openerp.com-20140414084833-gsanxrhysk7jn9bo --- .../static/src/js/website.tour.event_sale.js | 21 ++++++------------- addons/website_report/views/layouts.xml | 1 - 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/addons/website_event_sale/static/src/js/website.tour.event_sale.js b/addons/website_event_sale/static/src/js/website.tour.event_sale.js index 9a200ece499..333481bc349 100644 --- a/addons/website_event_sale/static/src/js/website.tour.event_sale.js +++ b/addons/website_event_sale/static/src/js/website.tour.event_sale.js @@ -11,32 +11,23 @@ steps: [ { title: "select event", - element: 'a[href*="/event"]:contains("Open Days in Los Angeles"):first', - }, - { - title: "go to register page", - waitNot: 'a[href*="/event"]:contains("Functional Webinar")', - autoComplete: function () { - // use onload if website_event_track is installed - if (!$('form:contains("Ticket Type")').size()) { - window.location.href = $('a[href*="/event/Open-Days-in-Los-Angeles"][href*="/register"]').attr("href"); - } - }, + element: 'a[href*="/event"]:contains("Conference on Business Applications"):first', }, { + waitNot: 'a[href*="/event"]:contains("Conference on Business Applications")', title: "select 2 Standard tickets", - element: 'select[name="ticket-1"]', + element: 'select:eq(0)', sampleText: '2', }, { title: "select 3 VIP tickets", - waitFor: 'select[name="ticket-1"] option:contains(2):selected', - element: 'select[name="ticket-2"]', + waitFor: 'select:eq(0) option:contains(2):selected', + element: 'select:eq(1)', sampleText: '3', }, { title: "Order Now", - waitFor: 'select[name="ticket-2"] option:contains(3):selected', + waitFor: 'select:eq(1) option:contains(3):selected', element: '.btn-primary:contains("Order Now")', }, { diff --git a/addons/website_report/views/layouts.xml b/addons/website_report/views/layouts.xml index c17fdf8c1ab..c9b2508489a 100644 --- a/addons/website_report/views/layouts.xml +++ b/addons/website_report/views/layouts.xml @@ -49,7 +49,6 @@ - From 7a61539141bc988b6bfce6beb6ceabde9198c176 Mon Sep 17 00:00:00 2001 From: "Mansi Kariya (OpenERP)" Date: Mon, 14 Apr 2014 15:11:29 +0530 Subject: [PATCH 101/248] [REM] Removed Duplicated Menu bzr revid: mka@tinyerp.com-20140414094129-dyeeu4zk6pgnz951 --- addons/account_followup/account_followup_view.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/account_followup/account_followup_view.xml b/addons/account_followup/account_followup_view.xml index 675edd1d52c..24fff3a8833 100644 --- a/addons/account_followup/account_followup_view.xml +++ b/addons/account_followup/account_followup_view.xml @@ -139,7 +139,6 @@ - account.move.line.partner.tree From 0d7b0108ed424c321a2c7da257180ace116f61a3 Mon Sep 17 00:00:00 2001 From: DJ Patel Date: Mon, 14 Apr 2014 15:51:23 +0530 Subject: [PATCH 102/248] [IMP] crm, project_gtd : Improved the filter string. bzr revid: mdi@tinyerp.com-20140414102123-j2bu0s4107hgh003 --- addons/crm/crm_lead_view.xml | 4 ++-- addons/project_gtd/project_gtd_view.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index a0d4bb4865e..a1ef15863c3 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -581,8 +581,8 @@ - - + + diff --git a/addons/project_gtd/project_gtd_view.xml b/addons/project_gtd/project_gtd_view.xml index 8335ae35c93..0ae335d9bfb 100644 --- a/addons/project_gtd/project_gtd_view.xml +++ b/addons/project_gtd/project_gtd_view.xml @@ -106,8 +106,8 @@ - - + + From 733f344ff623fce18400cdb743c349816045db93 Mon Sep 17 00:00:00 2001 From: Randhir Mayatra rma-openerp Date: Mon, 14 Apr 2014 17:39:15 +0530 Subject: [PATCH 103/248] [IMP] add 'report' in sale dependancy bzr revid: rma@tinyerp.com-20140414120915-3huithw6481rss0j --- addons/sale/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sale/__openerp__.py b/addons/sale/__openerp__.py index c330e01d7ca..65269b75153 100644 --- a/addons/sale/__openerp__.py +++ b/addons/sale/__openerp__.py @@ -59,7 +59,7 @@ The Dashboard for the Sales Manager will include 'author': 'OpenERP SA', 'website': 'http://www.openerp.com', 'images': ['images/Sale_order_line_to_invoice.jpeg','images/sale_order.jpeg','images/sales_analysis.jpeg'], - 'depends': ['account_voucher'], + 'depends': ['account_voucher', 'report'], 'data': [ 'wizard/sale_make_invoice_advance.xml', 'wizard/sale_line_invoice.xml', From f44a31dd27cedc9d3331319298463396fde094d6 Mon Sep 17 00:00:00 2001 From: Randhir Mayatra rma-openerp Date: Mon, 14 Apr 2014 18:41:31 +0530 Subject: [PATCH 104/248] [IMP] remove extra action from membership bzr revid: rma@tinyerp.com-20140414131131-y0qjfqkb2dlrh2o5 --- addons/membership/report/report_membership_view.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/addons/membership/report/report_membership_view.xml b/addons/membership/report/report_membership_view.xml index 100ec32043f..ab1b1013e50 100644 --- a/addons/membership/report/report_membership_view.xml +++ b/addons/membership/report/report_membership_view.xml @@ -54,13 +54,6 @@ {"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} - - - graph - - - - Date: Tue, 15 Apr 2014 14:44:28 +0530 Subject: [PATCH 105/248] [FIX] account_anglo_saxon: Enabled the multi-currency support for price diff calculation. (Maintenance Case: 606408) bzr revid: rgo@tinyerp.com-20140415091428-az1rx5ngz79j4fh6 --- addons/account_anglo_saxon/invoice.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/addons/account_anglo_saxon/invoice.py b/addons/account_anglo_saxon/invoice.py index f27d9b3ae72..a08346a29ed 100644 --- a/addons/account_anglo_saxon/invoice.py +++ b/addons/account_anglo_saxon/invoice.py @@ -117,9 +117,14 @@ class account_invoice_line(osv.osv): for line in res: if a == line['account_id'] and i_line.product_id.id == line['product_id']: uom = i_line.product_id.uos_id or i_line.product_id.uom_id - standard_price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id) - if standard_price != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc: - price_diff = i_line.price_unit - standard_price + converted_standard_price = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.product_id.standard_price, i_line.uos_id.id) + if inv.currency_id.id != company_currency: + standard_price = self.pool.get('res.currency').compute(cr, uid, company_currency, inv.currency_id.id, converted_standard_price, context={'date': inv.date_invoice}) + else: + standard_price = converted_standard_price + price_unit = self.pool.get('product.uom')._compute_price(cr, uid, uom.id, i_line.price_unit, i_line.uos_id.id) + if standard_price != price_unit and line['price_unit'] == i_line.price_unit and acc: + price_diff = price_unit - standard_price line.update({'price':standard_price * line['quantity']}) diff_res.append({ 'type':'src', From 9c0526b1bde33922fcf7dddf1e65bf4429b64bff Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Tue, 15 Apr 2014 17:37:34 +0200 Subject: [PATCH 106/248] [FIX] website tour: test mode + add log bzr revid: chm@openerp.com-20140415153734-5n2sz3xn01ydfeh6 --- addons/website/static/src/js/website.tour.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js index 28d80fb2272..368a316e6f7 100644 --- a/addons/website/static/src/js/website.tour.js +++ b/addons/website/static/src/js/website.tour.js @@ -98,15 +98,15 @@ var T = website.Tour = { T.tours[tour.id] = tour; }, run: function (tour_id, mode) { - if (localStorage.getItem("tour") && mode === "test") { // only one test running - return; - } 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 = "/"+T.getLang()+tour.path; + window.location.href = href; } else { + console.log("Tour Begin from run method"); T.saveState(tour.id, mode || tour.mode, 0); T.running(); } @@ -307,6 +307,7 @@ var T = website.Tour = { "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 || !T.tours[state.id]) { @@ -357,6 +358,7 @@ var T = website.Tour = { function run () { var state = T.getState(); if (state) { + console.log("Tour '"+state.id+"' is running"); T.registerSteps(state.tour); T.nextStep(); } From f658a55e4e66afeba98fdff37d30506ec38a2420 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Tue, 15 Apr 2014 18:03:31 +0200 Subject: [PATCH 107/248] [FIX] stock: before creating chained pickings, regroup moves by chained auto packing Before, all moves issued from a same purchase order were put in the same chained picking, and, therefore, the moves were all treated with the same behavior (manually, automaticaly, ...) bzr revid: dle@openerp.com-20140415160331-kzgib87qabvpc86p --- addons/stock/stock.py | 75 +++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index eaacbcb06a1..715578541eb 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -2082,41 +2082,46 @@ class stock_move(osv.osv): if context is None: context = {} seq_obj = self.pool.get('ir.sequence') - for picking, todo in self._chain_compute(cr, uid, moves, context=context).items(): - ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0]) - if picking: - # name of new picking according to its type - if ptype == 'internal': - new_pick_name = seq_obj.get(cr, uid,'stock.picking') - else : - new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype) - pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context) - # Need to check name of old picking because it always considers picking as "OUT" when created from Sales Order - old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id) - if old_ptype != picking.type: - old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype) - self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context) - else: - pickid = False - for move, (loc, dummy, delay, dummy, company_id, ptype, invoice_state) in todo: - new_id = move_obj.copy(cr, uid, move.id, { - 'location_id': move.location_dest_id.id, - 'location_dest_id': loc.id, - 'date': time.strftime('%Y-%m-%d'), - 'picking_id': pickid, - 'state': 'waiting', - 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) , - 'move_history_ids': [], - 'date_expected': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'), - 'move_history_ids2': []} - ) - move_obj.write(cr, uid, [move.id], { - 'move_dest_id': new_id, - 'move_history_ids': [(4, new_id)] - }) - new_moves.append(self.browse(cr, uid, [new_id])[0]) - if pickid: - wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr) + for picking, chained_moves in self._chain_compute(cr, uid, moves, context=context).items(): + # We group the moves by automatic move type, so it creates different pickings for different types + moves_by_type = {} + for move in chained_moves: + moves_by_type.setdefault(move[1][1], []).append(move) + for todo in moves_by_type.values(): + ptype = todo[0][1][5] and todo[0][1][5] or location_obj.picking_type_get(cr, uid, todo[0][0].location_dest_id, todo[0][1][0]) + if picking: + # name of new picking according to its type + if ptype == 'internal': + new_pick_name = seq_obj.get(cr, uid,'stock.picking') + else : + new_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + ptype) + pickid = self._create_chained_picking(cr, uid, new_pick_name, picking, ptype, todo, context=context) + # Need to check name of old picking because it always considers picking as "OUT" when created from Sales Order + old_ptype = location_obj.picking_type_get(cr, uid, picking.move_lines[0].location_id, picking.move_lines[0].location_dest_id) + if old_ptype != picking.type: + old_pick_name = seq_obj.get(cr, uid, 'stock.picking.' + old_ptype) + self.pool.get('stock.picking').write(cr, uid, [picking.id], {'name': old_pick_name, 'type': old_ptype}, context=context) + else: + pickid = False + for move, (loc, dummy, delay, dummy, company_id, ptype, invoice_state) in todo: + new_id = move_obj.copy(cr, uid, move.id, { + 'location_id': move.location_dest_id.id, + 'location_dest_id': loc.id, + 'date': time.strftime('%Y-%m-%d'), + 'picking_id': pickid, + 'state': 'waiting', + 'company_id': company_id or res_obj._company_default_get(cr, uid, 'stock.company', context=context) , + 'move_history_ids': [], + 'date_expected': (datetime.strptime(move.date, '%Y-%m-%d %H:%M:%S') + relativedelta(days=delay or 0)).strftime('%Y-%m-%d'), + 'move_history_ids2': []} + ) + move_obj.write(cr, uid, [move.id], { + 'move_dest_id': new_id, + 'move_history_ids': [(4, new_id)] + }) + new_moves.append(self.browse(cr, uid, [new_id])[0]) + if pickid: + wf_service.trg_validate(uid, 'stock.picking', pickid, 'button_confirm', cr) if new_moves: new_moves += self.create_chained_picking(cr, uid, new_moves, context) return new_moves From 1ab962d33829fd07d0cef84e3dbe4d913333aadb Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Tue, 15 Apr 2014 18:14:41 +0200 Subject: [PATCH 108/248] [FIX] mail: convert attachments to binary as it is the expected format of message_post opw 604205 The double convertion (render_message and send_mail) is done to keep the API but should be changed in next version. bzr revid: mat@openerp.com-20140415161441-q6pfueetvv0namgw --- addons/email_template/email_template.py | 3 ++- addons/mail/wizard/mail_compose_message.py | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py index 8890226f28b..30417acb70a 100644 --- a/addons/email_template/email_template.py +++ b/addons/email_template/email_template.py @@ -305,7 +305,7 @@ class email_template(osv.osv): is taken from template definition) :returns: a dict containing all relevant fields for creating a new mail.mail entry, with one extra key ``attachments``, in the - format expected by :py:meth:`mail_thread.message_post`. + format [(report_name, data)] where data is base64 encoded. """ if context is None: context = {} @@ -340,6 +340,7 @@ class email_template(osv.osv): ctx['lang'] = self.render_template(cr, uid, template.lang, template.model, res_id, context) service = netsvc.LocalService(report_service) (result, format) = service.create(cr, uid, [res_id], {'model': template.model}, ctx) + # TODO in trunk, change return format to binary to match message_post expected format result = base64.b64encode(result) if not report_name: report_name = report_service diff --git a/addons/mail/wizard/mail_compose_message.py b/addons/mail/wizard/mail_compose_message.py index 301dff515b3..7e269ab7379 100644 --- a/addons/mail/wizard/mail_compose_message.py +++ b/addons/mail/wizard/mail_compose_message.py @@ -19,6 +19,7 @@ # ############################################################################## +import base64 import re from openerp import tools from openerp import SUPERUSER_ID @@ -237,12 +238,15 @@ class mail_compose_message(osv.TransientModel): 'parent_id': wizard.parent_id and wizard.parent_id.id, 'partner_ids': [partner.id for partner in wizard.partner_ids], 'attachment_ids': [attach.id for attach in wizard.attachment_ids], + 'attachments': [], } # mass mailing: render and override default values if mass_mail_mode and wizard.model: email_dict = self.render_message(cr, uid, wizard, res_id, context=context) post_values['partner_ids'] += email_dict.pop('partner_ids', []) - post_values['attachments'] = email_dict.pop('attachments', []) + for filename, attachment_data in email_dict.pop('attachments', []): + # decode as render message return in base64 while message_post expect binary + post_values['attachments'].append((filename, base64.b64decode(attachment_data))) attachment_ids = [] for attach_id in post_values.pop('attachment_ids'): new_attach_id = ir_attachment_obj.copy(cr, uid, attach_id, {'res_model': self._name, 'res_id': wizard.id}, context=context) From 31a8dfaf4354b68ad750f5f1051ace73812027ef Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Wed, 16 Apr 2014 07:06:27 +0000 Subject: [PATCH 109/248] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20140416070627-eneildfcgmfpyjxy --- addons/auth_signup/i18n/zh_CN.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addons/auth_signup/i18n/zh_CN.po b/addons/auth_signup/i18n/zh_CN.po index 31b1cff4192..a4d8533c0c1 100644 --- a/addons/auth_signup/i18n/zh_CN.po +++ b/addons/auth_signup/i18n/zh_CN.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openobject-addons\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2013-06-07 19:36+0000\n" -"PO-Revision-Date: 2014-02-17 02:37+0000\n" -"Last-Translator: jackjc \n" +"PO-Revision-Date: 2014-04-16 05:21+0000\n" +"Last-Translator: 盈通 ccdos \n" "Language-Team: Chinese (Simplified) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2014-02-18 05:40+0000\n" -"X-Generator: Launchpad (build 16916)\n" +"X-Launchpad-Export-Date: 2014-04-16 07:06+0000\n" +"X-Generator: Launchpad (build 16976)\n" #. module: auth_signup #: view:res.users:0 @@ -32,14 +32,14 @@ msgstr "注册令牌(Token)类型" #. module: auth_signup #: field:base.config.settings,auth_signup_uninvited:0 msgid "Allow external users to sign up" -msgstr "允许外部用户登录" +msgstr "允许外部用户注册" #. module: auth_signup #. openerp-web #: code:addons/auth_signup/static/src/xml/auth_signup.xml:19 #, python-format msgid "Confirm Password" -msgstr "口令确认" +msgstr "确认密码" #. module: auth_signup #: help:base.config.settings,auth_signup_uninvited:0 From 9284bd4817e970ff26cb17d3cd8aff0d5c2efb24 Mon Sep 17 00:00:00 2001 From: "chm@openerp.com" <> Date: Wed, 16 Apr 2014 10:21:38 +0200 Subject: [PATCH 110/248] [FIX] website: tour test inject javascript bzr revid: chm@openerp.com-20140416082138-rhwo2tl9l6jrko78 --- addons/website_event_sale/tests/test_ui.py | 4 ++-- addons/website_sale/tests/test_ui.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/website_event_sale/tests/test_ui.py b/addons/website_event_sale/tests/test_ui.py index fccbabb9d18..9e0ae31484e 100644 --- a/addons/website_event_sale/tests/test_ui.py +++ b/addons/website_event_sale/tests/test_ui.py @@ -3,8 +3,8 @@ import os import openerp.tests inject = [ - ("openerp.website.Tour", os.path.join(os.path.dirname(__file__), '../../website/static/src/js/website.tour.js')), - ("openerp.website.Tour.tours.event_buy_tickets", os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.event_sale.js")), + os.path.join(os.path.dirname(__file__), '../../website/static/src/js/website.tour.js'), + os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.event_sale.js"), ] @openerp.tests.common.at_install(False) diff --git a/addons/website_sale/tests/test_ui.py b/addons/website_sale/tests/test_ui.py index 61b0e904abf..e242bb0b557 100644 --- a/addons/website_sale/tests/test_ui.py +++ b/addons/website_sale/tests/test_ui.py @@ -3,8 +3,8 @@ import os import openerp.tests inject = [ - ("openerp.website.Tour", os.path.join(os.path.dirname(__file__), '../../website/static/src/js/website.tour.js')), - ("openerp.website.Tour.tours.shop_buy_product", os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.sale.js")), + os.path.join(os.path.dirname(__file__), '../../website/static/src/js/website.tour.js'), + os.path.join(os.path.dirname(__file__), "../static/src/js/website.tour.sale.js"), ] @openerp.tests.common.at_install(False) From 40d3ae1e0f6efd644f05f151635a428a28c44caf Mon Sep 17 00:00:00 2001 From: Kersten Jeremy Date: Wed, 16 Apr 2014 10:29:24 +0200 Subject: [PATCH 111/248] [FIX] Record id are not always an integer. It could be a virtual id (str) as in calendar. bzr revid: jke@openerp.com-20140416082924-t52pvja4617zpkce --- addons/web/controllers/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 3015bb9c2e5..5030a977f18 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -1216,7 +1216,7 @@ class DataSet(http.Controller): records = getattr(request.session.model(model), method)(*args, **kwargs) for record in records: record['display_name'] = \ - names.get(record['id']) or "%s#%d" % (model, (record['id'])) + names.get(record['id']) or "{0}#{1}".format(model, (record['id'])) return records if method.startswith('_'): From c4164204b5496d0ed77f7049b09dc4596d84d5b8 Mon Sep 17 00:00:00 2001 From: Kersten Jeremy Date: Wed, 16 Apr 2014 10:34:11 +0200 Subject: [PATCH 112/248] [FIX] Website - fix path of script watch.js bzr revid: jke@openerp.com-20140416083411-a06k9sbiyda7zmrd --- addons/website/views/website_templates.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/website/views/website_templates.xml b/addons/website/views/website_templates.xml index e7f76e7e4aa..1640c9f51e2 100644 --- a/addons/website/views/website_templates.xml +++ b/addons/website/views/website_templates.xml @@ -43,7 +43,7 @@ t-att-data-view-xmlid="xmlid if editable else None" t-att-data-main-object="repr(main_object) if editable else None"> - + From 91930b470d000b863511b841b40d42c9ce1b0c98 Mon Sep 17 00:00:00 2001 From: Mohammed Shekha Date: Wed, 16 Apr 2014 14:08:57 +0530 Subject: [PATCH 113/248] [FIX]Fixed the issue of reference field throws traceback that view is undefined, the reason is that reference field passing DefaultFieldManager while creating instance of many2one widget and DefaultFieldManager is eventually extending instance.web.widget not instance.web.form.FormWidget and hence DefaultFieldmanager will nto having view attribute, instead of calling self.view.do_onchange, trigger changed_value which is going to do the same job. bzr revid: msh@tinyerp.com-20140416083857-sug0k4a28nkvgg27 --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index edb44e7ea06..11e2c4e6b7c 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3148,7 +3148,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc self.display_value = {}; self.render_value(); self.focus(); - self.view.do_onchange(self); + self.trigger('changed_value'); }); }); From cd25de6989577992a96140b9247f388f2582699c Mon Sep 17 00:00:00 2001 From: "Turkesh Patel (Open ERP)" Date: Wed, 16 Apr 2014 16:21:22 +0530 Subject: [PATCH 114/248] [ADD] website_doc: modue based on website_forum to show documentatoin based on questions and best answers. bzr revid: tpa@tinyerp.com-20140416105122-2368jv31gy26ek32 --- addons/website_doc/__init__.py | 4 + addons/website_doc/__openerp__.py | 48 +++++++++++ addons/website_doc/controllers/__init__.py | 3 + addons/website_doc/controllers/main.py | 61 +++++++++++++ addons/website_doc/data/doc_data.xml | 24 ++++++ addons/website_doc/data/doc_demo.xml | 22 +++++ addons/website_doc/models/__init__.py | 3 + addons/website_doc/models/doc.py | 37 ++++++++ .../website_doc/security/ir.model.access.csv | 3 + addons/website_doc/static/src/css/Makefile | 5 ++ .../static/src/css/website_doc.css | 0 .../static/src/css/website_doc.sass | 0 .../static/src/js/website_doc.editor.js | 31 +++++++ .../website_doc/static/src/js/website_doc.js | 12 +++ .../static/src/xml/website_doc.xml | 7 ++ addons/website_doc/views/doc.xml | 42 +++++++++ addons/website_doc/views/website_doc.xml | 86 +++++++++++++++++++ addons/website_forum/controllers/main.py | 7 +- addons/website_forum/views/website_forum.xml | 2 +- 19 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 addons/website_doc/__init__.py create mode 100644 addons/website_doc/__openerp__.py create mode 100644 addons/website_doc/controllers/__init__.py create mode 100644 addons/website_doc/controllers/main.py create mode 100644 addons/website_doc/data/doc_data.xml create mode 100644 addons/website_doc/data/doc_demo.xml create mode 100644 addons/website_doc/models/__init__.py create mode 100644 addons/website_doc/models/doc.py create mode 100644 addons/website_doc/security/ir.model.access.csv create mode 100644 addons/website_doc/static/src/css/Makefile create mode 100644 addons/website_doc/static/src/css/website_doc.css create mode 100644 addons/website_doc/static/src/css/website_doc.sass create mode 100644 addons/website_doc/static/src/js/website_doc.editor.js create mode 100644 addons/website_doc/static/src/js/website_doc.js create mode 100644 addons/website_doc/static/src/xml/website_doc.xml create mode 100644 addons/website_doc/views/doc.xml create mode 100644 addons/website_doc/views/website_doc.xml diff --git a/addons/website_doc/__init__.py b/addons/website_doc/__init__.py new file mode 100644 index 00000000000..bde83af3aea --- /dev/null +++ b/addons/website_doc/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +import controllers +import models diff --git a/addons/website_doc/__openerp__.py b/addons/website_doc/__openerp__.py new file mode 100644 index 00000000000..8bf980b3a70 --- /dev/null +++ b/addons/website_doc/__openerp__.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2014-Today OpenERP SA (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +{ + 'name': 'Documentation', + 'category': 'Website', + 'summary': 'Forum, Documentation', + 'version': '1.0', + 'description': """ +Documentation based on question and pertinent answers of Forum + """, + 'author': 'OpenERP SA', + 'depends': [ + 'website_forum' + ], + 'data': [ + 'data/doc_data.xml', + 'views/doc.xml', + 'views/website_doc.xml', + 'security/ir.model.access.csv', + ], + 'qweb': [ + 'static/src/xml/*.xml' + ], + 'demo': [ + 'data/doc_demo.xml', + ], + 'installable': True, + 'application': True, +} diff --git a/addons/website_doc/controllers/__init__.py b/addons/website_doc/controllers/__init__.py new file mode 100644 index 00000000000..bbd183e955b --- /dev/null +++ b/addons/website_doc/controllers/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import main diff --git a/addons/website_doc/controllers/main.py b/addons/website_doc/controllers/main.py new file mode 100644 index 00000000000..87a7a934a5e --- /dev/null +++ b/addons/website_doc/controllers/main.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + +from datetime import datetime +import werkzeug.urls +import simplejson + +from openerp import tools +from openerp import SUPERUSER_ID +from openerp.addons.web import http +from openerp.addons.web.controllers.main import login_redirect +from openerp.addons.web.http import request +from openerp.addons.website.controllers.main import Website as controllers +from openerp.addons.website.models.website import slug +from openerp.addons.website_forum.controllers.main import WebsiteForum + +controllers = controllers() + +class WebsiteDoc(http.Controller): + + @http.route(['/doc'], type='http', auth="public", website=True, multilang=True) + def documentation(self, content='', **kwargs): + cr, uid, context, toc_id = request.cr, request.uid, request.context, False + TOC = request.registry['documentation.toc'] + obj_ids = TOC.search(cr, uid, [], context=context) + toc = TOC.browse(cr, uid, obj_ids, context=context) + if content: + toc_ids = TOC.search(cr, uid, [('name', '=', content)], context=context) + toc_id = TOC.browse(cr, uid, toc_ids, context=context)[0] + value = { + 'documentaion_toc': toc, + 'toc_id': toc_id, + } + return request.website.render("website_doc.documentation", value) + + @http.route('/doc/new', type='http', auth="user", multilang=True, website=True) + def create_table_of_content(self, toc_name="New Table Of Content", **kwargs): + toc_id = request.registry['documentation.toc'].create(request.cr, request.uid, { + 'name': toc_name, + }, context=request.context) + return request.redirect("/doc/%s" % slug(toc_id)) + + #--------------------- + # Forum Posts + # -------------------- + +class WebsiteForum(WebsiteForum): + + def prepare_question_values(self, forum, **kwargs): + cr, uid, context = request.cr, request.uid, request.context + TOC = request.registry['documentation.toc'] + obj_ids = TOC.search(cr, uid, [], context=context) + toc = TOC.browse(cr, uid, obj_ids, context=context) + values = super(WebsiteForum, self).prepare_question_values(forum=forum, kwargs=kwargs) + values.update({'documentaion_toc': toc}) + return values + + @http.route('/forum/question/toc', type='json', auth="user", multilang=True, website=True) + def post_toc(self, post_id, toc_id): + toc_id = int(toc_id) if toc_id else False + request.registry['forum.post'].write(request.cr, request.uid, [int(post_id)], {'toc_id': toc_id}, context=request.context) + return True \ No newline at end of file diff --git a/addons/website_doc/data/doc_data.xml b/addons/website_doc/data/doc_data.xml new file mode 100644 index 00000000000..124fb68a83b --- /dev/null +++ b/addons/website_doc/data/doc_data.xml @@ -0,0 +1,24 @@ + + + + + + Documentation + + + 65 + + + + + Documentation + self + + + + + open + + + + diff --git a/addons/website_doc/data/doc_demo.xml b/addons/website_doc/data/doc_demo.xml new file mode 100644 index 00000000000..b02fa647fe3 --- /dev/null +++ b/addons/website_doc/data/doc_demo.xml @@ -0,0 +1,22 @@ + + + + + + + CMS & eCommerce + + + Employee Contract + + + + + + + + + + + + diff --git a/addons/website_doc/models/__init__.py b/addons/website_doc/models/__init__.py new file mode 100644 index 00000000000..30f5c61cfe0 --- /dev/null +++ b/addons/website_doc/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import doc diff --git a/addons/website_doc/models/doc.py b/addons/website_doc/models/doc.py new file mode 100644 index 00000000000..07a8cd3831a --- /dev/null +++ b/addons/website_doc/models/doc.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +import openerp +from openerp.osv import osv, fields +from openerp.tools.translate import _ + + +class Documentation(osv.Model): + _name = 'documentation.toc' + _description = 'Table Of Content For Documentation' + _inherit = ['website.seo.metadata'] + + _columns = { + 'name': fields.char('Name', required=True, translate=True), + 'post_ids': fields.one2many('forum.post', 'toc_id', 'Posts'), + } + +class Post(osv.Model): + _inherit = 'forum.post' + + def _get_pertinent_answer(self, cr, uid, ids, field_name=False, arg={}, context=None): + '''Set answer which have been accepted or have maximum votes''' + res = {} + for post in self.browse(cr, uid, ids, context=context): + pertinent_answer_ids = self.search(cr, uid, [('parent_id', '=', post.id)], order='is_correct, vote_count desc', context=context) + res[post.id] = pertinent_answer_ids[0] if pertinent_answer_ids else False + return res + + _columns = { + 'name': fields.char('Title', size=128), + 'toc_id': fields.many2one('documentation.toc', 'Table of Content'), + 'pertinent_answer_id':fields.function(_get_pertinent_answer, string="Pertinent Answer", type='many2one', relation="forum.post", + store={ + 'forum.post': (lambda self, cr, uid, ids, c={}: ids, [], 10), + } + ), + } diff --git a/addons/website_doc/security/ir.model.access.csv b/addons/website_doc/security/ir.model.access.csv new file mode 100644 index 00000000000..49767b2a203 --- /dev/null +++ b/addons/website_doc/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_documentation_toc,documentation.toc,model_documentation_toc,,1,0,0,0 + diff --git a/addons/website_doc/static/src/css/Makefile b/addons/website_doc/static/src/css/Makefile new file mode 100644 index 00000000000..3cae206a13a --- /dev/null +++ b/addons/website_doc/static/src/css/Makefile @@ -0,0 +1,5 @@ +all: website_doc.css +%.css: %.sass + sass -t expanded --compass --unix-newlines $< $@ +watch: + sass -t expanded --compass --unix-newlines --watch .:. diff --git a/addons/website_doc/static/src/css/website_doc.css b/addons/website_doc/static/src/css/website_doc.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/addons/website_doc/static/src/css/website_doc.sass b/addons/website_doc/static/src/css/website_doc.sass new file mode 100644 index 00000000000..e69de29bb2d diff --git a/addons/website_doc/static/src/js/website_doc.editor.js b/addons/website_doc/static/src/js/website_doc.editor.js new file mode 100644 index 00000000000..5f7af42544d --- /dev/null +++ b/addons/website_doc/static/src/js/website_doc.editor.js @@ -0,0 +1,31 @@ +(function() { + "use strict"; + + var website = openerp.website; + var _t = openerp._t; + website.add_template_file('/website_doc/static/src/xml/website_doc.xml'); + + website.is_editable = true; + website.EditorBar.include({ + start: function() { + website.is_editable_button = website.is_editable_button || !!$("#wrap").size(); + var res = this._super(); + this.$(".dropdown:has(.oe_content_menu)").removeClass("hidden"); + return res; + }, + events: _.extend({}, website.EditorBar.prototype.events, { + 'click a[data-action=new_toc]': function (ev) { + ev.preventDefault(); + website.prompt({ + id: "editor_new_toc", + window_title: _t("New Table Of Content"), + input: "Table Of Content Name", + }).then(function (toc_name) { + website.form('/doc/new', 'POST', { + toc_name: toc_name + }); + }); + } + }), + }); +})(); diff --git a/addons/website_doc/static/src/js/website_doc.js b/addons/website_doc/static/src/js/website_doc.js new file mode 100644 index 00000000000..fad553863c9 --- /dev/null +++ b/addons/website_doc/static/src/js/website_doc.js @@ -0,0 +1,12 @@ +$(document).ready(function () { + + $('.post_toc').change(function (ev) { + var $option = $(ev.currentTarget); + openerp.jsonRpc("/forum/question/toc", 'call', { + 'post_id' : $('#question').attr("value"), + 'toc_id': $option.attr("value"), + }) + return true; + }); + +}); diff --git a/addons/website_doc/static/src/xml/website_doc.xml b/addons/website_doc/static/src/xml/website_doc.xml new file mode 100644 index 00000000000..b1ea9191b00 --- /dev/null +++ b/addons/website_doc/static/src/xml/website_doc.xml @@ -0,0 +1,7 @@ + + + +
  • New Table Of Content
  • +
    +
    +
    diff --git a/addons/website_doc/views/doc.xml b/addons/website_doc/views/doc.xml new file mode 100644 index 00000000000..d629a4b22a9 --- /dev/null +++ b/addons/website_doc/views/doc.xml @@ -0,0 +1,42 @@ + + + + + + + documentation.toc.list + documentation.toc + + + + + + + + + documentation.toc.form + documentation.toc + + + + + + + + + + + + + + + Documentation TOC + documentation.toc + form + tree,form + + + + + + diff --git a/addons/website_doc/views/website_doc.xml b/addons/website_doc/views/website_doc.xml new file mode 100644 index 00000000000..6cb310b882a --- /dev/null +++ b/addons/website_doc/views/website_doc.xml @@ -0,0 +1,86 @@ + + + + + +