summaryrefslogtreecommitdiff
path: root/addons/website/static
diff options
context:
space:
mode:
authorXavier Morel <xmo@openerp.com>2013-10-14 10:54:59 +0200
committerXavier Morel <xmo@openerp.com>2013-10-14 10:54:59 +0200
commit2e352ce187d2685df64ebd36f669a8abd88d5f65 (patch)
tree529af9c967929ca13896e8464abdc8fe9d02710c /addons/website/static
parent3e349a2bf7c76f5136935b531c5b3fb65833e8be (diff)
parent063a698313e522596a0f784206a9d17b9f31dafa (diff)
[MERGE] from trunk
bzr revid: xmo@openerp.com-20131014085459-dhbypq0hg3lzzf3j
Diffstat (limited to 'addons/website/static')
-rwxr-xr-xaddons/website/static/lib/bootstrap-tour/bootstrap-tour.css43
-rwxr-xr-xaddons/website/static/lib/bootstrap-tour/bootstrap-tour.js559
-rw-r--r--addons/website/static/lib/nearest/README.md22
-rw-r--r--addons/website/static/lib/nearest/bower.json12
-rw-r--r--addons/website/static/lib/nearest/jquery.nearest.js223
-rw-r--r--addons/website/static/lib/nearest/jquery.nearest.min.js11
-rw-r--r--addons/website/static/lib/nearest/nearest.jquery.json24
-rw-r--r--addons/website/static/src/css/editor.css123
-rw-r--r--addons/website/static/src/css/editor.sass103
-rw-r--r--addons/website/static/src/css/website.css25
-rw-r--r--addons/website/static/src/css/website.sass22
-rw-r--r--addons/website/static/src/img/big_picture.pngbin126534 -> 642710 bytes
-rw-r--r--addons/website/static/src/img/drag_here.pngbin1969 -> 1295 bytes
-rw-r--r--addons/website/static/src/img/edit_here.pngbin0 -> 1626 bytes
-rw-r--r--addons/website/static/src/img/parallax/quote.pngbin0 -> 9429 bytes
-rw-r--r--addons/website/static/src/js/website.editor.js28
-rw-r--r--addons/website/static/src/js/website.seo.js2
-rw-r--r--addons/website/static/src/js/website.snippets.js216
-rw-r--r--addons/website/static/src/js/website.tour.js256
-rw-r--r--addons/website/static/src/xml/website.editor.xml2
-rw-r--r--addons/website/static/src/xml/website.tour.xml27
-rw-r--r--addons/website/static/src/xml/website.xml6
22 files changed, 1498 insertions, 206 deletions
diff --git a/addons/website/static/lib/bootstrap-tour/bootstrap-tour.css b/addons/website/static/lib/bootstrap-tour/bootstrap-tour.css
new file mode 100755
index 00000000000..72c6e8cbab7
--- /dev/null
+++ b/addons/website/static/lib/bootstrap-tour/bootstrap-tour.css
@@ -0,0 +1,43 @@
+.tour-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1009;
+ background-color: #000;
+ opacity: 0.8;
+}
+.tour-step-backdrop {
+ position: relative;
+ z-index: 1011;
+}
+.tour-step-background {
+ position: absolute;
+ z-index: 1010;
+ background: #fff;
+ border-radius: 6px;
+}
+.popover[class*="tour-"] .popover-navigation {
+ padding: 9px 14px;
+}
+.popover[class*="tour-"] .popover-navigation *[data-role=end] {
+ float: right;
+}
+.popover[class*="tour-"] .popover-navigation *[data-role=prev],
+.popover[class*="tour-"] .popover-navigation *[data-role=next],
+.popover[class*="tour-"] .popover-navigation *[data-role=end] {
+ cursor: pointer;
+}
+.popover[class*="tour-"] .popover-navigation *[data-role=prev].disabled,
+.popover[class*="tour-"] .popover-navigation *[data-role=next].disabled,
+.popover[class*="tour-"] .popover-navigation *[data-role=end].disabled {
+ cursor: default;
+}
+.popover[class*="tour-"].orphan {
+ position: fixed;
+ margin-top: 0;
+}
+.popover[class*="tour-"].orphan .arrow {
+ display: none;
+}
diff --git a/addons/website/static/lib/bootstrap-tour/bootstrap-tour.js b/addons/website/static/lib/bootstrap-tour/bootstrap-tour.js
new file mode 100755
index 00000000000..8b45d6da9ee
--- /dev/null
+++ b/addons/website/static/lib/bootstrap-tour/bootstrap-tour.js
@@ -0,0 +1,559 @@
+/* ===========================================================
+# bootstrap-tour - v0.6.1
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+(function() {
+ (function($, window) {
+ var Tour, document;
+ document = window.document;
+ Tour = (function() {
+ function Tour(options) {
+ this._options = $.extend({
+ name: "tour",
+ container: "body",
+ keyboard: true,
+ storage: window.localStorage,
+ debug: false,
+ backdrop: false,
+ redirect: true,
+ orphan: false,
+ basePath: "",
+ template: "<div class='popover'> <div class='arrow'></div> <h3 class='popover-title'></h3> <div class='popover-content'></div> <nav class='popover-navigation'> <div class='btn-group'> <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button> <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button> </div> <button class='btn btn-sm btn-default' data-role='end'>End tour</button> </nav> </div>",
+ afterSetState: function(key, value) {},
+ afterGetState: function(key, value) {},
+ afterRemoveState: function(key) {},
+ onStart: function(tour) {},
+ onEnd: function(tour) {},
+ onShow: function(tour) {},
+ onShown: function(tour) {},
+ onHide: function(tour) {},
+ onHidden: function(tour) {},
+ onNext: function(tour) {},
+ onPrev: function(tour) {}
+ }, options);
+ this._steps = [];
+ this.setCurrentStep();
+ this.backdrop = {
+ overlay: null,
+ $element: null,
+ $background: null
+ };
+ }
+
+ Tour.prototype.setState = function(key, value) {
+ var keyName;
+ if (this._options.storage) {
+ keyName = "" + this._options.name + "_" + key;
+ this._options.storage.setItem(keyName, value);
+ return this._options.afterSetState(keyName, value);
+ } else {
+ if (this._state == null) {
+ this._state = {};
+ }
+ return this._state[key] = value;
+ }
+ };
+
+ Tour.prototype.removeState = function(key) {
+ var keyName;
+ if (this._options.storage) {
+ keyName = "" + this._options.name + "_" + key;
+ this._options.storage.removeItem(keyName);
+ return this._options.afterRemoveState(keyName);
+ } else {
+ if (this._state != null) {
+ return delete this._state[key];
+ }
+ }
+ };
+
+ Tour.prototype.getState = function(key) {
+ var keyName, value;
+ if (this._options.storage) {
+ keyName = "" + this._options.name + "_" + key;
+ value = this._options.storage.getItem(keyName);
+ } else {
+ if (this._state != null) {
+ value = this._state[key];
+ }
+ }
+ if (value === void 0 || value === "null") {
+ value = null;
+ }
+ this._options.afterGetState(key, value);
+ return value;
+ };
+
+ Tour.prototype.addSteps = function(steps) {
+ var step, _i, _len, _results;
+ _results = [];
+ for (_i = 0, _len = steps.length; _i < _len; _i++) {
+ step = steps[_i];
+ _results.push(this.addStep(step));
+ }
+ return _results;
+ };
+
+ Tour.prototype.addStep = function(step) {
+ return this._steps.push(step);
+ };
+
+ Tour.prototype.getStep = function(i) {
+ if (this._steps[i] != null) {
+ return $.extend({
+ id: "step-" + i,
+ path: "",
+ placement: "right",
+ title: "",
+ content: "<p></p>",
+ next: i === this._steps.length - 1 ? -1 : i + 1,
+ prev: i - 1,
+ animation: true,
+ container: this._options.container,
+ backdrop: this._options.backdrop,
+ redirect: this._options.redirect,
+ orphan: this._options.orphan,
+ template: this._options.template,
+ onShow: this._options.onShow,
+ onShown: this._options.onShown,
+ onHide: this._options.onHide,
+ onHidden: this._options.onHidden,
+ onNext: this._options.onNext,
+ onPrev: this._options.onPrev
+ }, this._steps[i]);
+ }
+ };
+
+ Tour.prototype.start = function(force) {
+ var promise,
+ _this = this;
+ if (force == null) {
+ force = false;
+ }
+ if (this.ended() && !force) {
+ return this._debug("Tour ended, start prevented.");
+ }
+ $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]:not(.disabled)", function(e) {
+ e.preventDefault();
+ return _this.next();
+ });
+ $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]:not(.disabled)", function(e) {
+ e.preventDefault();
+ return _this.prev();
+ });
+ $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]", function(e) {
+ e.preventDefault();
+ return _this.end();
+ });
+ this._onResize(function() {
+ return _this.showStep(_this._current);
+ });
+ this._setupKeyboardNavigation();
+ promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
+ return this._callOnPromiseDone(promise, this.showStep, this._current);
+ };
+
+ Tour.prototype.next = function() {
+ var promise;
+ if (this.ended()) {
+ return this._debug("Tour ended, next prevented.");
+ }
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, this._showNextStep);
+ };
+
+ Tour.prototype.prev = function() {
+ var promise;
+ if (this.ended()) {
+ return this._debug("Tour ended, prev prevented.");
+ }
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, this._showPrevStep);
+ };
+
+ Tour.prototype.goto = function(i) {
+ var promise;
+ if (this.ended()) {
+ return this._debug("Tour ended, goto prevented.");
+ }
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, this.showStep, i);
+ };
+
+ Tour.prototype.end = function() {
+ var endHelper, hidePromise,
+ _this = this;
+ endHelper = function(e) {
+ $(document).off("click.tour-" + _this._options.name);
+ $(document).off("keyup.tour-" + _this._options.name);
+ $(window).off("resize.tour-" + _this._options.name);
+ _this.setState("end", "yes");
+ if (_this._options.onEnd != null) {
+ return _this._options.onEnd(_this);
+ }
+ };
+ hidePromise = this.hideStep(this._current);
+ return this._callOnPromiseDone(hidePromise, endHelper);
+ };
+
+ Tour.prototype.ended = function() {
+ return !!this.getState("end");
+ };
+
+ Tour.prototype.restart = function() {
+ this.removeState("current_step");
+ this.removeState("end");
+ this.setCurrentStep(0);
+ return this.start();
+ };
+
+ Tour.prototype.hideStep = function(i) {
+ var hideStepHelper, promise, step,
+ _this = this;
+ step = this.getStep(i);
+ promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
+ hideStepHelper = function(e) {
+ var $element;
+ $element = _this._isOrphan(step) ? $("body") : $(step.element);
+ $element.popover("destroy");
+ if (step.reflex) {
+ $element.css("cursor", "").off("click.tour-" + _this._options.name);
+ }
+ if (step.backdrop) {
+ _this._hideBackdrop();
+ }
+ if (step.onHidden != null) {
+ return step.onHidden(_this);
+ }
+ };
+ this._callOnPromiseDone(promise, hideStepHelper);
+ return promise;
+ };
+
+ Tour.prototype.showStep = function(i) {
+ var promise, showStepHelper, skipToPrevious, step,
+ _this = this;
+ step = this.getStep(i);
+ if (!step) {
+ return;
+ }
+ skipToPrevious = i < this._current;
+ promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
+ showStepHelper = function(e) {
+ var current_path, path;
+ _this.setCurrentStep(i);
+ path = $.isFunction(step.path) ? step.path.call() : _this._options.basePath + step.path;
+ current_path = [document.location.pathname, document.location.hash].join("");
+ if (_this._isRedirect(path, current_path)) {
+ _this._redirect(step, path);
+ return;
+ }
+ if (_this._isOrphan(step)) {
+ if (!step.orphan) {
+ _this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
+ if (skipToPrevious) {
+ _this._showPrevStep();
+ } else {
+ _this._showNextStep();
+ }
+ return;
+ }
+ _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
+ }
+ if (step.backdrop) {
+ _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
+ }
+ _this._showPopover(step, i);
+ if (step.onShown != null) {
+ step.onShown(_this);
+ }
+ return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length);
+ };
+ return this._callOnPromiseDone(promise, showStepHelper);
+ };
+
+ Tour.prototype.setCurrentStep = function(value) {
+ if (value != null) {
+ this._current = value;
+ return this.setState("current_step", value);
+ } else {
+ this._current = this.getState("current_step");
+ return this._current = this._current === null ? 0 : parseInt(this._current, 10);
+ }
+ };
+
+ Tour.prototype._showNextStep = function() {
+ var promise, showNextStepHelper, step,
+ _this = this;
+ step = this.getStep(this._current);
+ showNextStepHelper = function(e) {
+ return _this.showStep(step.next);
+ };
+ promise = this._makePromise((step.onNext != null ? step.onNext(this) : void 0));
+ return this._callOnPromiseDone(promise, showNextStepHelper);
+ };
+
+ Tour.prototype._showPrevStep = function() {
+ var promise, showPrevStepHelper, step,
+ _this = this;
+ step = this.getStep(this._current);
+ showPrevStepHelper = function(e) {
+ return _this.showStep(step.prev);
+ };
+ promise = this._makePromise((step.onPrev != null ? step.onPrev(this) : void 0));
+ return this._callOnPromiseDone(promise, showPrevStepHelper);
+ };
+
+ Tour.prototype._debug = function(text) {
+ if (this._options.debug) {
+ return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
+ }
+ };
+
+ Tour.prototype._isRedirect = function(path, currentPath) {
+ return (path != null) && path !== "" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, "");
+ };
+
+ Tour.prototype._redirect = function(step, path) {
+ if ($.isFunction(step.redirect)) {
+ return step.redirect.call(this, path);
+ } else if (step.redirect === true) {
+ this._debug("Redirect to " + path);
+ return document.location.href = path;
+ }
+ };
+
+ Tour.prototype._isOrphan = function(step) {
+ return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden");
+ };
+
+ Tour.prototype._showPopover = function(step, i) {
+ var $element, $navigation, $template, $tip, isOrphan, options,
+ _this = this;
+ options = $.extend({}, this._options);
+ $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
+ $navigation = $template.find(".popover-navigation");
+ isOrphan = this._isOrphan(step);
+ if (isOrphan) {
+ step.element = "body";
+ step.placement = "top";
+ $template = $template.addClass("orphan");
+ }
+ $element = $(step.element);
+ $template.addClass("tour-" + this._options.name);
+ if (step.options) {
+ $.extend(options, step.options);
+ }
+ if (step.reflex) {
+ $element.css("cursor", "pointer").on("click.tour-" + this._options.name, function(e) {
+ if (_this._current < _this._steps.length - 1) {
+ return _this.next();
+ } else {
+ return _this.end();
+ }
+ });
+ }
+ if (step.prev < 0) {
+ $navigation.find("*[data-role=prev]").addClass("disabled");
+ }
+ if (step.next < 0) {
+ $navigation.find("*[data-role=next]").addClass("disabled");
+ }
+ step.template = $template.clone().wrap("<div>").parent().html();
+ $element.popover({
+ placement: step.placement,
+ trigger: "manual",
+ title: step.title,
+ content: step.content,
+ html: true,
+ animation: step.animation,
+ container: step.container,
+ template: step.template,
+ selector: step.element
+ }).popover("show");
+ $tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
+ $tip.attr("id", step.id);
+ this._scrollIntoView($tip);
+ this._reposition($tip, step);
+ if (isOrphan) {
+ return this._center($tip);
+ }
+ };
+
+ Tour.prototype._reposition = function($tip, step) {
+ var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
+ offsetWidth = $tip[0].offsetWidth;
+ offsetHeight = $tip[0].offsetHeight;
+ tipOffset = $tip.offset();
+ originalLeft = tipOffset.left;
+ originalTop = tipOffset.top;
+ offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+ if (offsetBottom < 0) {
+ tipOffset.top = tipOffset.top + offsetBottom;
+ }
+ offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
+ if (offsetRight < 0) {
+ tipOffset.left = tipOffset.left + offsetRight;
+ }
+ if (tipOffset.top < 0) {
+ tipOffset.top = 0;
+ }
+ if (tipOffset.left < 0) {
+ tipOffset.left = 0;
+ }
+ $tip.offset(tipOffset);
+ if (step.placement === "bottom" || step.placement === "top") {
+ if (originalLeft !== tipOffset.left) {
+ return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
+ }
+ } else {
+ if (originalTop !== tipOffset.top) {
+ return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
+ }
+ }
+ };
+
+ Tour.prototype._center = function($tip) {
+ return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
+ };
+
+ Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
+ return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
+ };
+
+ Tour.prototype._scrollIntoView = function(tip) {
+ return $("html, body").stop().animate({
+ scrollTop: Math.ceil(tip.offset().top - ($(window).height() / 2))
+ });
+ };
+
+ Tour.prototype._onResize = function(callback, timeout) {
+ return $(window).on("resize.tour-" + this._options.name, function() {
+ clearTimeout(timeout);
+ return timeout = setTimeout(callback, 100);
+ });
+ };
+
+ Tour.prototype._setupKeyboardNavigation = function() {
+ var _this = this;
+ if (this._options.keyboard) {
+ return $(document).on("keyup.tour-" + this._options.name, function(e) {
+ if (!e.which) {
+ return;
+ }
+ switch (e.which) {
+ case 39:
+ e.preventDefault();
+ if (_this._current < _this._steps.length - 1) {
+ return _this.next();
+ } else {
+ return _this.end();
+ }
+ break;
+ case 37:
+ e.preventDefault();
+ if (_this._current > 0) {
+ return _this.prev();
+ }
+ break;
+ case 27:
+ e.preventDefault();
+ return _this.end();
+ }
+ });
+ }
+ };
+
+ Tour.prototype._makePromise = function(result) {
+ if (result && $.isFunction(result.then)) {
+ return result;
+ } else {
+ return null;
+ }
+ };
+
+ Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
+ var _this = this;
+ if (promise) {
+ return promise.then(function(e) {
+ return cb.call(_this, arg);
+ });
+ } else {
+ return cb.call(this, arg);
+ }
+ };
+
+ Tour.prototype._showBackdrop = function(element) {
+ if (this.backdrop.overlay !== null) {
+ return;
+ }
+ this._showOverlay();
+ if (element != null) {
+ return this._showOverlayElement(element);
+ }
+ };
+
+ Tour.prototype._hideBackdrop = function() {
+ if (this.backdrop.overlay === null) {
+ return;
+ }
+ if (this.backdrop.$element) {
+ this._hideOverlayElement();
+ }
+ return this._hideOverlay();
+ };
+
+ Tour.prototype._showOverlay = function() {
+ this.backdrop = $("<div/>", {
+ "class": "tour-backdrop"
+ });
+ return $("body").append(this.backdrop);
+ };
+
+ Tour.prototype._hideOverlay = function() {
+ this.backdrop.remove();
+ return this.backdrop.overlay = null;
+ };
+
+ Tour.prototype._showOverlayElement = function(element) {
+ var $background, $element, offset;
+ $element = $(element);
+ $background = $("<div/>");
+ offset = $element.offset();
+ offset.top = offset.top;
+ offset.left = offset.left;
+ $background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
+ $element.addClass("tour-step-backdrop");
+ $("body").append($background);
+ this.backdrop.$element = $element;
+ return this.backdrop.$background = $background;
+ };
+
+ Tour.prototype._hideOverlayElement = function() {
+ this.backdrop.$element.removeClass("tour-step-backdrop");
+ this.backdrop.$background.remove();
+ this.backdrop.$element = null;
+ return this.backdrop.$background = null;
+ };
+
+ return Tour;
+
+ })();
+ return window.Tour = Tour;
+ })(jQuery, window);
+
+}).call(this);
diff --git a/addons/website/static/lib/nearest/README.md b/addons/website/static/lib/nearest/README.md
new file mode 100644
index 00000000000..cc40c5fed38
--- /dev/null
+++ b/addons/website/static/lib/nearest/README.md
@@ -0,0 +1,22 @@
+jQuery Nearest Element plugin
+======
+
+**Full documentation is at <http://gilmoreorless.github.io/jquery-nearest/>**
+
+**Demo:** <http://gilmoreorless.github.io/jquery-nearest/demo.html>
+
+Method signatures:
+
+ * `$.nearest({x, y}, selector)` - find `$(selector)` closest to x/y point on screen
+ * `$(elem).nearest(selector)` - find `$(selector)` closest to elem
+ * `$(elemSet).nearest({x, y})` - filter `$(elemSet)` and return closest to x/y point on screen
+
+Reverse logic:
+
+ * `$.furthest()`
+ * `$(elem).furthest()`
+
+Intersecting/touching:
+
+ * `$.touching()`
+ * `$(elem).touching()`
diff --git a/addons/website/static/lib/nearest/bower.json b/addons/website/static/lib/nearest/bower.json
new file mode 100644
index 00000000000..27bad9c8785
--- /dev/null
+++ b/addons/website/static/lib/nearest/bower.json
@@ -0,0 +1,12 @@
+{
+ "name": "jquery-nearest",
+ "version": "1.2.1",
+ "main": "jquery.nearest.js",
+ "ignore": [
+ "**/.*",
+ "test"
+ ],
+ "dependencies": {
+ "jquery": ">=1.4"
+ }
+} \ No newline at end of file
diff --git a/addons/website/static/lib/nearest/jquery.nearest.js b/addons/website/static/lib/nearest/jquery.nearest.js
new file mode 100644
index 00000000000..7daab9ae209
--- /dev/null
+++ b/addons/website/static/lib/nearest/jquery.nearest.js
@@ -0,0 +1,223 @@
+/*!
+ * jQuery Nearest plugin v1.2.1
+ *
+ * Finds elements closest to a single point based on screen location and pixel dimensions
+ * http://gilmoreorless.github.com/jquery-nearest/
+ * Open source under the MIT licence: http://gilmoreorless.mit-license.org/2011/
+ *
+ * Requires jQuery 1.4 or above
+ * Also supports Ben Alman's "each2" plugin for faster looping (if available)
+ */
+
+/**
+ * Method signatures:
+ *
+ * $.nearest({x, y}, selector) - find $(selector) closest to point
+ * $(elem).nearest(selector) - find $(selector) closest to elem
+ * $(elemSet).nearest({x, y}) - filter $(elemSet) and return closest to point
+ *
+ * Also:
+ * $.furthest()
+ * $(elem).furthest()
+ *
+ * $.touching()
+ * $(elem).touching()
+ */
+;(function ($, undefined) {
+
+ /**
+ * Internal method that does the grunt work
+ *
+ * @param mixed selector Any valid jQuery selector providing elements to filter
+ * @param hash options Key/value list of options for matching elements
+ * @param mixed thisObj (optional) Any valid jQuery selector that represents self
+ * for the "includeSelf" option
+ * @return array List of matching elements, can be zero length
+ */
+ var rPerc = /^([\d.]+)%$/;
+ function nearest(selector, options, thisObj) {
+ // Normalise selector and dimensions
+ selector || (selector = 'div'); // I STRONGLY recommend passing in a selector
+ var $container = $(options.container),
+ containerOffset = $container.offset() || {left: 0, top: 0},
+ containerDims = [
+ containerOffset.left + $container.width(),
+ containerOffset.top + $container.height()
+ ],
+ percProps = {x: 0, y: 1, w: 0, h: 1},
+ prop, match;
+ for (prop in percProps) if (percProps.hasOwnProperty(prop)) {
+ match = rPerc.exec(options[prop]);
+ if (match) {
+ options[prop] = containerDims[percProps[prop]] * match[1] / 100;
+ }
+ }
+
+ // Get elements and work out x/y points
+ var $all = $(selector),
+ cache = [],
+ furthest = !!options.furthest,
+ checkX = !!options.checkHoriz,
+ checkY = !!options.checkVert,
+ compDist = furthest ? 0 : Infinity,
+ point1x = parseFloat(options.x) || 0,
+ point1y = parseFloat(options.y) || 0,
+ point2x = parseFloat(point1x + options.w) || point1x,
+ point2y = parseFloat(point1y + options.h) || point1y,
+ tolerance = options.tolerance || 0,
+ hasEach2 = !!$.fn.each2,
+ // Shortcuts to help with compression
+ min = Math.min,
+ max = Math.max;
+
+ // Normalise the remaining options
+ if (!options.includeSelf && thisObj) {
+ $all = $all.not(thisObj);
+ }
+ if (tolerance < 0) {
+ tolerance = 0;
+ }
+ // Loop through all elements and check their positions
+ $all[hasEach2 ? 'each2' : 'each'](function (i, elem) {
+ var $this = hasEach2 ? elem : $(this),
+ off = $this.offset(),
+ x = off.left,
+ y = off.top,
+ w = $this.outerWidth(),
+ h = $this.outerHeight(),
+ x2 = x + w,
+ y2 = y + h,
+ maxX1 = max(x, point1x),
+ minX2 = min(x2, point2x),
+ maxY1 = max(y, point1y),
+ minY2 = min(y2, point2y),
+ intersectX = minX2 >= maxX1,
+ intersectY = minY2 >= maxY1,
+ distX, distY, distT, isValid;
+ if (
+ // .nearest() / .furthest()
+ (checkX && checkY) ||
+ // .touching()
+ (!checkX && !checkY && intersectX && intersectY) ||
+ // .nearest({checkVert: false})
+ (checkX && intersectY) ||
+ // .nearest({checkHoriz: false})
+ (checkY && intersectX)
+ ) {
+ distX = intersectX ? 0 : maxX1 - minX2;
+ distY = intersectY ? 0 : maxY1 - minY2;
+ distT = intersectX || intersectY ?
+ max(distX, distY) :
+ Math.sqrt(distX * distX + distY * distY);
+ isValid = furthest ?
+ distT >= compDist - tolerance :
+ distT <= compDist + tolerance;
+ if (isValid) {
+ compDist = furthest ?
+ max(compDist, distT) :
+ min(compDist, distT);
+ cache.push({
+ node: this,
+ dist: distT
+ });
+ }
+ }
+ });
+ // Make sure all cached items are within tolerance range
+ var len = cache.length,
+ filtered = [],
+ compMin, compMax,
+ i, item;
+ if (len) {
+ if (furthest) {
+ compMin = compDist - tolerance;
+ compMax = compDist;
+ } else {
+ compMin = compDist;
+ compMax = compDist + tolerance;
+ }
+ for (i = 0; i < len; i++) {
+ item = cache[i];
+ if (item.dist >= compMin && item.dist <= compMax) {
+ filtered.push(item.node);
+ }
+ }
+ }
+ return filtered;
+ }
+
+ $.each(['nearest', 'furthest', 'touching'], function (i, name) {
+
+ // Internal default options
+ // Not exposed publicly because they're method-dependent and easily overwritten anyway
+ var defaults = {
+ x: 0, // X position of top left corner of point/region
+ y: 0, // Y position of top left corner of point/region
+ w: 0, // Width of region
+ h: 0, // Height of region
+ tolerance: 1, // Distance tolerance in pixels, mainly to handle fractional pixel rounding bugs
+ container: document, // Container of objects for calculating %-based dimensions
+ furthest: name == 'furthest', // Find max distance (true) or min distance (false)
+ includeSelf: false, // Include 'this' in search results (t/f) - only applies to $(elem).func(selector) syntax
+ checkHoriz: name != 'touching', // Check variations in X axis (t/f)
+ checkVert: name != 'touching' // Check variations in Y axis (t/f)
+ };
+
+ /**
+ * $.nearest() / $.furthest() / $.touching()
+ *
+ * Utility functions for finding elements near a specific point or region on screen
+ *
+ * @param hash point Co-ordinates for the point or region to measure from
+ * "x" and "y" keys are required, "w" and "h" keys are optional
+ * @param mixed selector Any valid jQuery selector that provides elements to filter
+ * @param hash options (optional) Extra filtering options
+ * Not technically needed as the options could go on the point object,
+ * but it's good to have a consistent API
+ * @return jQuery object containing matching elements in selector
+ */
+ $[name] = function (point, selector, options) {
+ if (!point || point.x === undefined || point.y === undefined) {
+ return $([]);
+ }
+ var opts = $.extend({}, defaults, point, options || {});
+ return $(nearest(selector, opts));
+ };
+
+ /**
+ * SIGNATURE 1:
+ * $(elem).nearest(selector) / $(elem).furthest(selector) / $(elem).touching(selector)
+ *
+ * Finds all elements in selector that are nearest to/furthest from elem
+ *
+ * @param mixed selector Any valid jQuery selector that provides elements to filter
+ * @param hash options (optional) Extra filtering options
+ * @return jQuery object containing matching elements in selector
+ *
+ * SIGNATURE 2:
+ * $(elemSet).nearest(point) / $(elemSet).furthest(point) / $(elemSet).touching(point)
+ *
+ * Filters elemSet to return only the elements nearest to/furthest from point
+ * Effectively a wrapper for $.nearest(point, elemSet) but with the benefits of method chaining
+ *
+ * @param hash point Co-ordinates for the point or region to measure from
+ * @return jQuery object containing matching elements in elemSet
+ */
+ $.fn[name] = function (selector, options) {
+ var opts;
+ if (selector && $.isPlainObject(selector)) {
+ opts = $.extend({}, defaults, selector, options || {});
+ return this.pushStack(nearest(this, opts));
+ }
+ var offset = this.offset(),
+ dimensions = {
+ x: offset.left,
+ y: offset.top,
+ w: this.outerWidth(),
+ h: this.outerHeight()
+ };
+ opts = $.extend({}, defaults, dimensions, options || {});
+ return this.pushStack(nearest(selector, opts, this));
+ };
+ });
+})(jQuery);
diff --git a/addons/website/static/lib/nearest/jquery.nearest.min.js b/addons/website/static/lib/nearest/jquery.nearest.min.js
new file mode 100644
index 00000000000..9bd37ca8733
--- /dev/null
+++ b/addons/website/static/lib/nearest/jquery.nearest.min.js
@@ -0,0 +1,11 @@
+/*!
+ * jQuery Nearest plugin v1.2.1
+ *
+ * Finds elements closest to a single point based on screen location and pixel dimensions
+ * http://gilmoreorless.github.com/jquery-nearest/
+ * Open source under the MIT licence: http://gilmoreorless.mit-license.org/2011/
+ *
+ * Requires jQuery 1.4 or above
+ * Also supports Ben Alman's "each2" plugin for faster looping (if available)
+ */
+;(function(e,t){function r(t,r,i){t||(t="div");var s=e(r.container),o=s.offset()||{left:0,top:0},u=[o.left+s.width(),o.top+s.height()],a={x:0,y:1,w:0,h:1},f,l;for(f in a)a.hasOwnProperty(f)&&(l=n.exec(r[f]),l&&(r[f]=u[a[f]]*l[1]/100));var c=e(t),h=[],p=!!r.furthest,d=!!r.checkHoriz,v=!!r.checkVert,m=p?0:Infinity,g=parseFloat(r.x)||0,y=parseFloat(r.y)||0,b=parseFloat(g+r.w)||g,w=parseFloat(y+r.h)||y,E=r.tolerance||0,S=!!e.fn.each2,x=Math.min,T=Math.max;!r.includeSelf&&i&&(c=c.not(i)),E<0&&(E=0),c[S?"each2":"each"](function(t,n){var r=S?n:e(this),i=r.offset(),s=i.left,o=i.top,u=r.outerWidth(),a=r.outerHeight(),f=s+u,l=o+a,c=T(s,g),N=x(f,b),C=T(o,y),k=x(l,w),L=N>=c,A=k>=C,O,M,_,D;if(d&&v||!d&&!v&&L&&A||d&&A||v&&L)O=L?0:c-N,M=A?0:C-k,_=L||A?T(O,M):Math.sqrt(O*O+M*M),D=p?_>=m-E:_<=m+E,D&&(m=p?T(m,_):x(m,_),h.push({node:this,dist:_}))});var N=h.length,C=[],k,L,A,O;if(N){p?(k=m-E,L=m):(k=m,L=m+E);for(A=0;A<N;A++)O=h[A],O.dist>=k&&O.dist<=L&&C.push(O.node)}return C}var n=/^([\d.]+)%$/;e.each(["nearest","furthest","touching"],function(n,i){var s={x:0,y:0,w:0,h:0,tolerance:1,container:document,furthest:i=="furthest",includeSelf:!1,checkHoriz:i!="touching",checkVert:i!="touching"};e[i]=function(n,i,o){if(!n||n.x===t||n.y===t)return e([]);var u=e.extend({},s,n,o||{});return e(r(i,u))},e.fn[i]=function(t,n){var i;if(t&&e.isPlainObject(t))return i=e.extend({},s,t,n||{}),this.pushStack(r(this,i));var o=this.offset(),u={x:o.left,y:o.top,w:this.outerWidth(),h:this.outerHeight()};return i=e.extend({},s,u,n||{}),this.pushStack(r(t,i,this))}})})(jQuery); \ No newline at end of file
diff --git a/addons/website/static/lib/nearest/nearest.jquery.json b/addons/website/static/lib/nearest/nearest.jquery.json
new file mode 100644
index 00000000000..9c9ee5c05c8
--- /dev/null
+++ b/addons/website/static/lib/nearest/nearest.jquery.json
@@ -0,0 +1,24 @@
+{
+ "name": "nearest",
+ "title": "jQuery Nearest Element",
+ "description": "Find the elements in a page that are closest to (or furthest away from) a particular point or element, based on pixel dimensions",
+ "version": "1.2.1",
+ "keywords": ["nearest", "furthest", "touching", "pixel", "distance"],
+ "homepage": "http://gilmoreorless.github.io/jquery-nearest/",
+ "docs": "http://gilmoreorless.github.io/jquery-nearest/",
+ "demo": "http://gilmoreorless.github.io/jquery-nearest/demo.html",
+ "bugs": "https://github.com/gilmoreorless/jquery-nearest/issues",
+ "author": {
+ "name": "Gilmore Davidson",
+ "url": "http://shoehornwithteeth.com/"
+ },
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "http://gilmoreorless.mit-license.org/2011/"
+ }
+ ],
+ "dependencies": {
+ "jquery": ">=1.4"
+ }
+} \ No newline at end of file
diff --git a/addons/website/static/src/css/editor.css b/addons/website/static/src/css/editor.css
index 5604c62af75..d0b0b34d180 100644
--- a/addons/website/static/src/css/editor.css
+++ b/addons/website/static/src/css/editor.css
@@ -1,4 +1,3 @@
-@charset "utf-8";
/* ---- CKEditor Minimal Reset ---- */
.navbar.navbar-inverse .cke_chrome {
border: none;
@@ -169,7 +168,7 @@ table.editorbar-panel td.selected {
position: fixed;
left: 0px;
right: 0px;
- top: 50px;
+ top: 51px;
background: #282828;
-webkit-box-shadow: 0px 10px 10px -10px black inset;
-moz-box-shadow: 0px 10px 10px -10px black inset;
@@ -182,17 +181,21 @@ table.editorbar-panel td.selected {
}
#oe_snippets .scroll {
white-space: nowrap;
- overflow-y: auto;
+ overflow-y: none;
}
#oe_snippets .nav {
- position: fixed;
+ display: inline-block;
+ border-bottom: none !important;
+ vertical-align: middle;
+ min-width: 120px;
z-index: 1;
- border: 0;
}
#oe_snippets .nav > li {
- display: inline-block;
+ display: block;
float: none;
- font-size: 13px;
+}
+#oe_snippets .nav > li.active {
+ background: black !important;
}
#oe_snippets .nav > li > a {
padding: 2px 10px !important;
@@ -200,18 +203,19 @@ table.editorbar-panel td.selected {
display: block;
border: 0;
}
+#oe_snippets .pill-content {
+ border: 0;
+}
#oe_snippets .tab-content {
- margin-top: 24px;
display: inline-block;
white-space: nowrap;
+ background: black;
}
#oe_snippets .tab-content > div {
background: black;
- padding: 5px;
}
#oe_snippets .tab-content > div label {
width: 44px;
- height: 100%;
color: white;
padding-left: 10px;
}
@@ -231,11 +235,10 @@ table.editorbar-panel td.selected {
}
.oe_snippet {
- display: inline-block;
+ float: left;
vertical-align: top;
- width: 100px;
- height: 100px;
- margin: 1px;
+ width: 93px;
+ margin-left: 1px;
margin-top: 0px;
position: relative;
overflow: hidden;
@@ -253,14 +256,32 @@ table.editorbar-panel td.selected {
color: white;
position: relative;
}
+.oe_snippet .oe_snippet_thumbnail:hover .oe_snippet_thumbnail_img {
+ -webkit-transform: scale(0.95, 0.95);
+ -moz-transform: scale(0.95, 0.95);
+ -ms-transform: scale(0.95, 0.95);
+ -o-transform: scale(0.95, 0.95);
+ transform: scale(0.95, 0.95);
+}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_title {
font-size: 12px;
display: block;
+ text-shadow: 0 0 2px black;
}
.oe_snippet .oe_snippet_thumbnail .oe_snippet_thumbnail_img {
+ height: 74px;
+ -webkit-transition: all 150ms linear;
+ -moz-transition: all 150ms linear;
+ -o-transition: all 150ms linear;
+ transition: all 150ms linear;
-webkit-box-shadow: inset 0px 0px 0px 3px #333333;
-moz-box-shadow: inset 0px 0px 0px 3px #333333;
box-shadow: inset 0px 0px 0px 3px #333333;
+ -webkit-transform: scale(1, 1);
+ -moz-transform: scale(1, 1);
+ -ms-transform: scale(1, 1);
+ -o-transform: scale(1, 1);
+ transform: scale(1, 1);
}
.oe_snippet .oe_snippet_thumbnail span, .oe_snippet .oe_snippet_thumbnail div {
line-height: 18px;
@@ -309,20 +330,21 @@ table.editorbar-panel td.selected {
margin: 0px -24px !important;
}
.oe_drop_zone.oe_insert.oe_overlay {
- background: rgba(153, 0, 255, 0.17);
border-radius: 3px;
+ background: rgba(153, 0, 255, 0.5);
}
.oe_drop_zone, .oe_drop_zone_style {
- background: rgba(153, 0, 255, 0.17);
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- -ms-border-radius: 3px;
- -o-border-radius: 3px;
- border-radius: 3px;
+ border: none;
+ background: rgba(153, 0, 255, 0.3);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -ms-border-radius: 4px;
+ -o-border-radius: 4px;
+ border-radius: 4px;
}
.oe_drop_zone.oe_hover, .oe_drop_zone_style.oe_hover {
- background: rgba(0, 255, 133, 0.22);
+ background: rgba(0, 255, 133, 0.3);
z-index: 1001;
}
@@ -359,7 +381,7 @@ table.editorbar-panel td.selected {
-webkit-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
-moz-box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
box-shadow: 0px 0px 0px 1px rgba(255, 255, 255, 0.3), 0px 0px 0px 1px rgba(255, 255, 255, 0.3) inset;
- border-color: rgba(153, 0, 255, 0.5);
+ border-color: rgba(0, 0, 0, 0.5);
}
.oe_overlay.oe_active .oe_handle {
display: block !important;
@@ -371,39 +393,43 @@ table.editorbar-panel td.selected {
left: 50%;
display: block;
background: white;
- border: solid 1px #9900ff;
- -webkit-border-radius: 8px;
- -moz-border-radius: 8px;
- -ms-border-radius: 8px;
- -o-border-radius: 8px;
- border-radius: 8px;
- width: 16px;
- height: 16px;
- margin: -8px;
+ border: solid 1px rgba(0, 0, 0, 0.2);
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -ms-border-radius: 5px;
+ -o-border-radius: 5px;
+ border-radius: 5px;
+ width: 18px;
+ height: 18px;
+ margin: -9px;
padding-left: 1px;
font-size: 14px;
line-height: 14px;
- color: #9900ff;
+ font-family: FontAwesome;
+ color: rgba(0, 0, 0, 0.5);
-webkit-transition: background 100ms linear;
-moz-transition: background 100ms linear;
-o-transition: background 100ms linear;
transition: background 100ms linear;
}
.oe_overlay.oe_active .oe_handle:hover:before {
- background: #9900ff;
+ background: rgba(0, 0, 0, 0.5);
color: white;
+ -webkit-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
+ -moz-box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
+ box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.7);
}
.oe_overlay.oe_active .oe_handle.e:before {
- content: "⇨";
+ content: "\F061";
}
.oe_overlay.oe_active .oe_handle.s:before {
- content: "⇩";
+ content: "\F063";
}
.oe_overlay.oe_active .oe_handle.w:before {
- content: "⇦";
+ content: "\F060";
}
.oe_overlay.oe_active .oe_handle.n:before {
- content: "⇧";
+ content: "\F062";
}
.oe_overlay .icon.btn {
display: inline-block;
@@ -568,18 +594,6 @@ table.editorbar-panel td.selected {
-o-border-radius: 0.4em;
border-radius: 0.4em;
}
-.oe_seo_configuration .keyword-in-title {
- background-color: #5cb85cpointer;
- color: white;
-}
-.oe_seo_configuration .keyword-in-description {
- background-color: #428bca;
- color: white;
-}
-.oe_seo_configuration .keyword-in-body {
- background-color: #5bc0de;
- color: white;
-}
/* ---- ACE EDITOR ---- */
.oe_ace_view_editor {
@@ -636,3 +650,12 @@ table.editorbar-panel td.selected {
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
}
+
+/* ---- EDITOR TOUR ---- */
+div.tour-backdrop {
+ z-index: 2009;
+}
+
+.popover.tour {
+ z-index: 2010;
+}
diff --git a/addons/website/static/src/css/editor.sass b/addons/website/static/src/css/editor.sass
index 7b2800bd849..51bae3dcf3a 100644
--- a/addons/website/static/src/css/editor.sass
+++ b/addons/website/static/src/css/editor.sass
@@ -4,6 +4,17 @@
@import "compass/css3/user-interface"
@import "compass/css3/transition"
+//smartphones, iPhone, portrait 480x320 phones
+$smart_phone: 320px
+//portrait e-readers (Nook/Kindle), smaller tablets @ 600 or @ 640 wide.*/
+$small-tablet: 481px
+//portrait tablets, portrait iPad, landscape e-readers, landscape 800x480 or 854x480 phones
+$portrait-tablet: 641px
+//tablet, landscape iPad, lo-res laptops ands desktops
+$tablet: 961px
+//big landscape tablets, laptops, and desktops
+$desktop: 1025px
+
/* ---- CKEditor Minimal Reset ---- */
.navbar.navbar-inverse .cke_chrome
@@ -141,7 +152,7 @@ table.editorbar-panel
position: fixed
left: 0px
right: 0px
- top: 50px
+ top: 51px
background: rgb(40,40,40)
+box-shadow(0px 10px 10px -10px black inset)
z-index: 1010
@@ -150,44 +161,47 @@ table.editorbar-panel
height: auto
.scroll
white-space: nowrap
- overflow-y: auto
+ overflow-y: none
.nav
+ display: inline-block
+ border-bottom: none !important
+ vertical-align: middle
+ min-width: 120px
> li
- display: inline-block
+ display: block
float: none
- font-size: 13px
+ &.active
+ background: black !important
> a
padding: 2px 10px !important
- width: 100%
+ width: 100%
display: block
border: 0
- position: fixed
z-index: 1
+ .pill-content
border: 0
.tab-content
- margin-top: 24px
display: inline-block
white-space: nowrap
- > div
+ background: black
+ > div
background: rgb(0,0,0)
- padding: 5px
label
width: 44px
- height: 100%
color: #fff
padding-left: 10px
+
div
width: 100px
text-align: center
- @include transform( translate(-39px, 44px) , rotate(-90deg) )
+ @include transform( translate(-39px, 44px) , rotate(-90deg) )
@include transform-origin(50% 50%)
.oe_snippet
- display: inline-block
+ float: left
vertical-align: top
- width: 100px
- height: 100px
- margin: 1px
+ width: 93px
+ margin-left: 1px
margin-top: 0px
position: relative
overflow: hidden
@@ -201,11 +215,18 @@ table.editorbar-panel
background: transparent
color: white
position: relative
+ &:hover
+ .oe_snippet_thumbnail_img
+ @include transform( scale(.95,.95))
.oe_snippet_thumbnail_title
font-size: 12px
display: block
+ +text-shadow(0 0 2px rgb(0,0,0))
.oe_snippet_thumbnail_img
+ height: 74px
+ @include transition(all 150ms linear)
+box-shadow(inset 0px 0px 0px 3px #333333)
+ @include transform( scale(1,1))
span, div
line-height: 18px
& > :not(.oe_snippet_thumbnail)
@@ -240,14 +261,19 @@ table.editorbar-panel
position: relative
margin: 0px -24px !important
&.oe_overlay
- background: rgba(153, 0, 255, 0.17)
border-radius: 3px
-
+ //@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
+ //background-size: 100px 100px
+ background: rgba(153, 0, 255,.5)
+
.oe_drop_zone, .oe_drop_zone_style
- background: rgba(153, 0, 255, 0.17)
- +border-radius(3px)
+ border: none
+ //@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.1) ,rgba(255,255,255,.1) 35px, rgba(0,0,0,.1) 35px, rgba(0,0,0,.1) 75px))
+ //background-size: 100px 100px
+ background: rgba(153, 0, 255, .3)
+ +border-radius(4px)
&.oe_hover
- background: rgba(0, 255, 133, 0.22)
+ background: rgba(0, 255, 133, .3)
z-index: 1001
.oe_drop_zone_style
@@ -262,6 +288,7 @@ table.editorbar-panel
display: none
position: absolute
background: transparent
+ //@include background-image( repeating-linear-gradient(45deg, rgba(255,255,255,.02) ,rgba(255,255,255,.02) 35px, rgba(0,0,0,.02) 35px, rgba(0,0,0,.02) 75px))
+border-radius(3px)
@include transition(opacity 100ms linear)
+box-sizing(border-box)
@@ -271,7 +298,7 @@ table.editorbar-panel
border-style: dashed
border-width: 1px
+box-shadow(0px 0px 0px 1px rgba(255,255,255,0.3), 0px 0px 0px 1px rgba(255,255,255,0.3) inset)
- border-color: rgba(153, 0, 255, 0.5)
+ border-color: rgba(0, 0, 0, 0.5)
.oe_handle
display: block !important
pointer-events: auto
@@ -281,27 +308,29 @@ table.editorbar-panel
left: 50%
display: block
background: rgba(255, 255, 255, 1)
- border: solid 1px rgba(153, 0, 255, 1)
- +border-radius(8px)
- width: 16px
- height: 16px
- margin: -8px
+ border: solid 1px rgba(0, 0, 0, .2)
+ +border-radius(5px)
+ width: 18px
+ height: 18px
+ margin: -9px
padding-left: 1px
font-size: 14px
line-height: 14px
- color: rgba(153, 0, 255, 1)
+ font-family: FontAwesome
+ color: rgba(0,0,0,.5)
@include transition(background 100ms linear)
&:hover:before
- background: rgba(153, 0, 255, 1)
+ background: rgba(0, 0, 0, .5)
color: #fff
+ +box-shadow(0 0 5px 3px rgba(255,255,255,.7))
.oe_handle.e:before
- content: "⇨"
+ content: "\F061"
.oe_handle.s:before
- content: "⇩"
+ content: "\F063"
.oe_handle.w:before
- content: "⇦"
+ content: "\F060"
.oe_handle.n:before
- content: "⇧"
+ content: "\F062"
.icon.btn
display: inline-block
@@ -436,10 +465,6 @@ $ace_width: 720px
$editorbar_height: 40px
// TODO Fix => might break with themes
$navbar_height: 51px
-@mixin pointer-events($type: none)
- $type: unquote($type)
- @include experimental(pointer-events, $type,-moz, -webkit, not -o, not -ms, -khtml, official)
-
@mixin editor-font
font-size: 14px
@@ -481,4 +506,10 @@ $navbar_height: 51px
&.oe_ace_closed
width: 0
+opacity(0)
+
+/* ---- EDITOR TOUR ---- */
+div.tour-backdrop
+ z-index: 2009
+.popover.tour
+ z-index: 2010
// vim:tabstop=4:shiftwidth=4:softtabstop=4:fdm=marker:
diff --git a/addons/website/static/src/css/website.css b/addons/website/static/src/css/website.css
index 6af2e7485fe..ce87e592136 100644
--- a/addons/website/static/src/css/website.css
+++ b/addons/website/static/src/css/website.css
@@ -223,11 +223,15 @@ footer {
}
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
-.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
+.oe_structure.oe_editable.oe_empty:empty, .oe_editable[data-oe-type=html]:empty, .oe_structure.oe_editable.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
background-image: url("/website/static/src/img/drag_here.png");
+}
+
+.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
+ background-image: url("/website/static/src/img/edit_here.png");
background-repeat: no-repeat;
- background-position: center top;
- height: 200px !important;
+ background-position: center;
+ height: 220px !important;
}
.oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child {
@@ -238,8 +242,8 @@ footer {
content: "Click Edit To Create Content";
text-align: center;
display: block;
- padding-top: 100px;
- padding-bottom: 50px;
+ padding-top: 160px;
+ padding-bottom: 30px;
color: grey;
font-size: 24px;
}
@@ -345,6 +349,17 @@ footer {
}
/* Parallax Theme */
+.parallax_quote {
+ background: url("/website/static/src/img/parallax/quote.png") center center no-repeat fixed;
+ background-size: contain;
+}
+.parallax_quote .carousel-indicators li {
+ border: 1px solid grey;
+}
+.parallax_quote .carousel-indicators .active {
+ background-color: grey;
+}
+
.parallax_full {
background: #eeeeee bottom center repeat fixed;
min-height: 650px;
diff --git a/addons/website/static/src/css/website.sass b/addons/website/static/src/css/website.sass
index 997b45a0253..5197653429c 100644
--- a/addons/website/static/src/css/website.sass
+++ b/addons/website/static/src/css/website.sass
@@ -151,11 +151,14 @@ footer
/* ---- HACK FOR COVERING UP CK EDITOR BOGUS P INSERTION --- */
-.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
+.oe_structure.oe_editable.oe_empty:empty, .oe_editable[data-oe-type=html]:empty, .oe_structure.oe_editable.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
background-image: url('/website/static/src/img/drag_here.png')
+
+.oe_structure.oe_empty:empty, [data-oe-type=html]:empty, .oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
+ background-image: url('/website/static/src/img/edit_here.png')
background-repeat: no-repeat
- background-position: center top
- height: 200px !important
+ background-position: center
+ height: 220px !important
.oe_structure.oe_empty > .oe_drop_zone.oe_insert:only-child, [data-oe-type=html] > .oe_drop_zone.oe_insert:only-child
position: static
@@ -164,8 +167,8 @@ footer
content: 'Click Edit To Create Content'
text-align: center
display: block
- padding-top: 100px
- padding-bottom: 50px
+ padding-top: 160px
+ padding-bottom: 30px
color: grey
font-size: 24px
@@ -263,6 +266,15 @@ footer
/* Parallax Theme */
+.parallax_quote
+ background: url('/website/static/src/img/parallax/quote.png') center center no-repeat fixed
+ background-size: contain
+ .carousel-indicators
+ li
+ border: 1px solid grey
+ .active
+ background-color: grey
+
.parallax_full
background: #eee bottom center repeat fixed
min-height: 650px
diff --git a/addons/website/static/src/img/big_picture.png b/addons/website/static/src/img/big_picture.png
index cecb39679d5..519e713ff7f 100644
--- a/addons/website/static/src/img/big_picture.png
+++ b/addons/website/static/src/img/big_picture.png
Binary files differ
diff --git a/addons/website/static/src/img/drag_here.png b/addons/website/static/src/img/drag_here.png
index f2e3d38b2df..0dfeb1bc5da 100644
--- a/addons/website/static/src/img/drag_here.png
+++ b/addons/website/static/src/img/drag_here.png
Binary files differ
diff --git a/addons/website/static/src/img/edit_here.png b/addons/website/static/src/img/edit_here.png
new file mode 100644
index 00000000000..b53f56e2ac8
--- /dev/null
+++ b/addons/website/static/src/img/edit_here.png
Binary files differ
diff --git a/addons/website/static/src/img/parallax/quote.png b/addons/website/static/src/img/parallax/quote.png
new file mode 100644
index 00000000000..769cb6b5e0f
--- /dev/null
+++ b/addons/website/static/src/img/parallax/quote.png
Binary files differ
diff --git a/addons/website/static/src/js/website.editor.js b/addons/website/static/src/js/website.editor.js
index 30514b25780..ffb0f9b86a3 100644
--- a/addons/website/static/src/js/website.editor.js
+++ b/addons/website/static/src/js/website.editor.js
@@ -3,13 +3,12 @@
var website = openerp.website;
// $.fn.data automatically parses value, '0'|'1' -> 0|1
- website.is_editable = $(document.documentElement).data('editable');
website.templates.push('/website/static/src/xml/website.editor.xml');
website.dom_ready.done(function () {
var is_smartphone = $(document.body)[0].clientWidth < 767;
- if (website.is_editable && !is_smartphone) {
+ if (!is_smartphone) {
website.ready().then(website.init_editor);
}
});
@@ -21,16 +20,15 @@
return new website.editor.RTEImageDialog(editor).appendTo(document.body);
}
- if (website.is_editable) {
- // only enable editors manually
- CKEDITOR.disableAutoInline = true;
- // EDIT ALL THE THINGS
- CKEDITOR.dtd.$editable = $.extend(
- {}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
- // Disable removal of empty elements on CKEDITOR activation. Empty
- // elements are used for e.g. support of FontAwesome icons
- CKEDITOR.dtd.$removeEmpty = {};
- }
+ // only enable editors manually
+ CKEDITOR.disableAutoInline = true;
+ // EDIT ALL THE THINGS
+ CKEDITOR.dtd.$editable = $.extend(
+ {}, CKEDITOR.dtd.$block, CKEDITOR.dtd.$inline);
+ // Disable removal of empty elements on CKEDITOR activation. Empty
+ // elements are used for e.g. support of FontAwesome icons
+ CKEDITOR.dtd.$removeEmpty = {};
+
website.init_editor = function () {
CKEDITOR.plugins.add('customdialogs', {
// requires: 'link,image',
@@ -211,8 +209,9 @@
}
});
// Adding Static Menus
- menu.append('<li class="divider"></li><li><a href="/page/website.themes">Change Theme</a></li>');
+ menu.append('<li class="divider"></li><li class="js_change_theme"><a href="/page/website.themes">Change Theme</a></li>');
menu.append('<li class="divider"></li><li><a data-action="ace" href="#">Advanced view editor</a></li>');
+ self.trigger('rte:customize_menu_ready');
}
);
});
@@ -616,7 +615,7 @@
} else if ($e.hasClass('pages')) {
// Create the page, get the URL back
done = $.get(_.str.sprintf(
- '/pagenew/%s?noredirect', encodeURIComponent(val)))
+ '/pagenew/%s?noredirect', encodeURI(val)))
.then(function (response) {
self.make_link(response, false, val);
});
@@ -813,6 +812,7 @@
var element, editor = this.editor;
if (!(element = this.element)) {
element = editor.document.createElement('img');
+ element.addClass('img');
// focus event handler interactions between bootstrap (modal)
// and ckeditor (RTE) lead to blowing the stack in Safari and
// Chrome (but not FF) when this is done synchronously =>
diff --git a/addons/website/static/src/js/website.seo.js b/addons/website/static/src/js/website.seo.js
index 635b80bb192..945b0ed353d 100644
--- a/addons/website/static/src/js/website.seo.js
+++ b/addons/website/static/src/js/website.seo.js
@@ -1,6 +1,6 @@
(function () {
'use strict';
-
+
var website = openerp.website;
website.templates.push('/website/static/src/xml/website.seo.xml');
diff --git a/addons/website/static/src/js/website.snippets.js b/addons/website/static/src/js/website.snippets.js
index d85b2a814eb..96f153bf86e 100644
--- a/addons/website/static/src/js/website.snippets.js
+++ b/addons/website/static/src/js/website.snippets.js
@@ -243,12 +243,10 @@
// activate drag and drop for the snippets in the snippet toolbar
make_snippet_draggable: function($snippets){
var self = this;
- var $toInsert = false;
var $tumb = $snippets.find(".oe_snippet_thumbnail:first");
var left = $tumb.outerWidth()/2;
var top = $tumb.outerHeight()/2;
- var dropped = false;
- var $snippet = false;
+ var $toInsert, dropped, $snippet, action, snipped_id;
$snippets.draggable({
greedy: true,
@@ -265,8 +263,8 @@
self.hide();
dropped = false;
$snippet = $(this);
- var snipped_id = $snippet.data('snippet-id');
- var action = $snippet.find('.oe_snippet_body').size() ? 'insert' : 'mutate';
+ snipped_id = $snippet.data('snippet-id');
+ action = $snippet.find('.oe_snippet_body').size() ? 'insert' : 'mutate';
if( action === 'insert'){
if (!$snippet.data('selector-siblings') && !$snippet.data('selector-children') && !$snippet.data('selector-vertical-children')) {
console.debug($snippet.data("snippet-id") + " have oe_snippet_body class and have not for insert action"+
@@ -312,38 +310,46 @@
},
drop: function(){
dropped = true;
+ },
+ });
+ },
+ stop: function(ev, ui){
+ if (action === 'insert' && ! dropped) {
+ var el = $('.oe_drop_zone').nearest({x: ui.position.left, y: ui.position.top}).first()
+ if (el) {
+ el.after($toInsert)
+ dropped = true;
+ }
+ }
- var $target = false;
- if(action === 'insert'){
- $target = $toInsert;
+ $('.oe_drop_zone').droppable('destroy').remove();
+ if (dropped) {
+ var $target = false;
+ if(action === 'insert'){
+ $target = $toInsert;
- if (website.snippet.animationRegistry[snipped_id]) {
- new website.snippet.animationRegistry[snipped_id]($target);
- }
+ if (website.snippet.animationRegistry[snipped_id]) {
+ new website.snippet.animationRegistry[snipped_id]($target);
+ }
- self.create_overlay($target);
- $target.data("snippet-editor").build_snippet($target);
+ self.create_overlay($target);
+ $target.data("snippet-editor").build_snippet($target);
- } else {
- $target = $(this).data('target');
+ } else {
+ $target = $(this).data('target');
- self.create_overlay($target);
- if (website.snippet.editorRegistry[snipped_id]) {
- var snippet = new website.snippet.editorRegistry[snipped_id](self, $target);
- snippet.build_snippet($target);
- }
+ self.create_overlay($target);
+ if (website.snippet.editorRegistry[snipped_id]) {
+ var snippet = new website.snippet.editorRegistry[snipped_id](self, $target);
+ snippet.build_snippet($target);
}
-
- $('.oe_drop_zone').remove();
-
- setTimeout(function () {self.make_active($target);},0);
- },
- });
- },
- stop: function(){
- $('.oe_drop_zone').droppable('destroy').remove();
- if (!dropped && self.$modal.find('input:not(:checked)').length) {
- self.$modal.modal('toggle');
+ }
+ setTimeout(function () {self.make_active($target);},0);
+ } else {
+ $toInsert.remove();
+ if (self.$modal.find('input:not(:checked)').length) {
+ self.$modal.modal('toggle');
+ }
}
},
});
@@ -488,7 +494,6 @@
$zone.appendTo('#oe_manipulators');
$zone.data('target',$target);
$target.data('overlay',$zone);
- console.log($target[0], $zone);
$target.on("DOMNodeInserted DOMNodeRemoved DOMSubtreeModified", function () {
self.cover_target($zone, $target);
@@ -746,16 +751,8 @@
change_background: function (bg, ul_options) {
var self = this;
+ this.set_options_background(bg, ul_options);
var $ul = this.$editor.find(ul_options);
- var bg_value = (typeof bg === 'string' ? self.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, "");
-
- // select in ul options
- $ul.find("li").removeClass("active");
- var selected = $ul.find('[data-value="' + bg_value + '"], [data-value="' + bg_value.replace(/.*:\/\/[^\/]+/, '') + '"]');
- selected.addClass('active');
- if (!selected.length) {
- $ul.find('.oe_custom_bg b').html(bg_value);
- }
// bind envent on options
var $li = $ul.find("li");
@@ -787,6 +784,19 @@
$bg.css("background-image", "url(" + src + ")");
});
},
+
+ set_options_background: function (bg, ul_options) {
+ var $ul = this.$editor.find(ul_options);
+ var bg_value = (typeof bg === 'string' ? this.$target.find(bg) : $(bg)).css("background-image").replace(/url\(['"]*|['"]*\)/g, "");
+
+ // select in ul options
+ $ul.find("li").removeClass("active");
+ var selected = $ul.find('[data-value="' + bg_value + '"], [data-value="' + bg_value.replace(/.*:\/\/[^\/]+/, '') + '"]');
+ selected.addClass('active');
+ if (!selected.length) {
+ $ul.find('.oe_custom_bg b').html(bg_value);
+ }
+ },
});
@@ -974,50 +984,95 @@
});
website.snippet.editorRegistry.carousel = website.snippet.editorRegistry.resize.extend({
- build_snippet: function($target) {
- var id = "myCarousel" + $("body .carousel").length;
- $target.attr("id", id);
- $target.find(".carousel-control").attr("href", "#"+id);
+ build_snippet: function() {
+ var id = 0;
+ $("body .carousel").each(function () {
+ var _id = +$(this).attr("id").replace(/^myCarousel/, '');
+ if (id <= _id) {
+ id = _id + 1;
+ }
+ });
+ this.$target.attr("id", "myCarousel" + id);
+ this.$target.find(".carousel-control").attr("href", "#myCarousel" + id);
+ this.$target.find("[data-target='#myCarousel']").attr("data-target", "#myCarousel" + id);
+ this.rebind_event();
+ },
+ onFocus: function () {
+ this._super();
+ this.$target.carousel('pause');
+ },
+ onBlur: function () {
+ this._super();
+ this.$target.carousel('cycle');
},
start : function () {
this._super();
+ this.id = this.$target.attr("id");
+
+ this.$inner = this.$target.find('.carousel-inner');
+ this.$indicators = this.$target.find('.carousel-indicators');
+
this.$editor.find(".js_add").on('click', _.bind(this.on_add, this));
this.$editor.find(".js_remove").on('click', _.bind(this.on_remove, this));
this.change_background(".item.active", 'ul[name="carousel-background"]');
this.change_style();
- this.set_options_style();
this.change_size();
+ this.set_options_style();
+ this.$target.carousel();
+
+ var self = this;
+ this.$target.on('slide.bs.carousel', function () {
+ self.set_options_style();
+ self.set_options_background(".item.active", 'ul[name="carousel-background"]');
+ self.$target.carousel();
+ });
+
+ this.rebind_event();
+ },
+ // rebind event to active carousel on edit mode
+ rebind_event: function () {
+ var self = this;
+ this.$target.on('click', '.carousel-control', function () {
+ self.$target.carousel($(this).data('slide')); });
+ this.$target.on('click', '.carousel-indicators [data-target]', function () {
+ self.$target.carousel(+$(this).data('slide-to')); });
},
on_add: function (e) {
e.preventDefault();
- this.$target.find('.carousel-control').removeClass("hidden");
- var $inner = this.$target.find('.carousel-inner');
- var cycle = $inner.find('.item').length;
- $inner.find('.item.active').clone().removeClass('active').appendTo($inner);
- this.$target.carousel(cycle);
- this.set_options_background();
- this.set_options_style();
+ var cycle = this.$inner.find('.item').length;
+ var $active = this.$inner.find('.item.active');
+ var index = $active.index();
+ this.$target.find('.carousel-control, .carousel-indicators').removeClass("hidden");
+ this.$indicators.append('<li data-target="#' + this.id + '" data-slide-to="' + cycle + '"></li>');
+ $active.clone().removeClass('active').insertAfter($active);
+ this.$target.carousel().carousel(++index);
},
on_remove: function (e) {
e.preventDefault();
- var $inner = this.$target.find('.carousel-inner');
- var nb = $inner.find('.item').length;
- if (nb > 1) {
- $inner
- .find('.item.active').remove().end()
- .find('.item:first').addClass('active');
- this.$target.carousel(0);
- this.set_options_style();
- }
- if (nb <= 1) {
- this.$target.find('.carousel-control').addClass("hidden");
+ var self = this;
+ var new_index = 0;
+ var cycle = this.$inner.find('.item').length - 1;
+ var index = this.$inner.find('.item.active').index();
+ if (cycle > 0) {
+ this.$inner.find('.item.active').fadeOut(1000, function () {
+ $(this).remove();
+ self.$indicators.find('[data-target]:last').remove();
+ self.$indicators.find("[data-slide-to]").removeClass("active");
+ self.$indicators.find("[data-slide-to='" + new_index + "']").addClass("active");
+ });
+ setTimeout(function () {
+ new_index = index % cycle;
+ self.$target.carousel( new_index + 1 );
+ }, 500);
+ } else {
+ this.$target.find('.carousel-control, .carousel-indicators').addClass("hidden");
}
},
set_options_style: function () {
var style = false;
- var $el = this.$target.find('.carousel-inner .item.active');
+ var $el = this.$inner.find('.item.active');
var $ul = this.$editor.find('ul[name="carousel-style"]');
var $li = $ul.find("li");
@@ -1040,12 +1095,12 @@
$(this).addClass("active");
})
.on('mouseover', function (event) {
- var $el = self.$target.find('.carousel-inner .item.active');
+ var $el = self.$inner.find('.item.active');
$el.removeClass('image_text text_image text_only');
$el.addClass($(event.currentTarget).data("value"));
})
.on('mouseout', function (event) {
- var $el = self.$target.find('.carousel-inner .item.active');
+ var $el = self.$inner.find('.item.active');
$el.removeClass('image_text text_image text_only');
$el.addClass($ul.find('li.active').data("value"));
});
@@ -1087,33 +1142,6 @@
},
});
- website.snippet.animationRegistry.surprise = website.snippet.Animation.extend({
- start: function() {
- this._super();
- var hue=0;
- var beat = false;
- var self = this;
- self.$target.append('<iframe width="1px" height="1px" src="http://www.youtube.com/embed/WY24YNsOefk?autoplay=1" frameborder="0"></iframe>');
-
- var a = setInterval(function(){
- self.$target.next().css({'-webkit-filter':'hue-rotate('+hue+'deg)'});
- self.$target.prev().css({'-webkit-filter':'hue-rotate('+(-hue)+'deg)'});
- hue -= 5;
- }, 10);
-
- setTimeout(function(){
- clearInterval(a);
- setInterval(function(){
- var filter = 'hue-rotate('+hue+'deg)'+ (beat ? ' invert()' : '');
- $(document.documentElement).css({'-webkit-filter': filter}); hue += 5;
- if(hue % 35 === 0){
- beat = !beat;
- }
- }, 10);
- },5000);
- }
- });
-
/*
* data-snippet-id automatically setted
* Don't need to add data-snippet-id="..." into the views
diff --git a/addons/website/static/src/js/website.tour.js b/addons/website/static/src/js/website.tour.js
new file mode 100644
index 00000000000..09e222acf64
--- /dev/null
+++ b/addons/website/static/src/js/website.tour.js
@@ -0,0 +1,256 @@
+(function () {
+ 'use strict';
+
+ var website = openerp.website;
+ website.templates.push('/website/static/src/xml/website.tour.xml');
+
+ function render (template, dict) {
+ return openerp.qweb.render(template, dict);
+ }
+
+ website.EditorTour = openerp.Class.extend({
+ tour: undefined,
+ steps: [],
+ tourStorage: window.localStorage,
+ init: function () {
+ this.tour = new Tour({
+ name: this.id,
+ storage: this.tourStorage,
+ keyboard: false,
+ });
+ this.tour.addSteps(_.map(this.steps, function (step) {
+ step.title = render('website.tour_popover_title', { title: step.title });
+ return step;
+ }));
+ this.monkeyPatchTour();
+ },
+ monkeyPatchTour: function () {
+ var self = this;
+ // showStep should wait for 'element' to appear instead of moving to the next step
+ self.tour.showStep = function (i) {
+ var step = self.tour.getStep(i);
+ return (function proceed () {
+ if (step.orphan || $(step.element).length > 0) {
+ return Tour.prototype.showStep.call(self.tour, i);
+ } else {
+ setTimeout(proceed, 50);
+ }
+ }());
+ };
+ },
+ reset: function () {
+ this.tourStorage.removeItem(this.id+'_current_step');
+ this.tourStorage.removeItem(this.id+'_end');
+ this.tour._current = 0;
+ $('.popover.tour').remove();
+ },
+ start: function () {
+ if (this.canResume()) {
+ this.tour.start();
+ }
+ },
+ canResume: function () {
+ return (this.currentStepIndex() === 0) && !this.tour.ended();
+ },
+ currentStepIndex: function () {
+ var index = this.tourStorage.getItem(this.id+'_current_step') || 0;
+ return parseInt(index, 10);
+ },
+ indexOfStep: function (stepId) {
+ var index = -1;
+ _.each(this.steps, function (step, i) {
+ if (step.stepId === stepId) {
+ index = i;
+ }
+ });
+ return index;
+ },
+ movetoStep: function (stepId) {
+ $('.popover.tour').remove();
+ var index = this.indexOfStep(stepId);
+ if (index > -1) {
+ this.tour.goto(index);
+ }
+ },
+ saveStep: function (stepId) {
+ var index = this.indexOfStep(stepId);
+ this.tourStorage.setItem(this.id+'_current_step', index);
+ },
+ stop: function () {
+ this.tour.end();
+ },
+ });
+
+ website.EditorBasicTour = website.EditorTour.extend({
+ id: 'add_banner_tour',
+ name: "Insert a banner",
+ init: function (editor) {
+ var self = this;
+ self.steps = [
+ {
+ stepId: 'welcome',
+ orphan: true,
+ backdrop: true,
+ title: "Welcome to your website!",
+ content: "This tutorial will guide you to build your first page. We will start by adding a banner.",
+ template: render('website.tour_popover', { next: "Start Tutorial", end: "Skip It" }),
+ },
+ {
+ stepId: 'edit-page',
+ element: 'button[data-action=edit]',
+ placement: 'bottom',
+ reflex: true,
+ title: "Edit this page",
+ content: "Every page of your website can be modified through the <i>Edit</i> button.",
+ template: render('website.tour_popover'),
+ },
+ {
+ stepId: 'add-block',
+ element: 'button[data-action=snippet]',
+ placement: 'bottom',
+ title: "Insert building blocks",
+ content: "To add content in a page, you can insert building blocks.",
+ template: render('website.tour_popover'),
+ onShow: function () {
+ function refreshAddBlockStep () {
+ self.tour.showStep(self.indexOfStep('add-block'));
+ editor.off('rte:ready', editor, refreshAddBlockStep);
+ }
+ editor.on('rte:ready', editor, refreshAddBlockStep);
+ $('button[data-action=snippet]').click(function () {
+ self.movetoStep('drag-banner');
+ });
+ }
+ },
+ {
+ stepId: 'drag-banner',
+ element: '#website-top-navbar [data-snippet-id=carousel]',
+ placement: 'bottom',
+ title: "Drag & Drop a Banner",
+ content: "Drag the <em>Banner</em> block and drop it in your page. <p class='text-muted'>Tip: release the mouse button when you are in a valid zone, with a preview of the banner.</p>",
+ template: render('website.tour_popover'),
+ onShow: function () {
+ function beginDrag () {
+ $('.popover.tour').remove();
+ $('body').off('mousedown', beginDrag);
+ function goToNextStep () {
+ $('#oe_snippets').hide();
+ self.movetoStep('edit-title');
+ $('body').off('mouseup', goToNextStep);
+ }
+ $('body').on('mouseup', goToNextStep);
+ }
+ $('body').on('mousedown', beginDrag);
+ },
+ },
+ {
+ stepId: 'edit-title',
+ element: '#wrap [data-snippet-id=carousel]:first .carousel-caption',
+ placement: 'left',
+ title: "Customize banner's text",
+ content: "Click in the text and start editing it. Click continue once it's done.",
+ template: render('website.tour_popover', { next: "Continue" }),
+ onHide: function () {
+ var $banner = $("#wrap [data-snippet-id=carousel]:first");
+ if ($banner.length) {
+ $banner.click();
+ }
+ },
+ },
+ {
+ stepId: 'customize-banner',
+ element: '.oe_overlay_options .oe_options',
+ placement: 'left',
+ title: "Customize the banner",
+ content: "You can customize components of your page through the <em>Customize</em> menu. Try to change the background of your banner.",
+ template: render('website.tour_popover', { next: "Continue" }),
+ onShow: function () {
+ $('.dropdown-menu [name=carousel-background]').click(function () {
+ self.movetoStep('save-changes');
+ });
+ },
+ },
+ {
+ stepId: 'save-changes',
+ element: 'button[data-action=save]',
+ placement: 'right',
+ reflex: true,
+ title: "Save your modifications",
+ content: "Once you click on save, your website page is updated.",
+ template: render('website.tour_popover'),
+ onHide: function () {
+ self.saveStep('part-2');
+ },
+
+ },
+ {
+ stepId: 'part-2',
+ orphan: true,
+ title: "Congratulation!",
+ content: "Your homepage have been updated. Now, we suggest you to insert others building blocks like texts and images to structure your page.",
+ template: render('website.tour_popover', { next: "Continue" }),
+ },
+ {
+ stepId: 'show-tutorials',
+ element: '#help-menu-button',
+ placement: 'left',
+ title: "Help is always available",
+ content: "But you can always click here if you want more tutorials.",
+ template: render('website.tour_popover', { end: "Close" }),
+ },
+ ];
+ return this._super();
+ },
+ startOfPart2: function () {
+ var currentStepIndex = this.currentStepIndex();
+ var secondPartIndex = this.indexOfStep('part-2');
+ var showTutorialsIndex = this.indexOfStep('show-tutorials');
+ return (currentStepIndex === secondPartIndex || currentStepIndex === showTutorialsIndex) && !this.tour.ended();
+ },
+ canResume: function () {
+ return this.startOfPart2() || this._super();
+ },
+ });
+
+ website.UrlParser = openerp.Class.extend({
+ init: function (url) {
+ var a = document.createElement('a');
+ a.href = url;
+ this.href = a.href;
+ this.host = a.host;
+ this.protocol = a.protocol;
+ this.port = a.port;
+ this.hostname = a.hostname;
+ this.pathname = a.pathname;
+ this.origin = a.origin;
+ this.search = a.search;
+ },
+ });
+
+ website.EditorBar.include({
+ start: function () {
+ website.tutorials = {
+ basic: new website.EditorBasicTour(this),
+ };
+ var menu = $('#help-menu');
+ _.each(website.tutorials, function (tutorial) {
+ var $menuItem = $($.parseHTML('<li><a href="#">'+tutorial.name+'</a></li>'));
+ $menuItem.click(function () {
+ tutorial.reset();
+ tutorial.start();
+ })
+ menu.append($menuItem);
+ });
+ var url = new website.UrlParser(window.location.href);
+ if (url.search.indexOf('?tutorial=true') === 0 || website.tutorials.basic.startOfPart2()) {
+ website.tutorials.basic.start();
+ }
+ $('.tour-backdrop').click(function (e) {
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ });
+ return this._super();
+ },
+ });
+
+}());
diff --git a/addons/website/static/src/xml/website.editor.xml b/addons/website/static/src/xml/website.editor.xml
index 157d19b56c0..685712d3411 100644
--- a/addons/website/static/src/xml/website.editor.xml
+++ b/addons/website/static/src/xml/website.editor.xml
@@ -56,7 +56,7 @@
</label>
</h3>
<input type="text" class="form-control pages url-source"
- id="link-new" pattern="[\\w/-]+"/>
+ id="link-new" placeholder="Page Name"/>
</li>
<li class="list-group-item form-group clearfix">
<div class="pull-right">
diff --git a/addons/website/static/src/xml/website.tour.xml b/addons/website/static/src/xml/website.tour.xml
new file mode 100644
index 00000000000..d2f562dec61
--- /dev/null
+++ b/addons/website/static/src/xml/website.tour.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<templates id="template" xml:space="preserve">
+ <t t-name="website.tour_popover">
+ <div class="popover tour">
+ <div class="arrow"></div>
+ <h3 class="popover-title"></h3>
+ <div class="popover-content"></div>
+ <t t-if="next or end">
+ <nav class="popover-navigation">
+ <t t-if="next">
+ <button class="btn btn-sm btn-default" data-role="next"><t t-esc="next"/></button>
+ </t>
+ <small t-if="next &amp;&amp; end">
+ <span class="text-muted"> or </span>
+ <button class="btn-link" data-role="end" style="float: none; padding: 0"><t t-esc="end"/></button>
+ </small>
+ <t t-if="end &amp;&amp; ! next">
+ <button class="btn btn-sm btn-default" data-role="end"><t t-esc="end"/></button>
+ </t>
+ </nav>
+ </t>
+ </div>
+ </t>
+ <t t-name="website.tour_popover_title">
+ <t t-esc="title"/><button title="Close Tutorial" type="button" class="close" data-role="end">×</button>
+ </t>
+</templates>
diff --git a/addons/website/static/src/xml/website.xml b/addons/website/static/src/xml/website.xml
index c2f7abe6ed2..b3e4cacd32a 100644
--- a/addons/website/static/src/xml/website.xml
+++ b/addons/website/static/src/xml/website.xml
@@ -28,6 +28,12 @@
<!-- filled in JS -->
</ul>
</li>
+ <li class="dropdown">
+ <a id="help-menu-button" class="dropdown-toggle" data-toggle="dropdown" href="#">Help <span class="caret"></span></a>
+ <ul class="dropdown-menu" role="menu" id="help-menu">
+ <!-- filled in JS -->
+ </ul>
+ </li>
<li>
<a href="/admin#action=website.action_module_website">Apps</a>
</li>