diff --git a/addons/website/models/website.py b/addons/website/models/website.py index acd42f2051f..d04d25e64fb 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -6,7 +6,7 @@ import math import simplejson import traceback import urllib -from urlparse import urljoin +import urlparse import werkzeug import werkzeug.exceptions @@ -53,29 +53,33 @@ def auth_method_public(): request.uid = request.session.uid http.auth_methods['public'] = auth_method_public -def url_for(path, lang=None, keep_query=None): - if request: - path = urljoin(request.httprequest.path, path) +def url_for(path_or_uri, lang=None, keep_query=None): + location = path_or_uri.strip() + url = urlparse.urlparse(location) + if request and not url.netloc and not url.scheme: + location = urlparse.urljoin(request.httprequest.path, location) langs = request.context.get('langs') - if path[0] == '/' and (len(langs) > 1 or lang): - ps = path.split('/') + if location[0] == '/' and (len(langs) > 1 or lang): + ps = location.split('/') lang = lang or request.context.get('lang') if ps[1] in langs: ps[1] = lang else: ps.insert(1, lang) - path = '/'.join(ps) + location = '/'.join(ps) if keep_query: - keep = [] - params = werkzeug.url_decode(request.httprequest.query_string) - params_keys = tuple(params.keys()) + url = urlparse.urlparse(location) + location = url.path + params = werkzeug.url_decode(url.query) + query_params = frozenset(werkzeug.url_decode(request.httprequest.query_string).keys()) for kq in keep_query: - keep += fnmatch.filter(params_keys, kq) - if keep: - params = dict([(k, params[k]) for k in keep]) - path += u'?%s' % werkzeug.urls.url_encode(params) + for param in fnmatch.filter(query_params, kq): + params[param] = request.params[param] + params = werkzeug.urls.url_encode(params) + if params: + location += '?%s' % params - return path + return location def urlplus(url, params): if not params: diff --git a/addons/website/static/lib/bootstrap/js/bootstrap.js b/addons/website/static/lib/bootstrap/js/bootstrap.js index ab217ed9cf1..b22be6fce1d 100644 --- a/addons/website/static/lib/bootstrap/js/bootstrap.js +++ b/addons/website/static/lib/bootstrap/js/bootstrap.js @@ -1,730 +1,2006 @@ -/** - * bootstrap.js v3.0.0 by @fat and @mdo - * Copyright 2013 Twitter Inc. - * http://www.apache.org/licenses/LICENSE-2.0 +/*! + * Bootstrap v3.0.1 by @fat and @mdo + * Copyright 2013 Twitter, Inc. + * Licensed under http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world by @mdo and @fat. */ -if (!jQuery) throw new Error("Bootstrap requires jQuery"); + function (a) { - "use strict"; - function b() { - var a = document.createElement("bootstrap"), - b = { - WebkitTransition: "webkitTransitionEnd", - MozTransition: "transitionend", - OTransition: "oTransitionEnd otransitionend", - transition: "transitionend" - }; - for (var c in b) - if (void 0 !== a.style[c]) return { - end: b[c] - } - } - a.fn.emulateTransitionEnd = function (b) { - var c = !1, - d = this; - a(this).one(a.support.transition.end, function () { - c = !0 - }); - var e = function () { - c || a(d).trigger(a.support.transition.end) - }; - return setTimeout(e, b), this - }, a(function () { - a.support.transition = b() - }) -}(window.jQuery), + function (a) { - "use strict"; - var b = '[data-dismiss="alert"]', - c = function (c) { - a(c).on("click", b, this.close) - }; - c.prototype.close = function (b) { - function c() { - f.trigger("closed.bs.alert").remove() - } - var d = a(this), - e = d.attr("data-target"); - e || (e = d.attr("href"), e = e && e.replace(/.*(?=#[^\s]*$)/, "")); - var f = a(e); - b && b.preventDefault(), f.length || (f = d.hasClass("alert") ? d : d.parent()), f.trigger(b = a.Event("close.bs.alert")), b.isDefaultPrevented() || (f.removeClass("in"), a.support.transition && f.hasClass("fade") ? f.one(a.support.transition.end, c).emulateTransitionEnd(150) : c()) - }; - var d = a.fn.alert; - a.fn.alert = function (b) { - return this.each(function () { - var d = a(this), - e = d.data("bs.alert"); - e || d.data("bs.alert", e = new c(this)), "string" == typeof b && e[b].call(d) - }) - }, a.fn.alert.Constructor = c, a.fn.alert.noConflict = function () { - return a.fn.alert = d, this - }, a(document).on("click.bs.alert.data-api", b, c.prototype.close) -}(window.jQuery), + function (a) { - "use strict"; - var b = function (c, d) { - this.$element = a(c), this.options = a.extend({}, b.DEFAULTS, d) - }; - b.DEFAULTS = { - loadingText: "loading..." - }, b.prototype.setState = function (a) { - var b = "disabled", - c = this.$element, - d = c.is("input") ? "val" : "html", - e = c.data(); - a += "Text", e.resetText || c.data("resetText", c[d]()), c[d](e[a] || this.options[a]), setTimeout(function () { - "loadingText" == a ? c.addClass(b).attr(b, b) : c.removeClass(b).removeAttr(b) - }, 0) - }, b.prototype.toggle = function () { - var a = this.$element.closest('[data-toggle="buttons"]'); - if (a.length) { - var b = this.$element.find("input").prop("checked", !this.$element.hasClass("active")).trigger("change"); - "radio" === b.prop("type") && a.find(".active").removeClass("active") - } - this.$element.toggleClass("active") - }; - var c = a.fn.button; - a.fn.button = function (c) { - return this.each(function () { - var d = a(this), - e = d.data("bs.button"), - f = "object" == typeof c && c; - e || d.data("bs.button", e = new b(this, f)), "toggle" == c ? e.toggle() : c && e.setState(c) - }) - }, a.fn.button.Constructor = b, a.fn.button.noConflict = function () { - return a.fn.button = c, this - }, a(document).on("click.bs.button.data-api", "[data-toggle^=button]", function (b) { - var c = a(b.target); - c.hasClass("btn") || (c = c.closest(".btn")), c.button("toggle"), b.preventDefault() - }) -}(window.jQuery), + function (a) { - "use strict"; - var b = function (b, c) { - this.$element = a(b), this.$indicators = this.$element.find(".carousel-indicators"), this.options = c, this.paused = this.sliding = this.interval = this.$active = this.$items = null, "hover" == this.options.pause && this.$element.on("mouseenter", a.proxy(this.pause, this)).on("mouseleave", a.proxy(this.cycle, this)) - }; - b.DEFAULTS = { - interval: 5e3, - pause: "hover", - wrap: !0 - }, b.prototype.cycle = function (b) { - return b || (this.paused = !1), this.interval && clearInterval(this.interval), this.options.interval && !this.paused && (this.interval = setInterval(a.proxy(this.next, this), this.options.interval)), this - }, b.prototype.getActiveIndex = function () { - return this.$active = this.$element.find(".item.active"), this.$items = this.$active.parent().children(), this.$items.index(this.$active) - }, b.prototype.to = function (b) { - var c = this, - d = this.getActiveIndex(); - return b > this.$items.length - 1 || 0 > b ? void 0 : this.sliding ? this.$element.one("slid", function () { - c.to(b) - }) : d == b ? this.pause().cycle() : this.slide(b > d ? "next" : "prev", a(this.$items[b])) - }, b.prototype.pause = function (b) { - return b || (this.paused = !0), this.$element.find(".next, .prev").length && a.support.transition.end && (this.$element.trigger(a.support.transition.end), this.cycle(!0)), this.interval = clearInterval(this.interval), this - }, b.prototype.next = function () { - return this.sliding ? void 0 : this.slide("next") - }, b.prototype.prev = function () { - return this.sliding ? void 0 : this.slide("prev") - }, b.prototype.slide = function (b, c) { - var d = this.$element.find(".item.active"), - e = c || d[b](), - f = this.interval, - g = "next" == b ? "left" : "right", - h = "next" == b ? "first" : "last", - i = this; - if (!e.length) { - if (!this.options.wrap) return; - e = this.$element.find(".item")[h]() - } - this.sliding = !0, f && this.pause(); - var j = a.Event("slide.bs.carousel", { - relatedTarget: e[0], - direction: g - }); - if (!e.hasClass("active")) { - if (this.$indicators.length && (this.$indicators.find(".active").removeClass("active"), this.$element.one("slid", function () { - var b = a(i.$indicators.children()[i.getActiveIndex()]); - b && b.addClass("active") - })), a.support.transition && this.$element.hasClass("slide")) { - if (this.$element.trigger(j), j.isDefaultPrevented()) return; - e.addClass(b), e[0].offsetWidth, d.addClass(g), e.addClass(g), d.one(a.support.transition.end, function () { - e.removeClass([b, g].join(" ")).addClass("active"), d.removeClass(["active", g].join(" ")), i.sliding = !1, setTimeout(function () { - i.$element.trigger("slid") - }, 0) - }).emulateTransitionEnd(600) - } else { - if (this.$element.trigger(j), j.isDefaultPrevented()) return; - d.removeClass("active"), e.addClass("active"), this.sliding = !1, this.$element.trigger("slid") - } - return f && this.cycle(), this - } - }; - var c = a.fn.carousel; - a.fn.carousel = function (c) { - return this.each(function () { - var d = a(this), - e = d.data("bs.carousel"), - f = a.extend({}, b.DEFAULTS, d.data(), "object" == typeof c && c), - g = "string" == typeof c ? c : f.slide; - e || d.data("bs.carousel", e = new b(this, f)), "number" == typeof c ? e.to(c) : g ? e[g]() : f.interval && e.pause().cycle() - }) - }, a.fn.carousel.Constructor = b, a.fn.carousel.noConflict = function () { - return a.fn.carousel = c, this - }, a(document).on("click.bs.carousel.data-api", "[data-slide], [data-slide-to]", function (b) { - var c, d = a(this), - e = a(d.attr("data-target") || (c = d.attr("href")) && c.replace(/.*(?=#[^\s]+$)/, "")), - f = a.extend({}, e.data(), d.data()), - g = d.attr("data-slide-to"); - g && (f.interval = !1), e.carousel(f), (g = d.attr("data-slide-to")) && e.data("bs.carousel").to(g), b.preventDefault() - }), a(window).on("load", function () { - a('[data-ride="carousel"]').each(function () { - var b = a(this); - b.carousel(b.data()) - }) - }) -}(window.jQuery), + function (a) { - "use strict"; - var b = function (c, d) { - this.$element = a(c), this.options = a.extend({}, b.DEFAULTS, d), this.transitioning = null, this.options.parent && (this.$parent = a(this.options.parent)), this.options.toggle && this.toggle() - }; - b.DEFAULTS = { - toggle: !0 - }, b.prototype.dimension = function () { - var a = this.$element.hasClass("width"); - return a ? "width" : "height" - }, b.prototype.show = function () { - if (!this.transitioning && !this.$element.hasClass("in")) { - var b = a.Event("show.bs.collapse"); - if (this.$element.trigger(b), !b.isDefaultPrevented()) { - var c = this.$parent && this.$parent.find("> .panel > .in"); - if (c && c.length) { - var d = c.data("bs.collapse"); - if (d && d.transitioning) return; - c.collapse("hide"), d || c.data("bs.collapse", null) - } - var e = this.dimension(); - this.$element.removeClass("collapse").addClass("collapsing")[e](0), this.transitioning = 1; - var f = function () { - this.$element.removeClass("collapsing").addClass("in")[e]("auto"), this.transitioning = 0, this.$element.trigger("shown.bs.collapse") - }; - if (!a.support.transition) return f.call(this); - var g = a.camelCase(["scroll", e].join("-")); - this.$element.one(a.support.transition.end, a.proxy(f, this)).emulateTransitionEnd(350)[e](this.$element[0][g]) - } - } - }, b.prototype.hide = function () { - if (!this.transitioning && this.$element.hasClass("in")) { - var b = a.Event("hide.bs.collapse"); - if (this.$element.trigger(b), !b.isDefaultPrevented()) { - var c = this.dimension(); - this.$element[c](this.$element[c]())[0].offsetHeight, this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"), this.transitioning = 1; - var d = function () { - this.transitioning = 0, this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse") - }; - return a.support.transition ? (this.$element[c](0).one(a.support.transition.end, a.proxy(d, this)).emulateTransitionEnd(350), void 0) : d.call(this) - } - } - }, b.prototype.toggle = function () { - this[this.$element.hasClass("in") ? "hide" : "show"]() - }; - var c = a.fn.collapse; - a.fn.collapse = function (c) { - return this.each(function () { - var d = a(this), - e = d.data("bs.collapse"), - f = a.extend({}, b.DEFAULTS, d.data(), "object" == typeof c && c); - e || d.data("bs.collapse", e = new b(this, f)), "string" == typeof c && e[c]() - }) - }, a.fn.collapse.Constructor = b, a.fn.collapse.noConflict = function () { - return a.fn.collapse = c, this - }, a(document).on("click.bs.collapse.data-api", "[data-toggle=collapse]", function (b) { - var c, d = a(this), - e = d.attr("data-target") || b.preventDefault() || (c = d.attr("href")) && c.replace(/.*(?=#[^\s]+$)/, ""), - f = a(e), - g = f.data("bs.collapse"), - h = g ? "toggle" : d.data(), - i = d.attr("data-parent"), - j = i && a(i); - g && g.transitioning || (j && j.find('[data-toggle=collapse][data-parent="' + i + '"]').not(d).addClass("collapsed"), d[f.hasClass("in") ? "addClass" : "removeClass"]("collapsed")), f.collapse(h) - }) -}(window.jQuery), + function (a) { - "use strict"; +if (typeof jQuery === "undefined") { throw new Error("Bootstrap requires jQuery") } - function b() { - a(d).remove(), a(e).each(function (b) { - var d = c(a(this)); - d.hasClass("open") && (d.trigger(b = a.Event("hide.bs.dropdown")), b.isDefaultPrevented() || d.removeClass("open").trigger("hidden.bs.dropdown")) - }) +/* ======================================================================== + * Bootstrap: transition.js v3.0.1 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2013 Twitter, Inc. + * + * 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 ($) { "use strict"; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' } - function c(b) { - var c = b.attr("data-target"); - c || (c = b.attr("href"), c = c && /#/.test(c) && c.replace(/.*(?=#[^\s]*$)/, "")); - var d = c && a(c); - return d && d.length ? d : b.parent() + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } } - var d = ".dropdown-backdrop", - e = "[data-toggle=dropdown]", - f = function (b) { - a(b).on("click.bs.dropdown", this.toggle) - }; - f.prototype.toggle = function (d) { - var e = a(this); - if (!e.is(".disabled, :disabled")) { - var f = c(e), - g = f.hasClass("open"); - if (b(), !g) { - if ("ontouchstart" in document.documentElement && !f.closest(".navbar-nav").length && a('