1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
+},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec=/#.*$/,fc=/([?&])_=[^&]*/,gc=/^(.*?):[ \t]*([^\r\n]*)$/gm,hc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ic=/^(?:GET|HEAD)$/,jc=/^\/\//,kc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lc={},mc={},nc="*/".concat("*"),oc=a.location.href,pc=kc.exec(oc.toLowerCase())||[];function qc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rc(a,b,c,d){var e={},f=a===mc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function uc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:oc,type:"GET",isLocal:hc.test(pc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sc(sc(a,n.ajaxSettings),b):sc(n.ajaxSettings,a)},ajaxPrefilter:qc(lc),ajaxTransport:qc(mc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gc.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||oc)+"").replace(ec,"").replace(jc,pc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pc[1]&&h[2]===pc[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pc[3]||("http:"===pc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rc(lc,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ic.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fc.test(d)?d.replace(fc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rc(mc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tc(k,v,f)),u=uc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vc=/%20/g,wc=/\[\]$/,xc=/\r?\n/g,yc=/^(?:submit|button|image|reset|file)$/i,zc=/^(?:input|select|textarea|keygen)/i;function Ac(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wc.test(a)?d(a,e):Ac(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ac(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ac(c,a[c],b,e);return d.join("&").replace(vc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zc.test(this.nodeName)&&!yc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xc,"\r\n")}}):{name:b.name,value:c.replace(xc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bc=0,Cc={},Dc={0:200,1223:204},Ec=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cc)Cc[a]()}),k.cors=!!Ec&&"withCredentials"in Ec,k.ajax=Ec=!!Ec,n.ajaxTransport(function(a){var b;return k.cors||Ec&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Dc[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("
- {%- endif -%}
-{%- endblock %}
diff --git a/doc/_themes/odoodoc/odoo_pygments.py b/doc/_themes/odoodoc/odoo_pygments.py
deleted file mode 100644
index 795c0a7fb21..00000000000
--- a/doc/_themes/odoodoc/odoo_pygments.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# -*- coding: utf-8 -*-
-
-import imp
-import sys
-
-from pygments.style import Style
-from pygments.token import *
-
-# extracted from getbootstrap.com
-class OdooStyle(Style):
- background_color = '#ffffcc'
- highlight_color = '#fcf8e3'
- styles = {
- Whitespace: '#BBB',
- Error: 'bg:#FAA #A00',
-
- Keyword: '#069',
- Keyword.Type: '#078',
-
- Name.Attribute: '#4F9FCF',
- Name.Builtin: '#366',
- Name.Class: '#0A8',
- Name.Constant: '#360',
- Name.Decorator: '#99F',
- Name.Entity: '#999',
- Name.Exception: '#C00',
- Name.Function: '#C0F',
- Name.Label: '#99F',
- Name.Namespace: '#0CF',
- Name.Tag: '#2F6F9F',
- Name.Variable: '#033',
-
- String: '#d44950',
- String.Backtick: '#C30',
- String.Char: '#C30',
- String.Doc: 'italic #C30',
- String.Double: '#C30',
- String.Escape: '#C30',
- String.Heredoc: '#C30',
- String.Interol: '#C30',
- String.Other: '#C30',
- String.Regex: '#3AA',
- String.Single: '#C30',
- String.Symbol: '#FC3',
-
- Number: '#F60',
-
- Operator: '#555',
- Operator.Word: '#000',
-
- Comment: '#999',
- Comment.Preproc: '#099',
-
- Generic.Deleted: 'bg:#FCC border:#c00',
- Generic.Emph: 'italic',
- Generic.Error: '#F00',
- Generic.Heading: '#030',
- Generic.Inserted: 'bg:#CFC border:#0C0',
- Generic.Output: '#AAA',
- Generic.Prompt: '#009',
- Generic.Strong: '',
- Generic.Subheading: '#030',
- Generic.Traceback: '#9C6',
- }
-
-
-modname = 'pygments.styles.odoo'
-m = imp.new_module(modname)
-m.OdooStyle = OdooStyle
-sys.modules[modname] = m
diff --git a/doc/_themes/odoodoc/sphinx_monkeypatch.py b/doc/_themes/odoodoc/sphinx_monkeypatch.py
deleted file mode 100644
index 60e8ed5a4b3..00000000000
--- a/doc/_themes/odoodoc/sphinx_monkeypatch.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# -*- coding: utf-8 -*-
-import sphinx.roles
-import sphinx.environment
-from sphinx.writers.html import HTMLTranslator
-from docutils.writers.html4css1 import HTMLTranslator as DocutilsTranslator
-
-def patch():
- # navify toctree (oh god)
- @monkey(sphinx.environment.BuildEnvironment)
- def resolve_toctree(old_resolve, self, *args, **kwargs):
- """ If navbar, bootstrapify TOC to yield a navbar
-
- """
- navbar = kwargs.pop('navbar', None)
- toc = old_resolve(self, *args, **kwargs)
- if toc is None:
- return None
-
- navbarify(toc[0], navbar=navbar)
- return toc
-
- # monkeypatch visit_table to remove border and add .table
- HTMLTranslator.visit_table = visit_table
- # disable colspec crap
- HTMLTranslator.write_colspecs = lambda self: None
- # copy data- attributes straight from source to dest
- HTMLTranslator.starttag = starttag_data
-
-def navbarify(node, navbar=None):
- """
- :param node: toctree node to navbarify
- :param navbar: Whether this toctree is a 'main' navbar, a 'side' navbar or
- not a navbar at all
- """
- if navbar == 'side':
- for n in node.traverse():
- if n.tagname == 'bullet_list':
- n['classes'].append('nav')
- elif navbar == 'main':
- # add classes to just toplevel
- node['classes'].extend(['nav', 'navbar-nav', 'navbar-right'])
- for list_item in node.children:
- # bullet_list
- # list_item
- # compact_paragraph
- # reference
- # bullet_list
- # list_item
- # compact_paragraph
- # reference
- # no bullet_list.list_item -> don't dropdownify
- if not list_item.children[1].children:
- continue
-
- list_item['classes'].append('dropdown')
- # list_item.compact_paragraph.reference
- link = list_item.children[0].children[0]
- link['classes'].append('dropdown-toggle')
- link.attributes['data-toggle'] = 'dropdown'
- # list_item.bullet_list
- list_item.children[1]['classes'].append('dropdown-menu')
-
-def visit_table(self, node):
- """
- * remove border
- * add table class
- """
- self._table_row_index = 0
- self.context.append(self.compact_p)
- self.compact_p = True
-
- classes = {self.settings.table_style}
- node_classes = node.get('classes', [])
- if 'no-table' in node_classes: node_classes.remove('no-table')
- else: classes.add('table')
-
- self.body.append(self.starttag(node, 'table', CLASS=' '.join(classes).strip()))
-
-def starttag_data(self, node, tagname, suffix='\n', empty=False, **attributes):
- attributes.update(
- (k, v) for k, v in node.attributes.iteritems()
- if k.startswith('data-')
- )
- # oh dear
- return DocutilsTranslator.starttag(
- self, node, tagname, suffix=suffix, empty=empty, **attributes)
-
-class monkey(object):
- def __init__(self, obj):
- self.obj = obj
- def __call__(self, fn):
- name = fn.__name__
- old = getattr(self.obj, name)
- setattr(self.obj, name, lambda self_, *args, **kwargs: \
- fn(old, self_, *args, **kwargs))
diff --git a/doc/_themes/odoodoc/static/app.js b/doc/_themes/odoodoc/static/app.js
deleted file mode 100644
index 16f5445d860..00000000000
--- a/doc/_themes/odoodoc/static/app.js
+++ /dev/null
@@ -1,146 +0,0 @@
-$(function () {
- var $body = $(document.body);
- $body.scrollspy({ target: '.sphinxsidebarwrapper' });
- $(window).on('load', function () {
- $body.scrollspy('refresh');
- });
-
- // Sidenav affixing
- setTimeout(function () {
- var $sideBar = $('.sphinxsidebarwrapper');
-
- $sideBar.affix({
- offset: {
- top: function () {
- var offsetTop = $sideBar.offset().top;
- var sideBarMargin = parseInt($sideBar.children(0).css('margin-top'), 10);
- var navOuterHeight = $('.docs-nav').height();
-
- return (this.top = offsetTop - navOuterHeight - sideBarMargin);
- },
- bottom: function () {
- return (this.bottom = $('div.footer').outerHeight(true));
- }
- }
- });
- }, 100);
-
- // stripe page stuff
- if ($('div.document-super').hasClass('stripe')) { (function () {
- // iterate on highlighted PL blocks (but not results because that'd
- // be gross), extract all switchable PLs in the document and add
- // clipboard-copy buttons
- var languages = {};
- $('div.switchable').each(function () {
- var language = getHighlightLanguage(this);
- if (language) {
- languages[language] = true;
- }
- });
-
- // if can't find CSS where base rule lives something's probably
- // broken, bail
- var sheet = findSheet(/style\.css$/);
- if (!sheet) { return; }
- // build PL switcher UI and hook toggle event
- var $switcher = $(buildSwitcher(Object.keys(languages)))
- .prependTo('div.documentwrapper')
- .on('click', 'li', function (e) {
- $(e.target).addClass('active')
- .siblings().removeClass('active');
- var id = e.target.textContent;
- var lastIndex = sheet.cssRules.length - 1;
- var content = sheet.cssRules[lastIndex].style.cssText;
- // change rule in CSS because why not (also can add new
- // languages without having to e.g. change CSS or anything)
- var sel = [
- '.stripe .only-', id, ', ',
- '.stripe .highlight-', id, ' > .highlight'
- ].join('');
- sheet.deleteRule(lastIndex);
- sheet.insertRule(sel + '{' + content + '}', lastIndex);
- });
- $switcher.affix();
-
- $('')
- .prependTo('.switchable:not(.setup) .highlight');
- $(document).on('click', '.btn-show-setup', function (e) {
- var $target = $(e.target);
- var switchable = $target.closest('.switchable:not(.setup)').get(0);
- // not in a switchable (???)
- if (!switchable) { return; }
-
- var lang = getHighlightLanguage(switchable);
- if (!lang) {
- // switchable without highlight (e.g. language-specific notes),
- // don't munge
- return;
- }
-
- var $following_siblings = $target.nextAll();
- if ($following_siblings.length > 1) {
- // remove all but the very last following sibling (which
- // should be the non-setup )
- $following_siblings.slice(0, -1).remove();
- } else {
- // otherwise insert setupcode
- $('.setupcode.highlight-' + lang + ' pre').clone().insertAfter($target);
- }
- });
- })(); }
-
- /**
- * @param {Node} node highlight node to get the language of
- * @returns {String|null} either the highlight language or null
- */
- function getHighlightLanguage(node) {
- var classes = node.className.split(/\s+/);
- for (var i = 0; i < classes.length; ++i) {
- var cls = classes[i];
- if (/^highlight-/.test(cls)) {
- return cls.slice(10);
- }
- }
- return null;
- }
- // programming language switcher
- function findSheet(pattern, fromSheet) {
- if (fromSheet) {
- // cssRules may be `null` in iOS safari (?)
- var rules = fromSheet.cssRules || [];
- for(var i=0; i= scrollHeight - offsetBottom) ? 'bottom' :
- offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
-
- if (this.affixed === affix) return
- if (this.unpin != null) this.$element.css('top', '')
-
- var affixType = 'affix' + (affix ? '-' + affix : '')
- var e = $.Event(affixType + '.bs.affix')
-
- this.$element.trigger(e)
-
- if (e.isDefaultPrevented()) return
-
- this.affixed = affix
- this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
-
- this.$element
- .removeClass(Affix.RESET)
- .addClass(affixType)
- .trigger($.Event(affixType.replace('affix', 'affixed')))
-
- if (affix == 'bottom') {
- this.$element.offset({
- top: scrollHeight - this.$element.height() - offsetBottom
- })
- }
- }
-
-
- // AFFIX PLUGIN DEFINITION
- // =======================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.affix')
- var options = typeof option == 'object' && option
-
- if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.affix
-
- $.fn.affix = Plugin
- $.fn.affix.Constructor = Affix
-
-
- // AFFIX NO CONFLICT
- // =================
-
- $.fn.affix.noConflict = function () {
- $.fn.affix = old
- return this
- }
-
-
- // AFFIX DATA-API
- // ==============
-
- $(window).on('load', function () {
- $('[data-spy="affix"]').each(function () {
- var $spy = $(this)
- var data = $spy.data()
-
- data.offset = data.offset || {}
-
- if (data.offsetBottom) data.offset.bottom = data.offsetBottom
- if (data.offsetTop) data.offset.top = data.offsetTop
-
- Plugin.call($spy, data)
- })
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/alert.js b/doc/_themes/odoodoc/static/bootstrap/js/alert.js
deleted file mode 100644
index 0efd92cba8b..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/alert.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/* ========================================================================
- * Bootstrap: alert.js v3.2.0
- * http://getbootstrap.com/javascript/#alerts
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // ALERT CLASS DEFINITION
- // ======================
-
- var dismiss = '[data-dismiss="alert"]'
- var Alert = function (el) {
- $(el).on('click', dismiss, this.close)
- }
-
- Alert.VERSION = '3.2.0'
-
- Alert.prototype.close = function (e) {
- var $this = $(this)
- var selector = $this.attr('data-target')
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
-
- var $parent = $(selector)
-
- if (e) e.preventDefault()
-
- if (!$parent.length) {
- $parent = $this.hasClass('alert') ? $this : $this.parent()
- }
-
- $parent.trigger(e = $.Event('close.bs.alert'))
-
- if (e.isDefaultPrevented()) return
-
- $parent.removeClass('in')
-
- function removeElement() {
- // detach from parent, fire event then clean up data
- $parent.detach().trigger('closed.bs.alert').remove()
- }
-
- $.support.transition && $parent.hasClass('fade') ?
- $parent
- .one('bsTransitionEnd', removeElement)
- .emulateTransitionEnd(150) :
- removeElement()
- }
-
-
- // ALERT PLUGIN DEFINITION
- // =======================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.alert')
-
- if (!data) $this.data('bs.alert', (data = new Alert(this)))
- if (typeof option == 'string') data[option].call($this)
- })
- }
-
- var old = $.fn.alert
-
- $.fn.alert = Plugin
- $.fn.alert.Constructor = Alert
-
-
- // ALERT NO CONFLICT
- // =================
-
- $.fn.alert.noConflict = function () {
- $.fn.alert = old
- return this
- }
-
-
- // ALERT DATA-API
- // ==============
-
- $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/button.js b/doc/_themes/odoodoc/static/bootstrap/js/button.js
deleted file mode 100644
index dc3164f866f..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/button.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/* ========================================================================
- * Bootstrap: button.js v3.2.0
- * http://getbootstrap.com/javascript/#buttons
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // BUTTON PUBLIC CLASS DEFINITION
- // ==============================
-
- var Button = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Button.DEFAULTS, options)
- this.isLoading = false
- }
-
- Button.VERSION = '3.2.0'
-
- Button.DEFAULTS = {
- loadingText: 'loading...'
- }
-
- Button.prototype.setState = function (state) {
- var d = 'disabled'
- var $el = this.$element
- var val = $el.is('input') ? 'val' : 'html'
- var data = $el.data()
-
- state = state + 'Text'
-
- if (data.resetText == null) $el.data('resetText', $el[val]())
-
- $el[val](data[state] == null ? this.options[state] : data[state])
-
- // push to event loop to allow forms to submit
- setTimeout($.proxy(function () {
- if (state == 'loadingText') {
- this.isLoading = true
- $el.addClass(d).attr(d, d)
- } else if (this.isLoading) {
- this.isLoading = false
- $el.removeClass(d).removeAttr(d)
- }
- }, this), 0)
- }
-
- Button.prototype.toggle = function () {
- var changed = true
- var $parent = this.$element.closest('[data-toggle="buttons"]')
-
- if ($parent.length) {
- var $input = this.$element.find('input')
- if ($input.prop('type') == 'radio') {
- if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
- else $parent.find('.active').removeClass('active')
- }
- if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
- }
-
- if (changed) this.$element.toggleClass('active')
- }
-
-
- // BUTTON PLUGIN DEFINITION
- // ========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.button')
- var options = typeof option == 'object' && option
-
- if (!data) $this.data('bs.button', (data = new Button(this, options)))
-
- if (option == 'toggle') data.toggle()
- else if (option) data.setState(option)
- })
- }
-
- var old = $.fn.button
-
- $.fn.button = Plugin
- $.fn.button.Constructor = Button
-
-
- // BUTTON NO CONFLICT
- // ==================
-
- $.fn.button.noConflict = function () {
- $.fn.button = old
- return this
- }
-
-
- // BUTTON DATA-API
- // ===============
-
- $(document).on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
- var $btn = $(e.target)
- if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
- Plugin.call($btn, 'toggle')
- e.preventDefault()
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/carousel.js b/doc/_themes/odoodoc/static/bootstrap/js/carousel.js
deleted file mode 100644
index b7da1ba53e2..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/carousel.js
+++ /dev/null
@@ -1,223 +0,0 @@
-/* ========================================================================
- * Bootstrap: carousel.js v3.2.0
- * http://getbootstrap.com/javascript/#carousel
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // CAROUSEL CLASS DEFINITION
- // =========================
-
- var Carousel = function (element, options) {
- this.$element = $(element).on('keydown.bs.carousel', $.proxy(this.keydown, this))
- this.$indicators = this.$element.find('.carousel-indicators')
- this.options = options
- this.paused =
- this.sliding =
- this.interval =
- this.$active =
- this.$items = null
-
- this.options.pause == 'hover' && this.$element
- .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
- .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
- }
-
- Carousel.VERSION = '3.2.0'
-
- Carousel.DEFAULTS = {
- interval: 5000,
- pause: 'hover',
- wrap: true
- }
-
- Carousel.prototype.keydown = function (e) {
- switch (e.which) {
- case 37: this.prev(); break
- case 39: this.next(); break
- default: return
- }
-
- e.preventDefault()
- }
-
- Carousel.prototype.cycle = function (e) {
- e || (this.paused = false)
-
- this.interval && clearInterval(this.interval)
-
- this.options.interval
- && !this.paused
- && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
-
- return this
- }
-
- Carousel.prototype.getItemIndex = function (item) {
- this.$items = item.parent().children('.item')
- return this.$items.index(item || this.$active)
- }
-
- Carousel.prototype.to = function (pos) {
- var that = this
- var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
-
- if (pos > (this.$items.length - 1) || pos < 0) return
-
- if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
- if (activeIndex == pos) return this.pause().cycle()
-
- return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
- }
-
- Carousel.prototype.pause = function (e) {
- e || (this.paused = true)
-
- if (this.$element.find('.next, .prev').length && $.support.transition) {
- this.$element.trigger($.support.transition.end)
- this.cycle(true)
- }
-
- this.interval = clearInterval(this.interval)
-
- return this
- }
-
- Carousel.prototype.next = function () {
- if (this.sliding) return
- return this.slide('next')
- }
-
- Carousel.prototype.prev = function () {
- if (this.sliding) return
- return this.slide('prev')
- }
-
- Carousel.prototype.slide = function (type, next) {
- var $active = this.$element.find('.item.active')
- var $next = next || $active[type]()
- var isCycling = this.interval
- var direction = type == 'next' ? 'left' : 'right'
- var fallback = type == 'next' ? 'first' : 'last'
- var that = this
-
- if (!$next.length) {
- if (!this.options.wrap) return
- $next = this.$element.find('.item')[fallback]()
- }
-
- if ($next.hasClass('active')) return (this.sliding = false)
-
- var relatedTarget = $next[0]
- var slideEvent = $.Event('slide.bs.carousel', {
- relatedTarget: relatedTarget,
- direction: direction
- })
- this.$element.trigger(slideEvent)
- if (slideEvent.isDefaultPrevented()) return
-
- this.sliding = true
-
- isCycling && this.pause()
-
- if (this.$indicators.length) {
- this.$indicators.find('.active').removeClass('active')
- var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
- $nextIndicator && $nextIndicator.addClass('active')
- }
-
- var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
- if ($.support.transition && this.$element.hasClass('slide')) {
- $next.addClass(type)
- $next[0].offsetWidth // force reflow
- $active.addClass(direction)
- $next.addClass(direction)
- $active
- .one('bsTransitionEnd', function () {
- $next.removeClass([type, direction].join(' ')).addClass('active')
- $active.removeClass(['active', direction].join(' '))
- that.sliding = false
- setTimeout(function () {
- that.$element.trigger(slidEvent)
- }, 0)
- })
- .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
- } else {
- $active.removeClass('active')
- $next.addClass('active')
- this.sliding = false
- this.$element.trigger(slidEvent)
- }
-
- isCycling && this.cycle()
-
- return this
- }
-
-
- // CAROUSEL PLUGIN DEFINITION
- // ==========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.carousel')
- var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
- var action = typeof option == 'string' ? option : options.slide
-
- if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
- if (typeof option == 'number') data.to(option)
- else if (action) data[action]()
- else if (options.interval) data.pause().cycle()
- })
- }
-
- var old = $.fn.carousel
-
- $.fn.carousel = Plugin
- $.fn.carousel.Constructor = Carousel
-
-
- // CAROUSEL NO CONFLICT
- // ====================
-
- $.fn.carousel.noConflict = function () {
- $.fn.carousel = old
- return this
- }
-
-
- // CAROUSEL DATA-API
- // =================
-
- $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
- var href
- var $this = $(this)
- var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
- if (!$target.hasClass('carousel')) return
- var options = $.extend({}, $target.data(), $this.data())
- var slideIndex = $this.attr('data-slide-to')
- if (slideIndex) options.interval = false
-
- Plugin.call($target, options)
-
- if (slideIndex) {
- $target.data('bs.carousel').to(slideIndex)
- }
-
- e.preventDefault()
- })
-
- $(window).on('load', function () {
- $('[data-ride="carousel"]').each(function () {
- var $carousel = $(this)
- Plugin.call($carousel, $carousel.data())
- })
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/collapse.js b/doc/_themes/odoodoc/static/bootstrap/js/collapse.js
deleted file mode 100644
index e4e6d793339..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/collapse.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/* ========================================================================
- * Bootstrap: collapse.js v3.2.0
- * http://getbootstrap.com/javascript/#collapse
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // COLLAPSE PUBLIC CLASS DEFINITION
- // ================================
-
- var Collapse = function (element, options) {
- this.$element = $(element)
- this.options = $.extend({}, Collapse.DEFAULTS, options)
- this.transitioning = null
-
- if (this.options.parent) this.$parent = $(this.options.parent)
- if (this.options.toggle) this.toggle()
- }
-
- Collapse.VERSION = '3.2.0'
-
- Collapse.DEFAULTS = {
- toggle: true
- }
-
- Collapse.prototype.dimension = function () {
- var hasWidth = this.$element.hasClass('width')
- return hasWidth ? 'width' : 'height'
- }
-
- Collapse.prototype.show = function () {
- if (this.transitioning || this.$element.hasClass('in')) return
-
- var startEvent = $.Event('show.bs.collapse')
- this.$element.trigger(startEvent)
- if (startEvent.isDefaultPrevented()) return
-
- var actives = this.$parent && this.$parent.find('> .panel > .in')
-
- if (actives && actives.length) {
- var hasData = actives.data('bs.collapse')
- if (hasData && hasData.transitioning) return
- Plugin.call(actives, 'hide')
- hasData || actives.data('bs.collapse', null)
- }
-
- var dimension = this.dimension()
-
- this.$element
- .removeClass('collapse')
- .addClass('collapsing')[dimension](0)
-
- this.transitioning = 1
-
- var complete = function () {
- this.$element
- .removeClass('collapsing')
- .addClass('collapse in')[dimension]('')
- this.transitioning = 0
- this.$element
- .trigger('shown.bs.collapse')
- }
-
- if (!$.support.transition) return complete.call(this)
-
- var scrollSize = $.camelCase(['scroll', dimension].join('-'))
-
- this.$element
- .one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(350)[dimension](this.$element[0][scrollSize])
- }
-
- Collapse.prototype.hide = function () {
- if (this.transitioning || !this.$element.hasClass('in')) return
-
- var startEvent = $.Event('hide.bs.collapse')
- this.$element.trigger(startEvent)
- if (startEvent.isDefaultPrevented()) return
-
- var dimension = this.dimension()
-
- this.$element[dimension](this.$element[dimension]())[0].offsetHeight
-
- this.$element
- .addClass('collapsing')
- .removeClass('collapse')
- .removeClass('in')
-
- this.transitioning = 1
-
- var complete = function () {
- this.transitioning = 0
- this.$element
- .trigger('hidden.bs.collapse')
- .removeClass('collapsing')
- .addClass('collapse')
- }
-
- if (!$.support.transition) return complete.call(this)
-
- this.$element
- [dimension](0)
- .one('bsTransitionEnd', $.proxy(complete, this))
- .emulateTransitionEnd(350)
- }
-
- Collapse.prototype.toggle = function () {
- this[this.$element.hasClass('in') ? 'hide' : 'show']()
- }
-
-
- // COLLAPSE PLUGIN DEFINITION
- // ==========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.collapse')
- var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
- if (!data && options.toggle && option == 'show') option = !option
- if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.collapse
-
- $.fn.collapse = Plugin
- $.fn.collapse.Constructor = Collapse
-
-
- // COLLAPSE NO CONFLICT
- // ====================
-
- $.fn.collapse.noConflict = function () {
- $.fn.collapse = old
- return this
- }
-
-
- // COLLAPSE DATA-API
- // =================
-
- $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
- var href
- var $this = $(this)
- var target = $this.attr('data-target')
- || e.preventDefault()
- || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
- var $target = $(target)
- var data = $target.data('bs.collapse')
- var option = data ? 'toggle' : $this.data()
- var parent = $this.attr('data-parent')
- var $parent = parent && $(parent)
-
- if (!data || !data.transitioning) {
- if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
- $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
- }
-
- Plugin.call($target, option)
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/dropdown.js b/doc/_themes/odoodoc/static/bootstrap/js/dropdown.js
deleted file mode 100644
index 88f118c2d39..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/dropdown.js
+++ /dev/null
@@ -1,151 +0,0 @@
-/* ========================================================================
- * Bootstrap: dropdown.js v3.2.0
- * http://getbootstrap.com/javascript/#dropdowns
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // DROPDOWN CLASS DEFINITION
- // =========================
-
- var backdrop = '.dropdown-backdrop'
- var toggle = '[data-toggle="dropdown"]'
- var Dropdown = function (element) {
- $(element).on('click.bs.dropdown', this.toggle)
- }
-
- Dropdown.VERSION = '3.2.0'
-
- Dropdown.prototype.toggle = function (e) {
- var $this = $(this)
-
- if ($this.is('.disabled, :disabled')) return
-
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
-
- clearMenus()
-
- if (!isActive) {
- if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
- // if mobile we use a backdrop because click events don't delegate
- $('').insertAfter($(this)).on('click', clearMenus)
- }
-
- var relatedTarget = { relatedTarget: this }
- $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
-
- if (e.isDefaultPrevented()) return
-
- $this.trigger('focus')
-
- $parent
- .toggleClass('open')
- .trigger('shown.bs.dropdown', relatedTarget)
- }
-
- return false
- }
-
- Dropdown.prototype.keydown = function (e) {
- if (!/(38|40|27)/.test(e.keyCode)) return
-
- var $this = $(this)
-
- e.preventDefault()
- e.stopPropagation()
-
- if ($this.is('.disabled, :disabled')) return
-
- var $parent = getParent($this)
- var isActive = $parent.hasClass('open')
-
- if (!isActive || (isActive && e.keyCode == 27)) {
- if (e.which == 27) $parent.find(toggle).trigger('focus')
- return $this.trigger('click')
- }
-
- var desc = ' li:not(.divider):visible a'
- var $items = $parent.find('[role="menu"]' + desc + ', [role="listbox"]' + desc)
-
- if (!$items.length) return
-
- var index = $items.index($items.filter(':focus'))
-
- if (e.keyCode == 38 && index > 0) index-- // up
- if (e.keyCode == 40 && index < $items.length - 1) index++ // down
- if (!~index) index = 0
-
- $items.eq(index).trigger('focus')
- }
-
- function clearMenus(e) {
- if (e && e.which === 3) return
- $(backdrop).remove()
- $(toggle).each(function () {
- var $parent = getParent($(this))
- var relatedTarget = { relatedTarget: this }
- if (!$parent.hasClass('open')) return
- $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
- if (e.isDefaultPrevented()) return
- $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
- })
- }
-
- function getParent($this) {
- var selector = $this.attr('data-target')
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
-
- var $parent = selector && $(selector)
-
- return $parent && $parent.length ? $parent : $this.parent()
- }
-
-
- // DROPDOWN PLUGIN DEFINITION
- // ==========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.dropdown')
-
- if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
- if (typeof option == 'string') data[option].call($this)
- })
- }
-
- var old = $.fn.dropdown
-
- $.fn.dropdown = Plugin
- $.fn.dropdown.Constructor = Dropdown
-
-
- // DROPDOWN NO CONFLICT
- // ====================
-
- $.fn.dropdown.noConflict = function () {
- $.fn.dropdown = old
- return this
- }
-
-
- // APPLY TO STANDARD DROPDOWN ELEMENTS
- // ===================================
-
- $(document)
- .on('click.bs.dropdown.data-api', clearMenus)
- .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
- .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
- .on('keydown.bs.dropdown.data-api', toggle + ', [role="menu"], [role="listbox"]', Dropdown.prototype.keydown)
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/modal.js b/doc/_themes/odoodoc/static/bootstrap/js/modal.js
deleted file mode 100644
index 29eedf117ad..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/modal.js
+++ /dev/null
@@ -1,280 +0,0 @@
-/* ========================================================================
- * Bootstrap: modal.js v3.2.0
- * http://getbootstrap.com/javascript/#modals
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // MODAL CLASS DEFINITION
- // ======================
-
- var Modal = function (element, options) {
- this.options = options
- this.$body = $(document.body)
- this.$element = $(element)
- this.$backdrop =
- this.isShown = null
- this.scrollbarWidth = 0
-
- if (this.options.remote) {
- this.$element
- .find('.modal-content')
- .load(this.options.remote, $.proxy(function () {
- this.$element.trigger('loaded.bs.modal')
- }, this))
- }
- }
-
- Modal.VERSION = '3.2.0'
-
- Modal.DEFAULTS = {
- backdrop: true,
- keyboard: true,
- show: true
- }
-
- Modal.prototype.toggle = function (_relatedTarget) {
- return this.isShown ? this.hide() : this.show(_relatedTarget)
- }
-
- Modal.prototype.show = function (_relatedTarget) {
- var that = this
- var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
-
- this.$element.trigger(e)
-
- if (this.isShown || e.isDefaultPrevented()) return
-
- this.isShown = true
-
- this.checkScrollbar()
- this.$body.addClass('modal-open')
-
- this.setScrollbar()
- this.escape()
-
- this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
-
- this.backdrop(function () {
- var transition = $.support.transition && that.$element.hasClass('fade')
-
- if (!that.$element.parent().length) {
- that.$element.appendTo(that.$body) // don't move modals dom position
- }
-
- that.$element
- .show()
- .scrollTop(0)
-
- if (transition) {
- that.$element[0].offsetWidth // force reflow
- }
-
- that.$element
- .addClass('in')
- .attr('aria-hidden', false)
-
- that.enforceFocus()
-
- var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
-
- transition ?
- that.$element.find('.modal-dialog') // wait for modal to slide in
- .one('bsTransitionEnd', function () {
- that.$element.trigger('focus').trigger(e)
- })
- .emulateTransitionEnd(300) :
- that.$element.trigger('focus').trigger(e)
- })
- }
-
- Modal.prototype.hide = function (e) {
- if (e) e.preventDefault()
-
- e = $.Event('hide.bs.modal')
-
- this.$element.trigger(e)
-
- if (!this.isShown || e.isDefaultPrevented()) return
-
- this.isShown = false
-
- this.$body.removeClass('modal-open')
-
- this.resetScrollbar()
- this.escape()
-
- $(document).off('focusin.bs.modal')
-
- this.$element
- .removeClass('in')
- .attr('aria-hidden', true)
- .off('click.dismiss.bs.modal')
-
- $.support.transition && this.$element.hasClass('fade') ?
- this.$element
- .one('bsTransitionEnd', $.proxy(this.hideModal, this))
- .emulateTransitionEnd(300) :
- this.hideModal()
- }
-
- Modal.prototype.enforceFocus = function () {
- $(document)
- .off('focusin.bs.modal') // guard against infinite focus loop
- .on('focusin.bs.modal', $.proxy(function (e) {
- if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
- this.$element.trigger('focus')
- }
- }, this))
- }
-
- Modal.prototype.escape = function () {
- if (this.isShown && this.options.keyboard) {
- this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
- e.which == 27 && this.hide()
- }, this))
- } else if (!this.isShown) {
- this.$element.off('keyup.dismiss.bs.modal')
- }
- }
-
- Modal.prototype.hideModal = function () {
- var that = this
- this.$element.hide()
- this.backdrop(function () {
- that.$element.trigger('hidden.bs.modal')
- })
- }
-
- Modal.prototype.removeBackdrop = function () {
- this.$backdrop && this.$backdrop.remove()
- this.$backdrop = null
- }
-
- Modal.prototype.backdrop = function (callback) {
- var that = this
- var animate = this.$element.hasClass('fade') ? 'fade' : ''
-
- if (this.isShown && this.options.backdrop) {
- var doAnimate = $.support.transition && animate
-
- this.$backdrop = $('')
- .appendTo(this.$body)
-
- this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
- if (e.target !== e.currentTarget) return
- this.options.backdrop == 'static'
- ? this.$element[0].focus.call(this.$element[0])
- : this.hide.call(this)
- }, this))
-
- if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
-
- this.$backdrop.addClass('in')
-
- if (!callback) return
-
- doAnimate ?
- this.$backdrop
- .one('bsTransitionEnd', callback)
- .emulateTransitionEnd(150) :
- callback()
-
- } else if (!this.isShown && this.$backdrop) {
- this.$backdrop.removeClass('in')
-
- var callbackRemove = function () {
- that.removeBackdrop()
- callback && callback()
- }
- $.support.transition && this.$element.hasClass('fade') ?
- this.$backdrop
- .one('bsTransitionEnd', callbackRemove)
- .emulateTransitionEnd(150) :
- callbackRemove()
-
- } else if (callback) {
- callback()
- }
- }
-
- Modal.prototype.checkScrollbar = function () {
- if (document.body.clientWidth >= window.innerWidth) return
- this.scrollbarWidth = this.scrollbarWidth || this.measureScrollbar()
- }
-
- Modal.prototype.setScrollbar = function () {
- var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
- if (this.scrollbarWidth) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
- }
-
- Modal.prototype.resetScrollbar = function () {
- this.$body.css('padding-right', '')
- }
-
- Modal.prototype.measureScrollbar = function () { // thx walsh
- var scrollDiv = document.createElement('div')
- scrollDiv.className = 'modal-scrollbar-measure'
- this.$body.append(scrollDiv)
- var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
- this.$body[0].removeChild(scrollDiv)
- return scrollbarWidth
- }
-
-
- // MODAL PLUGIN DEFINITION
- // =======================
-
- function Plugin(option, _relatedTarget) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.modal')
- var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
-
- if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
- if (typeof option == 'string') data[option](_relatedTarget)
- else if (options.show) data.show(_relatedTarget)
- })
- }
-
- var old = $.fn.modal
-
- $.fn.modal = Plugin
- $.fn.modal.Constructor = Modal
-
-
- // MODAL NO CONFLICT
- // =================
-
- $.fn.modal.noConflict = function () {
- $.fn.modal = old
- return this
- }
-
-
- // MODAL DATA-API
- // ==============
-
- $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
- var $this = $(this)
- var href = $this.attr('href')
- var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
- var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
-
- if ($this.is('a')) e.preventDefault()
-
- $target.one('show.bs.modal', function (showEvent) {
- if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
- $target.one('hidden.bs.modal', function () {
- $this.is(':visible') && $this.trigger('focus')
- })
- })
- Plugin.call($target, option, this)
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/popover.js b/doc/_themes/odoodoc/static/bootstrap/js/popover.js
deleted file mode 100644
index 825e1b39089..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/popover.js
+++ /dev/null
@@ -1,113 +0,0 @@
-/* ========================================================================
- * Bootstrap: popover.js v3.2.0
- * http://getbootstrap.com/javascript/#popovers
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // POPOVER PUBLIC CLASS DEFINITION
- // ===============================
-
- var Popover = function (element, options) {
- this.init('popover', element, options)
- }
-
- if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
-
- Popover.VERSION = '3.2.0'
-
- Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
- placement: 'right',
- trigger: 'click',
- content: '',
- template: ''
- })
-
-
- // NOTE: POPOVER EXTENDS tooltip.js
- // ================================
-
- Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
-
- Popover.prototype.constructor = Popover
-
- Popover.prototype.getDefaults = function () {
- return Popover.DEFAULTS
- }
-
- Popover.prototype.setContent = function () {
- var $tip = this.tip()
- var title = this.getTitle()
- var content = this.getContent()
-
- $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
- $tip.find('.popover-content').empty()[ // we use append for html objects to maintain js events
- this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
- ](content)
-
- $tip.removeClass('fade top bottom left right in')
-
- // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
- // this manually by checking the contents.
- if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
- }
-
- Popover.prototype.hasContent = function () {
- return this.getTitle() || this.getContent()
- }
-
- Popover.prototype.getContent = function () {
- var $e = this.$element
- var o = this.options
-
- return $e.attr('data-content')
- || (typeof o.content == 'function' ?
- o.content.call($e[0]) :
- o.content)
- }
-
- Popover.prototype.arrow = function () {
- return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
- }
-
- Popover.prototype.tip = function () {
- if (!this.$tip) this.$tip = $(this.options.template)
- return this.$tip
- }
-
-
- // POPOVER PLUGIN DEFINITION
- // =========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.popover')
- var options = typeof option == 'object' && option
-
- if (!data && option == 'destroy') return
- if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.popover
-
- $.fn.popover = Plugin
- $.fn.popover.Constructor = Popover
-
-
- // POPOVER NO CONFLICT
- // ===================
-
- $.fn.popover.noConflict = function () {
- $.fn.popover = old
- return this
- }
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/scrollspy.js b/doc/_themes/odoodoc/static/bootstrap/js/scrollspy.js
deleted file mode 100644
index db2378787e3..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/scrollspy.js
+++ /dev/null
@@ -1,170 +0,0 @@
-/* ========================================================================
- * Bootstrap: scrollspy.js v3.2.0
- * http://getbootstrap.com/javascript/#scrollspy
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // SCROLLSPY CLASS DEFINITION
- // ==========================
-
- function ScrollSpy(element, options) {
- var process = $.proxy(this.process, this)
-
- this.$body = $('body')
- this.$scrollElement = $(element).is('body') ? $(window) : $(element)
- this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
- this.selector = (this.options.target || '') + ' .nav li > a'
- this.offsets = []
- this.targets = []
- this.activeTarget = null
- this.scrollHeight = 0
-
- this.$scrollElement.on('scroll.bs.scrollspy', process)
- this.refresh()
- this.process()
- }
-
- ScrollSpy.VERSION = '3.2.0'
-
- ScrollSpy.DEFAULTS = {
- offset: 10
- }
-
- ScrollSpy.prototype.getScrollHeight = function () {
- return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
- }
-
- ScrollSpy.prototype.refresh = function () {
- var offsetMethod = 'offset'
- var offsetBase = 0
-
- if (!$.isWindow(this.$scrollElement[0])) {
- offsetMethod = 'position'
- offsetBase = this.$scrollElement.scrollTop()
- }
-
- this.offsets = []
- this.targets = []
- this.scrollHeight = this.getScrollHeight()
-
- var self = this
-
- this.$body
- .find(this.selector)
- .map(function () {
- var $el = $(this)
- var href = $el.data('target') || $el.attr('href')
- var $href = /^#./.test(href) && $(href)
-
- return ($href
- && $href.length
- && $href.is(':visible')
- && [[$href[offsetMethod]().top + offsetBase, href]]) || null
- })
- .sort(function (a, b) { return a[0] - b[0] })
- .each(function () {
- self.offsets.push(this[0])
- self.targets.push(this[1])
- })
- }
-
- ScrollSpy.prototype.process = function () {
- var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
- var scrollHeight = this.getScrollHeight()
- var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
- var offsets = this.offsets
- var targets = this.targets
- var activeTarget = this.activeTarget
- var i
-
- if (this.scrollHeight != scrollHeight) {
- this.refresh()
- }
-
- if (scrollTop >= maxScroll) {
- return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
- }
-
- if (activeTarget && scrollTop <= offsets[0]) {
- return activeTarget != (i = targets[0]) && this.activate(i)
- }
-
- for (i = offsets.length; i--;) {
- activeTarget != targets[i]
- && scrollTop >= offsets[i]
- && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
- && this.activate(targets[i])
- }
- }
-
- ScrollSpy.prototype.activate = function (target) {
- this.activeTarget = target
-
- $(this.selector)
- .parentsUntil(this.options.target, '.active')
- .removeClass('active')
-
- var selector = this.selector +
- '[data-target="' + target + '"],' +
- this.selector + '[href="' + target + '"]'
-
- var active = $(selector)
- .parents('li')
- .addClass('active')
-
- if (active.parent('.dropdown-menu').length) {
- active = active
- .closest('li.dropdown')
- .addClass('active')
- }
-
- active.trigger('activate.bs.scrollspy')
- }
-
-
- // SCROLLSPY PLUGIN DEFINITION
- // ===========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.scrollspy')
- var options = typeof option == 'object' && option
-
- if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.scrollspy
-
- $.fn.scrollspy = Plugin
- $.fn.scrollspy.Constructor = ScrollSpy
-
-
- // SCROLLSPY NO CONFLICT
- // =====================
-
- $.fn.scrollspy.noConflict = function () {
- $.fn.scrollspy = old
- return this
- }
-
-
- // SCROLLSPY DATA-API
- // ==================
-
- $(window).on('load.bs.scrollspy.data-api', function () {
- $('[data-spy="scroll"]').each(function () {
- var $spy = $(this)
- Plugin.call($spy, $spy.data())
- })
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tab.js b/doc/_themes/odoodoc/static/bootstrap/js/tab.js
deleted file mode 100644
index c0e1e466cdb..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tab.js
+++ /dev/null
@@ -1,128 +0,0 @@
-/* ========================================================================
- * Bootstrap: tab.js v3.2.0
- * http://getbootstrap.com/javascript/#tabs
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // TAB CLASS DEFINITION
- // ====================
-
- var Tab = function (element) {
- this.element = $(element)
- }
-
- Tab.VERSION = '3.2.0'
-
- Tab.prototype.show = function () {
- var $this = this.element
- var $ul = $this.closest('ul:not(.dropdown-menu)')
- var selector = $this.data('target')
-
- if (!selector) {
- selector = $this.attr('href')
- selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
- }
-
- if ($this.parent('li').hasClass('active')) return
-
- var previous = $ul.find('.active:last a')[0]
- var e = $.Event('show.bs.tab', {
- relatedTarget: previous
- })
-
- $this.trigger(e)
-
- if (e.isDefaultPrevented()) return
-
- var $target = $(selector)
-
- this.activate($this.closest('li'), $ul)
- this.activate($target, $target.parent(), function () {
- $this.trigger({
- type: 'shown.bs.tab',
- relatedTarget: previous
- })
- })
- }
-
- Tab.prototype.activate = function (element, container, callback) {
- var $active = container.find('> .active')
- var transition = callback
- && $.support.transition
- && $active.hasClass('fade')
-
- function next() {
- $active
- .removeClass('active')
- .find('> .dropdown-menu > .active')
- .removeClass('active')
-
- element.addClass('active')
-
- if (transition) {
- element[0].offsetWidth // reflow for transition
- element.addClass('in')
- } else {
- element.removeClass('fade')
- }
-
- if (element.parent('.dropdown-menu')) {
- element.closest('li.dropdown').addClass('active')
- }
-
- callback && callback()
- }
-
- transition ?
- $active
- .one('bsTransitionEnd', next)
- .emulateTransitionEnd(150) :
- next()
-
- $active.removeClass('in')
- }
-
-
- // TAB PLUGIN DEFINITION
- // =====================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.tab')
-
- if (!data) $this.data('bs.tab', (data = new Tab(this)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.tab
-
- $.fn.tab = Plugin
- $.fn.tab.Constructor = Tab
-
-
- // TAB NO CONFLICT
- // ===============
-
- $.fn.tab.noConflict = function () {
- $.fn.tab = old
- return this
- }
-
-
- // TAB DATA-API
- // ============
-
- $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
- e.preventDefault()
- Plugin.call($(this), 'show')
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/index.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/index.html
deleted file mode 100644
index 3ebde11e6c9..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/index.html
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
- Bootstrap Plugin Test Suite
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/affix.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/affix.js
deleted file mode 100644
index 1cdfc7f9071..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/affix.js
+++ /dev/null
@@ -1,62 +0,0 @@
-$(function () {
- 'use strict';
-
- module('affix plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).affix, 'affix method is defined')
- })
-
- module('affix', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapAffix = $.fn.affix.noConflict()
- },
- teardown: function () {
- $.fn.affix = $.fn.bootstrapAffix
- delete $.fn.bootstrapAffix
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.affix, 'affix was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapAffix()[0] == document.body, 'document.body returned')
- })
-
- test('should exit early if element is not visible', function () {
- var $affix = $('').bootstrapAffix()
- $affix.data('bs.affix').checkPosition()
- ok(!$affix.hasClass('affix'), 'affix class was not added')
- })
-
- test('should trigger affixed event after affix', function () {
- stop()
-
- var template = $('')
- template.appendTo('body')
-
- $('#affixTarget').bootstrapAffix({
- offset: $('#affixTarget ul').position()
- })
-
- $('#affixTarget')
- .on('affix.bs.affix', function () {
- ok(true, 'affix event triggered')
- }).on('affixed.bs.affix', function () {
- ok(true, 'affixed event triggered')
- $('#affixTarget').remove()
- $('#affixAfter').remove()
- start()
- })
-
- setTimeout(function () {
- window.scrollTo(0, document.body.scrollHeight)
- setTimeout(function () {
- window.scroll(0, 0)
- }, 0)
- }, 0)
- })
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/alert.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/alert.js
deleted file mode 100644
index 31116cce25b..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/alert.js
+++ /dev/null
@@ -1,72 +0,0 @@
-$(function () {
- 'use strict';
-
- module('alert plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).alert, 'alert method is defined')
- })
-
- module('alert', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapAlert = $.fn.alert.noConflict()
- },
- teardown: function () {
- $.fn.alert = $.fn.bootstrapAlert
- delete $.fn.bootstrapAlert
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.alert, 'alert was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapAlert()[0] == document.body, 'document.body returned')
- })
-
- test('should fade element out on clicking .close', function () {
- var alertHTML = '' +
- '
×' +
- '
Holy guacamole! Best check yo self, you\'re not looking too good.
' +
- '
'
- var alert = $(alertHTML).bootstrapAlert()
-
- alert.find('.close').click()
-
- ok(!alert.hasClass('in'), 'remove .in class on .close click')
- })
-
- test('should remove element when clicking .close', function () {
- $.support.transition = false
-
- var alertHTML = '' +
- '
×' +
- '
Holy guacamole! Best check yo self, you\'re not looking too good.
' +
- '
'
- var alert = $(alertHTML).appendTo('#qunit-fixture').bootstrapAlert()
-
- ok($('#qunit-fixture').find('.alert-message').length, 'element added to dom')
-
- alert.find('.close').click()
-
- ok(!$('#qunit-fixture').find('.alert-message').length, 'element removed from dom')
- })
-
- test('should not fire closed when close is prevented', function () {
- $.support.transition = false
- stop()
- $('')
- .on('close.bs.alert', function (e) {
- e.preventDefault()
- ok(true)
- start()
- })
- .on('closed.bs.alert', function () {
- ok(false)
- })
- .bootstrapAlert('close')
- })
-
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/button.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/button.js
deleted file mode 100644
index 671a93891d4..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/button.js
+++ /dev/null
@@ -1,151 +0,0 @@
-$(function () {
- 'use strict';
-
- module('button plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).button, 'button method is defined')
- })
-
- module('button', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapButton = $.fn.button.noConflict()
- },
- teardown: function () {
- $.fn.button = $.fn.bootstrapButton
- delete $.fn.bootstrapButton
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.button, 'button was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapButton()[0] == document.body, 'document.body returned')
- })
-
- test('should return set state to loading', function () {
- var btn = $('')
- equal(btn.html(), 'mdo', 'btn text equals mdo')
- btn.bootstrapButton('loading')
- equal(btn.html(), 'fat', 'btn text equals fat')
- stop()
- setTimeout(function () {
- ok(btn.attr('disabled'), 'btn is disabled')
- ok(btn.hasClass('disabled'), 'btn has disabled class')
- start()
- }, 0)
- })
-
- test('should return reset state', function () {
- var btn = $('')
- equal(btn.html(), 'mdo', 'btn text equals mdo')
- btn.bootstrapButton('loading')
- equal(btn.html(), 'fat', 'btn text equals fat')
- stop()
- setTimeout(function () {
- ok(btn.attr('disabled'), 'btn is disabled')
- ok(btn.hasClass('disabled'), 'btn has disabled class')
- start()
- stop()
- btn.bootstrapButton('reset')
- equal(btn.html(), 'mdo', 'btn text equals mdo')
- setTimeout(function () {
- ok(!btn.attr('disabled'), 'btn is not disabled')
- ok(!btn.hasClass('disabled'), 'btn does not have disabled class')
- start()
- }, 0)
- }, 0)
- })
-
- test('should work with an empty string as reset state', function () {
- var btn = $('')
- equal(btn.html(), '', 'btn text equals ""')
- btn.bootstrapButton('loading')
- equal(btn.html(), 'fat', 'btn text equals fat')
- stop()
- setTimeout(function () {
- ok(btn.attr('disabled'), 'btn is disabled')
- ok(btn.hasClass('disabled'), 'btn has disabled class')
- start()
- stop()
- btn.bootstrapButton('reset')
- equal(btn.html(), '', 'btn text equals ""')
- setTimeout(function () {
- ok(!btn.attr('disabled'), 'btn is not disabled')
- ok(!btn.hasClass('disabled'), 'btn does not have disabled class')
- start()
- }, 0)
- }, 0)
- })
-
- test('should toggle active', function () {
- var btn = $('')
- ok(!btn.hasClass('active'), 'btn does not have active class')
- btn.bootstrapButton('toggle')
- ok(btn.hasClass('active'), 'btn has class active')
- })
-
- test('should toggle active when btn children are clicked', function () {
- var btn = $('')
- var inner = $('')
- btn
- .append(inner)
- .appendTo($('#qunit-fixture'))
- ok(!btn.hasClass('active'), 'btn does not have active class')
- inner.click()
- ok(btn.hasClass('active'), 'btn has class active')
- })
-
- test('should toggle active when btn children are clicked within btn-group', function () {
- var btngroup = $('')
- var btn = $('')
- var inner = $('')
- btngroup
- .append(btn.append(inner))
- .appendTo($('#qunit-fixture'))
- ok(!btn.hasClass('active'), 'btn does not have active class')
- inner.click()
- ok(btn.hasClass('active'), 'btn has class active')
- })
-
- test('should check for closest matching toggle', function () {
- var group = '' +
- '' +
- '' +
- '' +
- '
'
-
- group = $(group)
-
- var btn1 = $(group.children()[0])
- var btn2 = $(group.children()[1])
-
- group.appendTo($('#qunit-fixture'))
-
- ok(btn1.hasClass('active'), 'btn1 has active class')
- ok(btn1.find('input').prop('checked'), 'btn1 is checked')
- ok(!btn2.hasClass('active'), 'btn2 does not have active class')
- ok(!btn2.find('input').prop('checked'), 'btn2 is not checked')
- btn2.find('input').click()
- ok(!btn1.hasClass('active'), 'btn1 does not have active class')
- ok(!btn1.find('input').prop('checked'), 'btn1 is checked')
- ok(btn2.hasClass('active'), 'btn2 has active class')
- ok(btn2.find('input').prop('checked'), 'btn2 is checked')
-
- btn2.find('input').click() /* clicking an already checked radio should not un-check it */
- ok(!btn1.hasClass('active'), 'btn1 does not have active class')
- ok(!btn1.find('input').prop('checked'), 'btn1 is checked')
- ok(btn2.hasClass('active'), 'btn2 has active class')
- ok(btn2.find('input').prop('checked'), 'btn2 is checked')
- })
-
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/carousel.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/carousel.js
deleted file mode 100644
index 474cfb40c72..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/carousel.js
+++ /dev/null
@@ -1,174 +0,0 @@
-$(function () {
- 'use strict';
-
- module('carousel plugin')
-
- test('should be defined on jQuery object', function () {
- ok($(document.body).carousel, 'carousel method is defined')
- })
-
- module('carousel', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapCarousel = $.fn.carousel.noConflict()
- },
- teardown: function () {
- $.fn.carousel = $.fn.bootstrapCarousel
- delete $.fn.bootstrapCarousel
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.carousel, 'carousel was set back to undefined (orig value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapCarousel()[0] == document.body, 'document.body returned')
- })
-
- test('should not fire slide when slide is prevented', function () {
- $.support.transition = false
- stop()
- $('')
- .on('slide.bs.carousel', function (e) {
- e.preventDefault()
- ok(true)
- start()
- })
- .on('slid.bs.carousel', function () {
- ok(false)
- })
- .bootstrapCarousel('next')
- })
-
- test('should reset when slide is prevented', function () {
- var template = ''
- var $carousel = $(template)
- $.support.transition = false
- stop()
- $carousel.one('slide.bs.carousel', function (e) {
- e.preventDefault()
- setTimeout(function () {
- ok($carousel.find('.item:eq(0)').is('.active'))
- ok($carousel.find('.carousel-indicators li:eq(0)').is('.active'))
- $carousel.bootstrapCarousel('next')
- }, 1)
- })
- $carousel.one('slid.bs.carousel', function () {
- setTimeout(function () {
- ok($carousel.find('.item:eq(1)').is('.active'))
- ok($carousel.find('.carousel-indicators li:eq(1)').is('.active'))
- start()
- }, 1)
- })
- $carousel.bootstrapCarousel('next')
- })
-
- test('should fire slide event with direction', function () {
- var template = '{{_i}}First Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Second Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Third Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
‹› '
- $.support.transition = false
- stop()
- $(template).on('slide.bs.carousel', function (e) {
- e.preventDefault()
- ok(e.direction)
- ok(e.direction === 'right' || e.direction === 'left')
- start()
- }).bootstrapCarousel('next')
- })
-
- test('should fire slid event with direction', function () {
- var template = '{{_i}}First Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Second Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Third Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
‹› '
- $.support.transition = false
- stop()
- $(template).on('slid.bs.carousel', function (e) {
- e.preventDefault()
- ok(e.direction)
- ok(e.direction === 'right' || e.direction === 'left')
- start()
- }).bootstrapCarousel('next')
- })
-
- test('should fire slide event with relatedTarget', function () {
- var template = '{{_i}}First Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Second Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Third Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
‹› '
- $.support.transition = false
- stop()
- $(template)
- .on('slide.bs.carousel', function (e) {
- e.preventDefault()
- ok(e.relatedTarget)
- ok($(e.relatedTarget).hasClass('item'))
- start()
- })
- .bootstrapCarousel('next')
- })
-
- test('should fire slid event with relatedTarget', function () {
- var template = '{{_i}}First Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Second Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Third Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
‹› '
- $.support.transition = false
- stop()
- $(template)
- .on('slid.bs.carousel', function (e) {
- e.preventDefault()
- ok(e.relatedTarget)
- ok($(e.relatedTarget).hasClass('item'))
- start()
- })
- .bootstrapCarousel('next')
- })
-
- test('should set interval from data attribute', 4, function () {
- var template = $(' {{_i}}First Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Second Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
{{_i}}Third Thumbnail label{{/i}}
Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.
‹ › ')
- template.attr('data-interval', 1814)
-
- template.appendTo('body')
- $('[data-slide]').first().click()
- ok($('#myCarousel').data('bs.carousel').options.interval == 1814)
- $('#myCarousel').remove()
-
- template.appendTo('body').attr('data-modal', 'foobar')
- $('[data-slide]').first().click()
- ok($('#myCarousel').data('bs.carousel').options.interval == 1814, 'even if there is an data-modal attribute set')
- $('#myCarousel').remove()
-
- template.appendTo('body')
- $('[data-slide]').first().click()
- $('#myCarousel').attr('data-interval', 1860)
- $('[data-slide]').first().click()
- ok($('#myCarousel').data('bs.carousel').options.interval == 1814, 'attributes should be read only on initialization')
- $('#myCarousel').remove()
-
- template.attr('data-interval', false)
- template.appendTo('body')
- $('#myCarousel').bootstrapCarousel(1)
- ok($('#myCarousel').data('bs.carousel').options.interval === false, 'data attribute has higher priority than default options')
- $('#myCarousel').remove()
- })
-
- test('should skip over non-items', function () {
- $.support.transition = false
-
- var $template = $(
- ''
- + '
'
- + '
'
- + '
'
- + '
'
- + ''
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- + '
'
- )
-
- $template.bootstrapCarousel()
-
- equal($template.find('.item')[0], $template.find('.active')[0], 'the first carousel item should be active')
-
- $template.bootstrapCarousel(1)
-
- equal($template.find('.item')[1], $template.find('.active')[0], 'the second carousel item should be active')
- })
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/collapse.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/collapse.js
deleted file mode 100644
index 4a0cf2b2e8f..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/collapse.js
+++ /dev/null
@@ -1,174 +0,0 @@
-$(function () {
- 'use strict';
-
- module('collapse plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).collapse, 'collapse method is defined')
- })
-
- module('collapse', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapCollapse = $.fn.collapse.noConflict()
- },
- teardown: function () {
- $.fn.collapse = $.fn.bootstrapCollapse
- delete $.fn.bootstrapCollapse
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.collapse, 'collapse was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapCollapse()[0] == document.body, 'document.body returned')
- })
-
- test('should show a collapsed element', function () {
- var el = $('').bootstrapCollapse('show')
- ok(el.hasClass('in'), 'has class in')
- ok(!/height/.test(el.attr('style')), 'has height reset')
- })
-
- test('should hide a collapsed element', function () {
- var el = $('').bootstrapCollapse('hide')
- ok(!el.hasClass('in'), 'does not have class in')
- ok(/height/.test(el.attr('style')), 'has height set')
- })
-
- test('should not fire shown when show is prevented', function () {
- $.support.transition = false
- stop()
- $('')
- .on('show.bs.collapse', function (e) {
- e.preventDefault()
- ok(true)
- start()
- })
- .on('shown.bs.collapse', function () {
- ok(false)
- })
- .bootstrapCollapse('show')
- })
-
- test('should reset style to auto after finishing opening collapse', function () {
- $.support.transition = false
- stop()
- $('')
- .on('show.bs.collapse', function () {
- ok(this.style.height == '0px')
- })
- .on('shown.bs.collapse', function () {
- ok(this.style.height === '')
- start()
- })
- .bootstrapCollapse('show')
- })
-
- test('should add active class to target when collapse shown', function () {
- $.support.transition = false
- stop()
-
- var target = $('')
- .appendTo($('#qunit-fixture'))
-
- $('')
- .appendTo($('#qunit-fixture'))
- .on('show.bs.collapse', function () {
- ok(!target.hasClass('collapsed'))
- start()
- })
-
- target.click()
- })
-
- test('should remove active class to target when collapse hidden', function () {
- $.support.transition = false
- stop()
-
- var target = $('')
- .appendTo($('#qunit-fixture'))
-
- $('')
- .appendTo($('#qunit-fixture'))
- .on('hide.bs.collapse', function () {
- ok(target.hasClass('collapsed'))
- start()
- })
-
- target.click()
- })
-
- test('should remove active class from inactive accordion targets', function () {
- $.support.transition = false
- stop()
-
- var accordion = $('')
- .appendTo($('#qunit-fixture'))
-
- var target1 = $('')
- .appendTo(accordion.find('.accordion-group').eq(0))
-
- $('')
- .appendTo(accordion.find('.accordion-group').eq(0))
-
- var target2 = $('')
- .appendTo(accordion.find('.accordion-group').eq(1))
-
- $('')
- .appendTo(accordion.find('.accordion-group').eq(1))
-
- var target3 = $('')
- .appendTo(accordion.find('.accordion-group').eq(2))
-
- $('')
- .appendTo(accordion.find('.accordion-group').eq(2))
- .on('show.bs.collapse', function () {
- ok(target1.hasClass('collapsed'))
- ok(target2.hasClass('collapsed'))
- ok(!target3.hasClass('collapsed'))
-
- start()
- })
-
- target3.click()
- })
-
- test('should allow dots in data-parent', function () {
- $.support.transition = false
- stop()
-
- var accordion = $('')
- .appendTo($('#qunit-fixture'))
-
- var target1 = $('')
- .appendTo(accordion.find('.accordion-group').eq(0))
-
- $('')
- .appendTo(accordion.find('.accordion-group').eq(0))
-
- var target2 = $('')
- .appendTo(accordion.find('.accordion-group').eq(1))
-
- $('')
- .appendTo(accordion.find('.accordion-group').eq(1))
-
- var target3 = $('')
- .appendTo(accordion.find('.accordion-group').eq(2))
-
- $('')
- .appendTo(accordion.find('.accordion-group').eq(2))
- .on('show.bs.collapse', function () {
- ok(target1.hasClass('collapsed'))
- ok(target2.hasClass('collapsed'))
- ok(!target3.hasClass('collapsed'))
-
- start()
- })
-
- target3.click()
- })
-
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/dropdown.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/dropdown.js
deleted file mode 100644
index f21aa98fc39..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/dropdown.js
+++ /dev/null
@@ -1,228 +0,0 @@
-$(function () {
- 'use strict';
-
- module('dropdowns plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).dropdown, 'dropdown method is defined')
- })
-
- module('dropdowns', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapDropdown = $.fn.dropdown.noConflict()
- },
- teardown: function () {
- $.fn.dropdown = $.fn.bootstrapDropdown
- delete $.fn.bootstrapDropdown
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.dropdown, 'dropdown was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- var el = $('')
- ok(el.bootstrapDropdown()[0] === el[0], 'same element returned')
- })
-
- test('should not open dropdown if target is disabled', function () {
- var dropdownHTML = '' +
- '- ' +
- '' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().click()
-
- ok(!dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
- })
-
- test('should not open dropdown if target is disabled', function () {
- var dropdownHTML = '' +
- '- ' +
- '' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().click()
-
- ok(!dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
- })
-
- test('should add class open to menu if clicked', function () {
- var dropdownHTML = '' +
- '- ' +
- 'Dropdown' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().click()
-
- ok(dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
- })
-
- test('should test if element has a # before assuming it\'s a selector', function () {
- var dropdownHTML = '' +
- '- ' +
- 'Dropdown' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().click()
-
- ok(dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
- })
-
-
- test('should remove open class if body clicked', function () {
- var dropdownHTML = '' +
- '- ' +
- 'Dropdown' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML)
- .appendTo('#qunit-fixture')
- .find('[data-toggle="dropdown"]')
- .bootstrapDropdown()
- .click()
-
- ok(dropdown.parent('.dropdown').hasClass('open'), 'open class added on click')
- $('body').click()
- ok(!dropdown.parent('.dropdown').hasClass('open'), 'open class removed')
- dropdown.remove()
- })
-
- test('should remove open class if body clicked, with multiple drop downs', function () {
- var dropdownHTML = '' +
- '' +
- ' ' +
- ' ' +
- ' ' +
- '
'
- var dropdowns = $(dropdownHTML).appendTo('#qunit-fixture').find('[data-toggle="dropdown"]')
- var first = dropdowns.first()
- var last = dropdowns.last()
-
- ok(dropdowns.length == 2, 'Should be two dropdowns')
-
- first.click()
- ok(first.parents('.open').length == 1, 'open class added on click')
- ok($('#qunit-fixture .open').length == 1, 'only one object is open')
- $('body').click()
- ok($('#qunit-fixture .open').length === 0, 'open class removed')
-
- last.click()
- ok(last.parent('.open').length == 1, 'open class added on click')
- ok($('#qunit-fixture .open').length == 1, 'only one object is open')
- $('body').click()
- ok($('#qunit-fixture .open').length === 0, 'open class removed')
-
- $('#qunit-fixture').html('')
- })
-
- test('should fire show and hide event', function () {
- var dropdownHTML = '' +
- '- ' +
- 'Dropdown' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML)
- .appendTo('#qunit-fixture')
- .find('[data-toggle="dropdown"]')
- .bootstrapDropdown()
-
- stop()
-
- dropdown
- .parent('.dropdown')
- .on('show.bs.dropdown', function () {
- ok(true, 'show was called')
- })
- .on('hide.bs.dropdown', function () {
- ok(true, 'hide was called')
- start()
- })
-
- dropdown.click()
- $(document.body).click()
- })
-
-
- test('should fire shown and hiden event', function () {
- var dropdownHTML = '' +
- '- ' +
- 'Dropdown' +
- '' +
- '
' +
- '
'
- var dropdown = $(dropdownHTML)
- .appendTo('#qunit-fixture')
- .find('[data-toggle="dropdown"]')
- .bootstrapDropdown()
-
- stop()
-
- dropdown
- .parent('.dropdown')
- .on('shown.bs.dropdown', function () {
- ok(true, 'show was called')
- })
- .on('hidden.bs.dropdown', function () {
- ok(true, 'hide was called')
- start()
- })
-
- dropdown.click()
- $(document.body).click()
- })
-
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/modal.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/modal.js
deleted file mode 100644
index a415129aaef..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/modal.js
+++ /dev/null
@@ -1,256 +0,0 @@
-$(function () {
- 'use strict';
-
- module('modal plugin')
-
- test('should be defined on jquery object', function () {
- var div = $('')
- ok(div.modal, 'modal method is defined')
- })
-
- module('modal', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapModal = $.fn.modal.noConflict()
- },
- teardown: function () {
- $.fn.modal = $.fn.bootstrapModal
- delete $.fn.bootstrapModal
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.modal, 'modal was set back to undefined (orig value)')
- })
-
- test('should return element', function () {
- var div = $('')
- ok(div.bootstrapModal() == div, 'document.body returned')
- $('#modal-test').remove()
- })
-
- test('should expose defaults var for settings', function () {
- ok($.fn.bootstrapModal.Constructor.DEFAULTS, 'default object exposed')
- })
-
- test('should insert into dom when show method is called', function () {
- stop()
- $.support.transition = false
- $('')
- .on('shown.bs.modal', function () {
- ok($('#modal-test').length, 'modal inserted into dom')
- $(this).remove()
- start()
- })
- .bootstrapModal('show')
- })
-
- test('should fire show event', function () {
- stop()
- $.support.transition = false
- $('')
- .on('show.bs.modal', function () {
- ok(true, 'show was called')
- })
- .on('shown.bs.modal', function () {
- $(this).remove()
- start()
- })
- .bootstrapModal('show')
- })
-
- test('should not fire shown when default prevented', function () {
- stop()
- $.support.transition = false
- $('')
- .on('show.bs.modal', function (e) {
- e.preventDefault()
- ok(true, 'show was called')
- start()
- })
- .on('shown.bs.modal', function () {
- ok(false, 'shown was called')
- })
- .bootstrapModal('show')
- })
-
- test('should hide modal when hide is called', function () {
- stop()
- $.support.transition = false
-
- $('')
- .on('shown.bs.modal', function () {
- ok($('#modal-test').is(':visible'), 'modal visible')
- ok($('#modal-test').length, 'modal inserted into dom')
- $(this).bootstrapModal('hide')
- })
- .on('hidden.bs.modal', function () {
- ok(!$('#modal-test').is(':visible'), 'modal hidden')
- $('#modal-test').remove()
- start()
- })
- .bootstrapModal('show')
- })
-
- test('should toggle when toggle is called', function () {
- stop()
- $.support.transition = false
- var div = $('')
- div
- .on('shown.bs.modal', function () {
- ok($('#modal-test').is(':visible'), 'modal visible')
- ok($('#modal-test').length, 'modal inserted into dom')
- div.bootstrapModal('toggle')
- })
- .on('hidden.bs.modal', function () {
- ok(!$('#modal-test').is(':visible'), 'modal hidden')
- div.remove()
- start()
- })
- .bootstrapModal('toggle')
- })
-
- test('should remove from dom when click [data-dismiss="modal"]', function () {
- stop()
- $.support.transition = false
- var div = $('
')
- div
- .on('shown.bs.modal', function () {
- ok($('#modal-test').is(':visible'), 'modal visible')
- ok($('#modal-test').length, 'modal inserted into dom')
- div.find('.close').click()
- })
- .on('hidden.bs.modal', function () {
- ok(!$('#modal-test').is(':visible'), 'modal hidden')
- div.remove()
- start()
- })
- .bootstrapModal('toggle')
- })
-
- test('should allow modal close with "backdrop:false"', function () {
- stop()
- $.support.transition = false
- var div = $('', { id: 'modal-test', 'data-backdrop': false })
- div
- .on('shown.bs.modal', function () {
- ok($('#modal-test').is(':visible'), 'modal visible')
- div.bootstrapModal('hide')
- })
- .on('hidden.bs.modal', function () {
- ok(!$('#modal-test').is(':visible'), 'modal hidden')
- div.remove()
- start()
- })
- .bootstrapModal('show')
- })
-
- test('should close modal when clicking outside of modal-content', function () {
- stop()
- $.support.transition = false
- var div = $('
')
- div
- .on('shown.bs.modal', function () {
- ok($('#modal-test').length, 'modal insterted into dom')
- $('.contents').click()
- ok($('#modal-test').is(':visible'), 'modal visible')
- $('#modal-test').click()
- })
- .on('hidden.bs.modal', function () {
- ok(!$('#modal-test').is(':visible'), 'modal hidden')
- div.remove()
- start()
- })
- .bootstrapModal('show')
- })
-
- test('should trigger hide event once when clicking outside of modal-content', function () {
- stop()
- $.support.transition = false
-
- var triggered
- var div = $('
')
-
- div
- .on('shown.bs.modal', function () {
- triggered = 0
- $('#modal-test').click()
- })
- .on('hide.bs.modal', function () {
- triggered += 1
- ok(triggered === 1, 'modal hide triggered once')
- start()
- })
- .bootstrapModal('show')
- })
-
- test('should close reopened modal with [data-dismiss="modal"] click', function () {
- stop()
- $.support.transition = false
- var div = $('
')
- div
- .on('shown.bs.modal', function () {
- $('#close').click()
- ok(!$('#modal-test').is(':visible'), 'modal hidden')
- })
- .one('hidden.bs.modal', function () {
- div.one('hidden.bs.modal', function () {
- start()
- }).bootstrapModal('show')
- })
- .bootstrapModal('show')
-
- div.remove()
- })
-
- test('should restore focus to toggling element when modal is hidden after having been opened via data-api', function () {
- stop()
- $.support.transition = false
- var toggleBtn = $('
').appendTo('#qunit-fixture')
- var div = $('
')
- div
- .on('hidden.bs.modal', function () {
- window.setTimeout(function () { // give the focus restoration callback a chance to run
- equal(document.activeElement, toggleBtn[0], 'toggling element is once again focused')
- div.remove()
- toggleBtn.remove()
- start()
- }, 0)
- })
- .on('shown.bs.modal', function () {
- $('#close').click()
- })
- .appendTo('#qunit-fixture')
- toggleBtn.click()
- })
-
- test('should not restore focus to toggling element if the associated show event gets prevented', function () {
- stop()
- $.support.transition = false
- var toggleBtn = $('
').appendTo('#qunit-fixture')
- var otherBtn = $('
').appendTo('#qunit-fixture')
- var div = $('
')
- div
- .one('show.bs.modal', function (e) {
- e.preventDefault()
- otherBtn.focus()
- window.setTimeout(function () { // give the focus event from the previous line a chance to run
- div.bootstrapModal('show')
- }, 0)
- })
- .on('hidden.bs.modal', function () {
- window.setTimeout(function () { // give the focus restoration callback a chance to run (except it shouldn't run in this case)
- equal(document.activeElement, otherBtn[0], 'show was prevented, so focus should not have been restored to toggling element')
- div.remove()
- toggleBtn.remove()
- otherBtn.remove()
- start()
- }, 0)
- })
- .on('shown.bs.modal', function () {
- $('#close').click()
- })
- .appendTo('#qunit-fixture')
- toggleBtn.click()
- })
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/phantom.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/phantom.js
deleted file mode 100644
index b5f0c67a67a..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/phantom.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * grunt-contrib-qunit
- * http://gruntjs.com/
- *
- * Copyright (c) 2013 "Cowboy" Ben Alman, contributors
- * Licensed under the MIT license.
- */
-
-(function () {
- 'use strict';
-
- // Don't re-order tests.
- QUnit.config.reorder = false
- // Run tests serially, not in parallel.
- QUnit.config.autorun = false
-
- // Send messages to the parent PhantomJS process via alert! Good times!!
- function sendMessage() {
- var args = [].slice.call(arguments)
- alert(JSON.stringify(args))
- }
-
- // These methods connect QUnit to PhantomJS.
- QUnit.log = function (obj) {
- // What is this I don’t even
- if (obj.message === '[object Object], undefined:undefined') { return }
- // Parse some stuff before sending it.
- var actual = QUnit.jsDump.parse(obj.actual)
- var expected = QUnit.jsDump.parse(obj.expected)
- // Send it.
- sendMessage('qunit.log', obj.result, actual, expected, obj.message, obj.source)
- }
-
- QUnit.testStart = function (obj) {
- sendMessage('qunit.testStart', obj.name)
- }
-
- QUnit.testDone = function (obj) {
- sendMessage('qunit.testDone', obj.name, obj.failed, obj.passed, obj.total)
- }
-
- QUnit.moduleStart = function (obj) {
- sendMessage('qunit.moduleStart', obj.name)
- }
-
- QUnit.begin = function () {
- sendMessage('qunit.begin')
- console.log('Starting test suite')
- console.log('================================================\n')
- }
-
- QUnit.moduleDone = function (opts) {
- if (opts.failed === 0) {
- console.log('\r\u2714 All tests passed in "' + opts.name + '" module')
- } else {
- console.log('\u2716 ' + opts.failed + ' tests failed in "' + opts.name + '" module')
- }
- sendMessage('qunit.moduleDone', opts.name, opts.failed, opts.passed, opts.total)
- }
-
- QUnit.done = function (opts) {
- console.log('\n================================================')
- console.log('Tests completed in ' + opts.runtime + ' milliseconds')
- console.log(opts.passed + ' tests of ' + opts.total + ' passed, ' + opts.failed + ' failed.')
- sendMessage('qunit.done', opts.failed, opts.passed, opts.total, opts.runtime)
- }
-
-}())
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/popover.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/popover.js
deleted file mode 100644
index 16f94e14384..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/popover.js
+++ /dev/null
@@ -1,184 +0,0 @@
-$(function () {
- 'use strict';
-
- module('popover plugin')
-
- test('should be defined on jquery object', function () {
- var div = $('
')
- ok(div.popover, 'popover method is defined')
- })
-
- module('popover', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapPopover = $.fn.popover.noConflict()
- },
- teardown: function () {
- $.fn.popover = $.fn.bootstrapPopover
- delete $.fn.bootstrapPopover
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.popover, 'popover was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- var div = $('
')
- ok(div.bootstrapPopover() == div, 'document.body returned')
- })
-
- test('should render popover element', function () {
- $.support.transition = false
- var popover = $('
@mdo')
- .appendTo('#qunit-fixture')
- .bootstrapPopover('show')
-
- ok($('.popover').length, 'popover was inserted')
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover removed')
- })
-
- test('should store popover instance in popover data object', function () {
- $.support.transition = false
- var popover = $('
@mdo')
- .bootstrapPopover()
-
- ok(!!popover.data('bs.popover'), 'popover instance exists')
- })
-
- test('should store popover trigger in popover instance data object', function () {
- $.support.transition = false
- var popover = $('
@ResentedHook')
- .appendTo('#qunit-fixture')
- .bootstrapPopover()
- popover.bootstrapPopover('show')
- ok(!!$('.popover').data('bs.popover'), 'popover trigger stored in instance data')
- $('#qunit-fixture').empty()
- })
-
- test('should get title and content from options', function () {
- $.support.transition = false
- var popover = $('
@fat')
- .appendTo('#qunit-fixture')
- .bootstrapPopover({
- title: function () {
- return '@fat'
- },
- content: function () {
- return 'loves writing tests (╯°□°)╯︵ ┻━┻'
- }
- })
-
- popover.bootstrapPopover('show')
-
- ok($('.popover').length, 'popover was inserted')
- equal($('.popover .popover-title').text(), '@fat', 'title correctly inserted')
- equal($('.popover .popover-content').text(), 'loves writing tests (╯°□°)╯︵ ┻━┻', 'content correctly inserted')
-
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover was removed')
- $('#qunit-fixture').empty()
- })
-
- test('should not duplicate HTML object', function () {
- $.support.transition = false
-
- var $div = $('
').html('loves writing tests (╯°□°)╯︵ ┻━┻')
-
- var popover = $('
@fat')
- .appendTo('#qunit-fixture')
- .bootstrapPopover({
- content: function () {
- return $div
- }
- })
-
- popover.bootstrapPopover('show')
- ok($('.popover').length, 'popover was inserted')
- equal($('.popover .popover-content').html(), $div, 'content correctly inserted')
-
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover was removed')
-
- popover.bootstrapPopover('show')
- ok($('.popover').length, 'popover was inserted')
- equal($('.popover .popover-content').html(), $div, 'content correctly inserted')
-
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover was removed')
- $('#qunit-fixture').empty()
- })
-
- test('should get title and content from attributes', function () {
- $.support.transition = false
- var popover = $('
@mdo')
- .appendTo('#qunit-fixture')
- .bootstrapPopover()
- .bootstrapPopover('show')
-
- ok($('.popover').length, 'popover was inserted')
- equal($('.popover .popover-title').text(), '@mdo', 'title correctly inserted')
- equal($('.popover .popover-content').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted')
-
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover was removed')
- $('#qunit-fixture').empty()
- })
-
-
- test('should get title and content from attributes #2', function () {
- $.support.transition = false
- var popover = $('
@mdo')
- .appendTo('#qunit-fixture')
- .bootstrapPopover({
- title: 'ignored title option',
- content: 'ignored content option'
- })
- .bootstrapPopover('show')
-
- ok($('.popover').length, 'popover was inserted')
- equal($('.popover .popover-title').text(), '@mdo', 'title correctly inserted')
- equal($('.popover .popover-content').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted')
-
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover was removed')
- $('#qunit-fixture').empty()
- })
-
- test('should respect custom classes', function () {
- $.support.transition = false
- var popover = $('
@fat')
- .appendTo('#qunit-fixture')
- .bootstrapPopover({
- title: 'Test',
- content: 'Test',
- template: '
'
- })
-
- popover.bootstrapPopover('show')
-
- ok($('.popover').length, 'popover was inserted')
- ok($('.popover').hasClass('foobar'), 'custom class is present')
-
- popover.bootstrapPopover('hide')
- ok(!$('.popover').length, 'popover was removed')
- $('#qunit-fixture').empty()
- })
-
- test('should destroy popover', function () {
- var popover = $('
').bootstrapPopover({
- trigger: 'hover'
- }).on('click.foo', function () {})
- ok(popover.data('bs.popover'), 'popover has data')
- ok($._data(popover[0], 'events').mouseover && $._data(popover[0], 'events').mouseout, 'popover has hover event')
- ok($._data(popover[0], 'events').click[0].namespace == 'foo', 'popover has extra click.foo event')
- popover.bootstrapPopover('show')
- popover.bootstrapPopover('destroy')
- ok(!popover.hasClass('in'), 'popover is hidden')
- ok(!popover.data('popover'), 'popover does not have data')
- ok($._data(popover[0], 'events').click[0].namespace == 'foo', 'popover still has click.foo')
- ok(!$._data(popover[0], 'events').mouseover && !$._data(popover[0], 'events').mouseout, 'popover does not have any events')
- })
-
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/scrollspy.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/scrollspy.js
deleted file mode 100644
index 2ec51fc2438..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/scrollspy.js
+++ /dev/null
@@ -1,117 +0,0 @@
-$(function () {
- 'use strict';
-
- module('scrollspy plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).scrollspy, 'scrollspy method is defined')
- })
-
- module('scrollspy', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapScrollspy = $.fn.scrollspy.noConflict()
- },
- teardown: function () {
- $.fn.scrollspy = $.fn.bootstrapScrollspy
- delete $.fn.bootstrapScrollspy
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.scrollspy, 'scrollspy was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapScrollspy()[0] == document.body, 'document.body returned')
- })
-
- test('should switch active class on scroll', function () {
- var sectionHTML = '
'
- $(sectionHTML).append('#qunit-fixture')
- var topbarHTML = '
'
- var $topbar = $(topbarHTML).bootstrapScrollspy()
-
- $(sectionHTML).append('#qunit-fixture')
- ok($topbar.find('.active', true))
- })
-
- asyncTest('should only switch active class on current target', function () {
- expect(1);
- var sectionHTML = '
'
- var $section = $(sectionHTML).appendTo('#qunit-fixture')
- var $scrollSpy = $section
- .show()
- .find('#scrollspy-example')
- .bootstrapScrollspy({ target: '#ss-target' })
-
- $scrollSpy.on('scroll.bs.scrollspy', function () {
- ok($section.hasClass('active'), 'Active class still on root node')
- start()
- })
- $scrollSpy.scrollTop(350);
- })
-
- asyncTest('middle navigation option correctly selected when large offset is used', function () {
- expect(3);
- var sectionHTML = '' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
'
- var $section = $(sectionHTML).appendTo('#qunit-fixture')
- var $scrollSpy = $section
- .show()
- .filter('#content')
- $scrollSpy.bootstrapScrollspy({ target: '#navigation', offset: $scrollSpy.position().top })
-
- $scrollSpy.on('scroll.bs.scrollspy', function () {
- ok(!$section.find('#one-link').parent().hasClass('active'), 'Active class removed from first section')
- ok($section.find('#two-link').parent().hasClass('active'), 'Active class on middle section')
- ok(!$section.find('#three-link').parent().hasClass('active'), 'Active class not on last section')
- start()
- })
- $scrollSpy.scrollTop(550);
- })
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/tab.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/tab.js
deleted file mode 100644
index 0c49feeaf8d..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/tab.js
+++ /dev/null
@@ -1,96 +0,0 @@
-$(function () {
- 'use strict';
-
- module('tabs plugin')
-
- test('should be defined on jquery object', function () {
- ok($(document.body).tab, 'tabs method is defined')
- })
-
- module('tabs', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapTab = $.fn.tab.noConflict()
- },
- teardown: function () {
- $.fn.tab = $.fn.bootstrapTab
- delete $.fn.bootstrapTab
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.tab, 'tab was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- ok($(document.body).bootstrapTab()[0] == document.body, 'document.body returned')
- })
-
- test('should activate element by tab id', function () {
- var tabsHTML = '
'
-
- $('
').appendTo('#qunit-fixture')
-
- $(tabsHTML).find('li:last a').bootstrapTab('show')
- equal($('#qunit-fixture').find('.active').attr('id'), 'profile')
-
- $(tabsHTML).find('li:first a').bootstrapTab('show')
- equal($('#qunit-fixture').find('.active').attr('id'), 'home')
- })
-
- test('should activate element by tab id', function () {
- var pillsHTML = '
'
-
- $('
').appendTo('#qunit-fixture')
-
- $(pillsHTML).find('li:last a').bootstrapTab('show')
- equal($('#qunit-fixture').find('.active').attr('id'), 'profile')
-
- $(pillsHTML).find('li:first a').bootstrapTab('show')
- equal($('#qunit-fixture').find('.active').attr('id'), 'home')
- })
-
-
- test('should not fire closed when close is prevented', function () {
- $.support.transition = false
- stop()
- $('
')
- .on('show.bs.tab', function (e) {
- e.preventDefault()
- ok(true)
- start()
- })
- .on('shown.bs.tab', function () {
- ok(false)
- })
- .bootstrapTab('show')
- })
-
- test('show and shown events should reference correct relatedTarget', function () {
- var dropHTML = '
' +
- '- 1' +
- '' +
- '
' +
- '
'
-
- $(dropHTML).find('ul>li:first a').bootstrapTab('show').end()
- .find('ul>li:last a')
- .on('show.bs.tab', function (event) {
- equal(event.relatedTarget.hash, '#1-1')
- })
- .on('show.bs.tab', function (event) {
- equal(event.relatedTarget.hash, '#1-1')
- })
- .bootstrapTab('show')
- })
-
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/tooltip.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/tooltip.js
deleted file mode 100644
index f4c840d840e..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/unit/tooltip.js
+++ /dev/null
@@ -1,595 +0,0 @@
-$(function () {
- 'use strict';
-
- module('tooltip plugin')
-
- test('should be defined on jquery object', function () {
- var div = $('
')
- ok(div.tooltip, 'popover method is defined')
- })
-
- module('tooltip', {
- setup: function () {
- // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
- $.fn.bootstrapTooltip = $.fn.tooltip.noConflict()
- },
- teardown: function () {
- $.fn.tooltip = $.fn.bootstrapTooltip
- delete $.fn.bootstrapTooltip
- }
- })
-
- test('should provide no conflict', function () {
- ok(!$.fn.tooltip, 'tooltip was set back to undefined (org value)')
- })
-
- test('should return element', function () {
- var div = $('
')
- ok(div.bootstrapTooltip() == div, 'document.body returned')
- })
-
- test('should expose default settings', function () {
- ok(!!$.fn.bootstrapTooltip.Constructor.DEFAULTS, 'defaults is defined')
- })
-
- test('should empty title attribute', function () {
- var tooltip = $('
').bootstrapTooltip()
- ok(tooltip.attr('title') === '', 'title attribute was emptied')
- })
-
- test('should add data attribute for referencing original title', function () {
- var tooltip = $('
').bootstrapTooltip()
- equal(tooltip.attr('data-original-title'), 'Another tooltip', 'original title preserved in data attribute')
- })
-
- test('should add set set aria describedby to the element called on show', function () {
- var tooltip = $('
').bootstrapTooltip()
- .appendTo('#qunit-fixture')
- .bootstrapTooltip('show')
- ok(tooltip.attr('aria-describedby'), 'has the right attributes')
- var id = $('.tooltip').attr('id')
-
- ok($('#' + id).length == 1, 'has a unique id')
- ok($('.tooltip').attr('aria-describedby') === tooltip.attr('id'), 'they match!')
- ok(tooltip.attr('aria-describedby') !== undefined, 'has the right attributes')
- })
-
- test('should remove the aria-describedby attributes on hide', function () {
- var tooltip = $('
').bootstrapTooltip()
- .appendTo('#qunit-fixture')
- .bootstrapTooltip('show')
- ok(tooltip.attr('aria-describedby'), 'has the right attributes')
- tooltip.bootstrapTooltip('hide')
- ok(!tooltip.attr('aria-describedby'), 'removed the attributes on hide')
- })
-
- test('should assign a unique id tooltip element', function () {
- $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip('show')
- var id = $('.tooltip').attr('id')
-
- ok($('#' + id).length == 1 && id.indexOf('tooltip') === 0, 'generated prefixed and unique tooltip id')
- })
-
- test('should place tooltips relative to placement option', function () {
- $.support.transition = false
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ placement: 'bottom' })
- .bootstrapTooltip('show')
-
- ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied')
- tooltip.bootstrapTooltip('hide')
- })
-
- test('should allow html entities', function () {
- $.support.transition = false
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ html: true })
- .bootstrapTooltip('show')
-
- ok($('.tooltip b').length, 'b tag was inserted')
- tooltip.bootstrapTooltip('hide')
- ok(!$('.tooltip').length, 'tooltip removed')
- })
-
- test('should respect custom classes', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ template: '
' })
- .bootstrapTooltip('show')
-
- ok($('.tooltip').hasClass('some-class'), 'custom class is present')
- tooltip.bootstrapTooltip('hide')
- ok(!$('.tooltip').length, 'tooltip removed')
- })
-
- test('should fire show event', function () {
- stop()
- $('
')
- .on('show.bs.tooltip', function () {
- ok(true, 'show was called')
- start()
- })
- .bootstrapTooltip('show')
- })
-
- test('should fire shown event', function () {
- stop()
- var tooltip = $('
').appendTo('#qunit-fixture')
- tooltip
- .on('shown.bs.tooltip', function () {
- ok(true, 'shown was called')
- tooltip.remove()
- start()
- })
- .bootstrapTooltip('show')
- })
-
- test('should not fire shown event when default prevented', function () {
- stop()
- $('
')
- .on('show.bs.tooltip', function (e) {
- e.preventDefault()
- ok(true, 'show was called')
- start()
- })
- .on('shown.bs.tooltip', function () {
- ok(false, 'shown was called')
- })
- .bootstrapTooltip('show')
- })
-
- test('should fire hide event', function () {
- stop()
- var tooltip = $('
').appendTo('#qunit-fixture')
- tooltip
- .on('shown.bs.tooltip', function () {
- $(this).bootstrapTooltip('hide')
- })
- .on('hide.bs.tooltip', function () {
- ok(true, 'hide was called')
- tooltip.remove()
- start()
- })
- .bootstrapTooltip('show')
- })
-
- test('should fire hidden event', function () {
- stop()
- var tooltip = $('
').appendTo('#qunit-fixture')
- tooltip
- .on('shown.bs.tooltip', function () {
- $(this).bootstrapTooltip('hide')
- })
- .on('hidden.bs.tooltip', function () {
- ok(true, 'hidden was called')
- tooltip.remove()
- start()
- })
- .bootstrapTooltip('show')
- })
-
- test('should not fire hidden event when default prevented', function () {
- stop()
- var tooltip = $('
').appendTo('#qunit-fixture')
- tooltip
- .on('shown.bs.tooltip', function () {
- $(this).bootstrapTooltip('hide')
- })
- .on('hide.bs.tooltip', function (e) {
- e.preventDefault()
- ok(true, 'hide was called')
- tooltip.remove()
- start()
- })
- .on('hidden.bs.tooltip', function () {
- ok(false, 'hidden was called')
- })
- .bootstrapTooltip('show')
- })
-
- test('should not show tooltip if leave event occurs before delay expires', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ delay: 200 })
-
- stop()
-
- tooltip.trigger('mouseenter')
-
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- tooltip.trigger('mouseout')
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- start()
- }, 200)
- }, 100)
- })
-
- test('should not show tooltip if leave event occurs before delay expires, even if hide delay is 0', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ delay: { show: 200, hide: 0 }})
-
- stop()
-
- tooltip.trigger('mouseenter')
-
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- tooltip.trigger('mouseout')
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- start()
- }, 200)
- }, 100)
- })
-
- test('should wait 200 ms before hiding the tooltip', 3, function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ delay: { show: 0, hide: 200 }})
-
- stop()
-
- tooltip.trigger('mouseenter')
-
- setTimeout(function () {
- ok($('.tooltip').is('.fade.in'), 'tooltip is faded in')
- tooltip.trigger('mouseout')
- setTimeout(function () {
- ok($('.tooltip').is('.fade.in'), '100ms:tooltip is still faded in')
- setTimeout(function () {
- ok(!$('.tooltip').is('.in'), 'tooltip removed')
- start()
- }, 150)
- }, 100)
- }, 1)
- })
-
- test('should not hide tooltip if leave event occurs, then tooltip is show immediately again', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ delay: { show: 0, hide: 200 }})
-
- stop()
-
- tooltip.trigger('mouseenter')
-
- setTimeout(function () {
- ok($('.tooltip').is('.fade.in'), 'tooltip is faded in')
- tooltip.trigger('mouseout')
- setTimeout(function () {
- ok($('.tooltip').is('.fade.in'), '100ms:tooltip is still faded in')
- tooltip.trigger('mouseenter')
- setTimeout(function () {
- ok($('.tooltip').is('.in'), 'tooltip removed')
- start()
- }, 150)
- }, 100)
- }, 1)
- })
-
- test('should not show tooltip if leave event occurs before delay expires', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ delay: 100 })
- stop()
- tooltip.trigger('mouseenter')
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- tooltip.trigger('mouseout')
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- start()
- }, 100)
- }, 50)
- })
-
- test('should show tooltip if leave event hasn\'t occured before delay expires', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ delay: 150 })
- stop()
- tooltip.trigger('mouseenter')
- setTimeout(function () {
- ok(!$('.tooltip').is('.fade.in'), 'tooltip is not faded in')
- }, 100)
- setTimeout(function () {
- ok($('.tooltip').is('.fade.in'), 'tooltip has faded in')
- start()
- }, 200)
- })
-
- test('should destroy tooltip', function () {
- var tooltip = $('
').bootstrapTooltip().on('click.foo', function () {})
- ok(tooltip.data('bs.tooltip'), 'tooltip has data')
- ok($._data(tooltip[0], 'events').mouseover && $._data(tooltip[0], 'events').mouseout, 'tooltip has hover event')
- ok($._data(tooltip[0], 'events').click[0].namespace == 'foo', 'tooltip has extra click.foo event')
- tooltip.bootstrapTooltip('show')
- tooltip.bootstrapTooltip('destroy')
- ok(!tooltip.hasClass('in'), 'tooltip is hidden')
- ok(!$._data(tooltip[0], 'bs.tooltip'), 'tooltip does not have data')
- ok($._data(tooltip[0], 'events').click[0].namespace == 'foo', 'tooltip still has click.foo')
- ok(!$._data(tooltip[0], 'events').mouseover && !$._data(tooltip[0], 'events').mouseout, 'tooltip does not have any events')
- })
-
- test('should show tooltip with delegate selector on click', function () {
- var div = $('
')
- div.appendTo('#qunit-fixture').bootstrapTooltip({
- selector: 'a[rel="tooltip"]', trigger: 'click'
- })
- div.find('a').trigger('click')
- ok($('.tooltip').is('.fade.in'), 'tooltip is faded in')
- })
-
- test('should show tooltip when toggle is called', function () {
- $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ trigger: 'manual' })
- .bootstrapTooltip('toggle')
- ok($('.tooltip').is('.fade.in'), 'tooltip should be toggled in')
- })
-
- test('should hide shown tooltip when toggle is called on tooltip', function () {
- var tooltip = $('
@ResentedHook')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ trigger: 'manual' })
- .bootstrapTooltip('toggle')
- $('.tooltip', '#qunit-fixture').bootstrapTooltip('toggle')
- ok($('.tooltip').not('.fade.in'), 'tooltip should be toggled out')
- tooltip.bootstrapTooltip('hide')
- $('#qunit-fixture').empty()
- })
-
- test('should place tooltips inside the body', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({ container: 'body' })
- .bootstrapTooltip('show')
- ok($('body > .tooltip').length, 'inside the body')
- ok(!$('#qunit-fixture > .tooltip').length, 'not found in parent')
- tooltip.bootstrapTooltip('hide')
- })
-
- test('should place tooltip inside window', function () {
- var container = $('
').appendTo('body')
- .css({ position: 'absolute', width: 200, height: 200, bottom: 0, left: 0 })
- $('
Hover me')
- .css({ position: 'absolute', top: 0, left: 0 })
- .appendTo(container)
- .bootstrapTooltip({ placement: 'top', animate: false })
- .bootstrapTooltip('show')
-
- stop()
-
- setTimeout(function () {
- ok($('.tooltip').offset().left >= 0)
-
- start()
- container.remove()
- }, 100)
- })
-
- test('should place tooltip on top of element', function () {
- var container = $('
').appendTo('body')
- .css({ position: 'absolute', bottom: 0, left: 0, textAlign: 'right', width: 300, height: 300 })
- var p = $('
').appendTo(container)
- var tooltiped = $('
Hover me')
- .css({ marginTop: 200 })
- .appendTo(p)
- .bootstrapTooltip({ placement: 'top', animate: false })
- .bootstrapTooltip('show')
-
- stop()
-
- setTimeout(function () {
- var tooltip = container.find('.tooltip')
-
- start()
- ok(Math.round(tooltip.offset().top + tooltip.outerHeight()) <= Math.round(tooltiped.offset().top))
- container.remove()
- }, 100)
- })
-
- test('should add position class before positioning so that position-specific styles are taken into account', function () {
- $('head').append('')
-
- var container = $('
').appendTo('body')
- var target = $('
')
- .appendTo(container)
- .bootstrapTooltip({ placement: 'right', viewport: null })
- .bootstrapTooltip('show')
- var tooltip = container.find('.tooltip')
-
- // this is some dumb hack shit because sub pixels in firefox
- var top = Math.round(target.offset().top + (target[0].offsetHeight / 2) - (tooltip[0].offsetHeight / 2))
- var top2 = Math.round(tooltip.offset().top)
- var topDiff = top - top2
- ok(topDiff <= 1 && topDiff >= -1)
- target.bootstrapTooltip('hide')
- $('head #test').remove()
- })
-
- test('tooltip title test #1', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({})
- .bootstrapTooltip('show')
- equal($('.tooltip').children('.tooltip-inner').text(), 'Simple tooltip', 'title from title attribute is set')
- tooltip.bootstrapTooltip('hide')
- ok(!$('.tooltip').length, 'tooltip removed')
- })
-
- test('tooltip title test #2', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({
- title: 'This is a tooltip with some content'
- })
- .bootstrapTooltip('show')
- equal($('.tooltip').children('.tooltip-inner').text(), 'Simple tooltip', 'title is set from title attribute while prefered over title option')
- tooltip.bootstrapTooltip('hide')
- ok(!$('.tooltip').length, 'tooltip removed')
- })
-
- test('tooltip title test #3', function () {
- var tooltip = $('
')
- .appendTo('#qunit-fixture')
- .bootstrapTooltip({
- title: 'This is a tooltip with some content'
- })
- .bootstrapTooltip('show')
- equal($('.tooltip').children('.tooltip-inner').text(), 'This is a tooltip with some content', 'title from title option is set')
- tooltip.bootstrapTooltip('hide')
- ok(!$('.tooltip').length, 'tooltip removed')
- })
-
- test('tooltips should be placed dynamically, with the dynamic placement option', function () {
- $.support.transition = false
- var ttContainer = $('
').css({
- height: 400,
- overflow: 'hidden',
- position: 'absolute',
- top: 0,
- left: 0,
- width: 600
- })
- .appendTo('body')
-
- var topTooltip = $('
Top Dynamic Tooltip
')
- .appendTo('#dynamic-tt-test')
- .bootstrapTooltip({ placement: 'auto' })
- .bootstrapTooltip('show')
-
- ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned bottom')
-
- topTooltip.bootstrapTooltip('hide')
-
- var rightTooltip = $('
Right Dynamic Tooltip
')
- .appendTo('#dynamic-tt-test')
- .bootstrapTooltip({ placement: 'right auto' })
- .bootstrapTooltip('show')
-
- ok($('.tooltip').is('.left'), 'right positioned tooltip is dynamically positioned left')
- rightTooltip.bootstrapTooltip('hide')
-
- var leftTooltip = $('
Left Dynamic Tooltip
')
- .appendTo('#dynamic-tt-test')
- .bootstrapTooltip({ placement: 'auto left' })
- .bootstrapTooltip('show')
-
- ok($('.tooltip').is('.right'), 'left positioned tooltip is dynamically positioned right')
- leftTooltip.bootstrapTooltip('hide')
-
- ttContainer.remove()
- })
-
- test('should adjust the tip\'s top when up against the top of the viewport', function () {
- $('head').append('')
-
- var container = $('
').appendTo('body')
- var target = $('
')
- .appendTo(container)
- .bootstrapTooltip({ placement: 'right', viewport: { selector: 'body', padding: 12 }})
- .bootstrapTooltip('show')
- var tooltip = container.find('.tooltip')
-
- ok(Math.round(tooltip.offset().top) === 12)
- target.bootstrapTooltip('hide')
- $('head #test').remove()
- })
-
- test('should adjust the tip\'s top when up against the bottom of the viewport', function () {
- $('head').append('')
-
- var container = $('
').appendTo('body')
- var target = $('
')
- .appendTo(container)
- .bootstrapTooltip({ placement: 'right', viewport: { selector: 'body', padding: 12 }})
- .bootstrapTooltip('show')
- var tooltip = container.find('.tooltip')
-
- ok(Math.round(tooltip.offset().top) === Math.round($(window).height() - 12 - tooltip[0].offsetHeight))
- target.bootstrapTooltip('hide')
- $('head #test').remove()
- })
-
- test('should adjust the tip\'s left when up against the left of the viewport', function () {
- $('head').append('')
-
- var container = $('
').appendTo('body')
- var target = $('
')
- .appendTo(container)
- .bootstrapTooltip({ placement: 'bottom', viewport: { selector: 'body', padding: 12 }})
- .bootstrapTooltip('show')
- var tooltip = container.find('.tooltip')
-
- ok(Math.round(tooltip.offset().left) === 12)
- target.bootstrapTooltip('hide')
- $('head #test').remove()
- })
-
- test('should adjust the tip\'s left when up against the right of the viewport', function () {
- $('head').append('')
-
- var container = $('
').appendTo('body')
- var target = $('
')
- .appendTo(container)
- .bootstrapTooltip({ placement: 'bottom', viewport: { selector: 'body', padding: 12 }})
- .bootstrapTooltip('show')
- var tooltip = container.find('.tooltip')
-
- ok(Math.round(tooltip.offset().left) === Math.round($(window).width() - 12 - tooltip[0].offsetWidth))
- target.bootstrapTooltip('hide')
- $('head #test').remove()
- })
-
- test('should adjust the tip when up against the right of an arbitrary viewport', function () {
- $('head').append('')
- $('head').append('')
-
- var container = $('
', { 'class': 'container-viewport' }).appendTo('body')
- var target = $('
')
- .appendTo(container)
- .bootstrapTooltip({ placement: 'bottom', viewport: '.container-viewport' })
- .bootstrapTooltip('show')
- var tooltip = container.find('.tooltip')
-
- ok(Math.round(tooltip.offset().left) === Math.round(60 + container.width() - tooltip[0].offsetWidth))
- target.bootstrapTooltip('hide')
- $('head #test').remove()
- $('head #viewport-style').remove()
- })
-
- test('should not error when trying to show an auto-placed tooltip that has been removed from the dom', function () {
- var tooltip = $('
').appendTo('#qunit-fixture')
-
- tooltip
- .one('show.bs.tooltip', function () {
- tooltip.remove()
- })
- .bootstrapTooltip({ placement: 'auto' })
-
- var passed = true
- try {
- tooltip.bootstrapTooltip('show')
- }
- catch (err) {
- passed = false
- console.log(err)
- }
- ok(passed, '.tooltip(\'show\') should not throw an error in this case')
-
- try {
- tooltip.remove()
- }
- catch (err) {
- // tooltip may have already been removed
- }
- })
-})
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/vendor/jquery.min.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/vendor/jquery.min.js
deleted file mode 100644
index ab28a24729b..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/vendor/jquery.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
-!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="
",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d
b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;
-if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML=" a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,""],area:[1,""],param:[1,""],thead:[1,""],tr:[2,""],col:[2,""],td:[3,""],_default:k.htmlSerialize?[0,"",""]:[1,"X","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("")).appendTo(b.documentElement),b=(Cb[0].contentWindow||Cb[0].contentDocument).document,b.write(),b.close(),c=Eb(a,b),Cb.detach()),Db[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Gb=/^margin/,Hb=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ib,Jb,Kb=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ib=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Hb.test(g)&&Gb.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ib=function(a){return a.currentStyle},Jb=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ib(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Hb.test(g)&&!Kb.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Lb(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML=" a",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight)),b.innerHTML="",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Mb=/alpha\([^)]*\)/i,Nb=/opacity\s*=\s*([^)]*)/,Ob=/^(none|table(?!-c[ea]).+)/,Pb=new RegExp("^("+S+")(.*)$","i"),Qb=new RegExp("^([+-])=("+S+")","i"),Rb={position:"absolute",visibility:"hidden",display:"block"},Sb={letterSpacing:"0",fontWeight:"400"},Tb=["Webkit","O","Moz","ms"];function Ub(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Tb.length;while(e--)if(b=Tb[e]+c,b in a)return b;return d}function Vb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fb(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wb(a,b,c){var d=Pb.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Yb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ib(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Jb(a,b,f),(0>e||null==e)&&(e=a.style[b]),Hb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xb(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Jb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ub(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ub(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Jb(a,b,d)),"normal"===f&&b in Sb&&(f=Sb[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Ob.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Rb,function(){return Yb(a,b,d)}):Yb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ib(a);return Wb(a,c,d?Xb(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Nb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Mb,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Mb.test(f)?f.replace(Mb,e):f+" "+e)}}),m.cssHooks.marginRight=Lb(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Jb,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Gb.test(a)||(m.cssHooks[a+b].set=Wb)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ib(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Vb(this,!0)},hide:function(){return Vb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Zb(a,b,c,d,e){return new Zb.prototype.init(a,b,c,d,e)}m.Tween=Zb,Zb.prototype={constructor:Zb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")
-},cur:function(){var a=Zb.propHooks[this.prop];return a&&a.get?a.get(this):Zb.propHooks._default.get(this)},run:function(a){var b,c=Zb.propHooks[this.prop];return this.pos=b=this.options.duration?m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Zb.propHooks._default.set(this),this}},Zb.prototype.init.prototype=Zb.prototype,Zb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Zb.propHooks.scrollTop=Zb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Zb.prototype.init,m.fx.step={};var $b,_b,ac=/^(?:toggle|show|hide)$/,bc=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cc=/queueHooks$/,dc=[ic],ec={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bc.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bc.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fc(){return setTimeout(function(){$b=void 0}),$b=m.now()}function gc(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hc(a,b,c){for(var d,e=(ec[b]||[]).concat(ec["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ic(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fb(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fb(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ac.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fb(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hc(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jc(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kc(a,b,c){var d,e,f=0,g=dc.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$b||fc(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$b||fc(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jc(k,j.opts.specialEasing);g>f;f++)if(d=dc[f].call(j,a,k,j.opts))return d;return m.map(k,hc,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kc,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],ec[c]=ec[c]||[],ec[c].unshift(b)},prefilter:function(a,b){b?dc.unshift(a):dc.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kc(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cc.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gc(b,!0),a,d,e)}}),m.each({slideDown:gc("show"),slideUp:gc("hide"),slideToggle:gc("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($b=m.now();ca",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lc=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lc,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mc,nc,oc=m.expr.attrHandle,pc=/^(?:checked|selected)$/i,qc=k.getSetAttribute,rc=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nc:mc)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rc&&qc||!pc.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qc?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nc={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rc&&qc||!pc.test(c)?a.setAttribute(!qc&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=oc[b]||m.find.attr;oc[b]=rc&&qc||!pc.test(b)?function(a,b,d){var e,f;return d||(f=oc[b],oc[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,oc[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rc&&qc||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mc&&mc.set(a,b,c)}}),qc||(mc={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},oc.id=oc.name=oc.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mc.set},m.attrHooks.contenteditable={set:function(a,b,c){mc.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sc=/^(?:input|select|textarea|button|object)$/i,tc=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sc.test(a.nodeName)||tc.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var uc=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(uc," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(uc," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vc=m.now(),wc=/\?/,xc=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xc,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yc,zc,Ac=/#.*$/,Bc=/([?&])_=[^&]*/,Cc=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Dc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ec=/^(?:GET|HEAD)$/,Fc=/^\/\//,Gc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hc={},Ic={},Jc="*/".concat("*");try{zc=location.href}catch(Kc){zc=y.createElement("a"),zc.href="",zc=zc.href}yc=Gc.exec(zc.toLowerCase())||[];function Lc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mc(a,b,c,d){var e={},f=a===Ic;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nc(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Oc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zc,type:"GET",isLocal:Dc.test(yc[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nc(Nc(a,m.ajaxSettings),b):Nc(m.ajaxSettings,a)},ajaxPrefilter:Lc(Hc),ajaxTransport:Lc(Ic),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cc.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zc)+"").replace(Ac,"").replace(Fc,yc[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gc.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yc[1]&&c[2]===yc[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yc[3]||("http:"===yc[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mc(Hc,k,b,v),2===t)return v;h=k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Ec.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wc.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bc.test(e)?e.replace(Bc,"$1_="+vc++):e+(wc.test(e)?"&":"?")+"_="+vc++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jc+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mc(Ic,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Oc(k,v,c)),u=Pc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qc=/%20/g,Rc=/\[\]$/,Sc=/\r?\n/g,Tc=/^(?:submit|button|image|reset|file)$/i,Uc=/^(?:input|select|textarea|keygen)/i;function Vc(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rc.test(a)?d(a,e):Vc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vc(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vc(c,a[c],b,e);return d.join("&").replace(Qc,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Uc.test(this.nodeName)&&!Tc.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sc,"\r\n")}}):{name:b.name,value:c.replace(Sc,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zc()||$c()}:Zc;var Wc=0,Xc={},Yc=m.ajaxSettings.xhr();a.ActiveXObject&&m(a).on("unload",function(){for(var a in Xc)Xc[a](void 0,!0)}),k.cors=!!Yc&&"withCredentials"in Yc,Yc=k.ajax=!!Yc,Yc&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xc[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xc[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zc(){try{return new a.XMLHttpRequest}catch(b){}}function $c(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _c=[],ad=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_c.pop()||m.expando+"_"+vc++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ad.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ad.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ad,"$1"+e):b.jsonp!==!1&&(b.url+=(wc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_c.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bd=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bd)return bd.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cd=a.document.documentElement;function dd(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dd(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cd;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cd})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dd(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=Lb(k.pixelPosition,function(a,c){return c?(c=Jb(a,b),Hb.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ed=a.jQuery,fd=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fd),b&&a.jQuery===m&&(a.jQuery=ed),m},typeof b===K&&(a.jQuery=a.$=m),m});
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/vendor/qunit.js b/doc/_themes/odoodoc/static/bootstrap/js/tests/vendor/qunit.js
deleted file mode 100644
index 0e279fde170..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/vendor/qunit.js
+++ /dev/null
@@ -1,2288 +0,0 @@
-/*!
- * QUnit 1.14.0
- * http://qunitjs.com/
- *
- * Copyright 2013 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2014-01-31T16:40Z
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- setTimeout = window.setTimeout,
- clearTimeout = window.clearTimeout,
- defined = {
- document: typeof window.document !== "undefined",
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "
" + escapeText( testName ) + "";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "
" + escapeText( config.currentModule ) + ": " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// We use the prototype to distinguish between properties that should
-// be exposed as globals (and in exports) and those that shouldn't
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // by default, scroll to top of the page when suite is done
- scrolltop: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i, current,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {};
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
-
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- if ( urlParams[ current[ 0 ] ] ) {
- urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
- } else {
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = [];
- if ( urlParams.testNumber ) {
-
- // Ensure that urlParams.testNumber is an array
- urlParams.testNumber = [].concat( urlParams.testNumber );
- for ( i = 0; i < urlParams.testNumber.length; i++ ) {
- current = urlParams.testNumber[ i ];
- config.testNumber.push( parseInt( current, 10 ) );
- }
- }
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-extend( QUnit, {
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "" +
- "
" +
- "
" +
- "
" +
- "
";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...
";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- /*
- DEPRECATED: Use multiple tests instead of resetting inside a test.
- Use testStart or testDone for custom cleanup.
- This method will throw an error in 2.0, and will be removed in 2.1
- */
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- }
-
- // Consider: typeof null === object
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "
" + message + "";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "
Expected: | " + expected + " |
";
-
- if ( actual !== expected ) {
- output += "Result: | " + actual + " |
";
- output += "Diff: | " + QUnit.diff( expected, actual ) + " |
";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "
" + message + "";
- output = message;
-
- output += "
";
-
- if ( actual ) {
- output += "Result: | " + escapeText( actual ) + " |
";
- }
-
- if ( source ) {
- details.source = source;
- output += "Source: | " + escapeText( source ) + " |
";
- }
-
- output += "
";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( hasOwn.call( params, key ) ) {
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent,
- addClass: addClass,
- hasClass: hasClass,
- removeClass: removeClass
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, runtime }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( !defined.document || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
- urlConfigContainer, moduleFilter, userAgent,
- numModules = 0,
- moduleNames = [],
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- if ( !val.value || typeof val.value === "string" ) {
- urlConfigHtml += "
";
- } else {
- urlConfigHtml += "
";
- }
- }
- for ( i in config.modules ) {
- if ( config.modules.hasOwnProperty( i ) ) {
- moduleNames.push(i);
- }
- }
- numModules = moduleNames.length;
- moduleNames.sort( function( a, b ) {
- return a.localeCompare( b );
- });
- moduleFilterHtml += "
";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "
" + banner.innerHTML + " ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = id( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = id( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigContainer = document.createElement("span");
- urlConfigContainer.innerHTML = urlConfigHtml;
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change" for checkboxes
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ?
- target.defaultValue || true :
- undefined;
- window.location = QUnit.url( params );
- });
- addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( "span" );
- moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url({
- module: ( selectedModule === "" ) ? undefined : selectedModule,
- // Remove any existing filters
- filter: undefined,
- testNumber: undefined
- });
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-if ( defined.document ) {
- addEvent( window, "load", QUnit.load );
-}
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will suppress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not suppressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- delete config.previousModule;
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.
",
- "
",
- passed,
- " assertions of
",
- config.stats.all,
- " passed,
",
- config.stats.bad,
- " failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && defined.document && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( config.scrolltop && window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = ( test.module + ": " + test.testName ).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber.length > 0 ) {
- if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
- return false;
- }
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case "'":
- return "'";
- case "\"":
- return """;
- case "<":
- return "<";
- case ">":
- return ">";
- case "&":
- return "&";
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- if ( hasOwn.call( window, key ) ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( hasOwn.call( b, prop ) ) {
- // Avoid "Member not found" error in IE8 caused by messing with window.constructor
- if ( !( prop === "constructor" && a === window ) ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
- } else {
- a[ prop ] = b[ prop ];
- }
- }
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- if ( elem.addEventListener ) {
-
- // Standards-based browsers
- elem.addEventListener( type, fn, false );
- } else if ( elem.attachEvent ) {
-
- // support: IE <9
- elem.attachEvent( "on" + type, fn );
- } else {
-
- // Caller must ensure support for event listeners is present
- throw new Error( "addEvent() was called in a context without event listener support" );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not necessarily
- elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
-}
-
-function id( name ) {
- return defined.document && document.getElementById && document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if (
- // Emit moduleStart when we're switching from one module to another
- this.module !== config.previousModule ||
- // They could be equal (both undefined) but if the previousModule property doesn't
- // yet exist it means this is the first test in a suite that isn't wrapped in a
- // module, in which case we'll just emit a moduleStart event for 'undefined'.
- // Without this, reporters can get testStart before moduleStart which is a problem.
- !hasOwn.call( config, "previousModule" )
- ) {
- if ( hasOwn.call( config, "previousModule" ) ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- /*jshint camelcase:false */
-
-
- /**
- * Expose the current test environment.
- *
- * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
- */
- QUnit.current_testEnvironment = this.testEnvironment;
-
- /*jshint camelcase:true */
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running:
" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + "
(" + bad + ", " + good + ", " + this.assertions.length + ")";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- runtime: this.runtime,
- // DEPRECATED: this property will be removed in 2.0.0, use runtime instead
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Assert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-assert = QUnit.assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
- msg = msg || ( result ? "okay" : "failed" );
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = "
" + escapeText( msg ) + "";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "
Source: | " +
- escapeText( source ) +
- " |
---|
";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( !message && typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
-
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
-
- // expected is an Error object
- } else if ( expected instanceof Error ) {
- ok = actual instanceof Error &&
- actual.name === expected.name &&
- actual.message === expected.message;
-
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
-
- // expected is a string
- } else if ( QUnit.objectType( expected ) === "string" ) {
- ok = expected === errorString( actual );
-
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
-
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, "No exception was thrown." );
- }
- }
-};
-
-/**
- * @deprecated since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit.constructor.prototype, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.raises = function() {
- QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" );
-};
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.constructor.prototype.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
- parentsB = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- /*jshint camelcase:false */
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotation VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifiers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop, aCircular, bCircular;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- parentsB.push( b );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- aCircular = parents[j] === a[i];
- bCircular = parentsB[j] === b[i];
- if ( aCircular || bCircular ) {
- if ( a[i] === b[i] || aCircular && bCircular ) {
- loop = true;
- } else {
- parents.pop();
- parentsB.pop();
- return false;
- }
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- parentsB.pop();
- return false;
- }
- }
- parents.pop();
- parentsB.pop();
- return true;
- },
-
- "object": function( b, a ) {
- /*jshint forin:false */
- var i, j, loop, aCircular, bCircular,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
-
- // track reference to avoid circular references
- parents.push( a );
- parentsB.push( b );
-
- // be strict: don't ensure hasOwnProperty and go deep
- for ( i in a ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- aCircular = parents[j] === a[i];
- bCircular = parentsB[j] === b[i];
- if ( aCircular || bCircular ) {
- if ( a[i] === b[i] || aCircular && bCircular ) {
- loop = true;
- } else {
- eq = false;
- break;
- }
- }
- }
- aProperties.push(i);
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- eq = false;
- break;
- }
- }
-
- parents.pop();
- parentsB.pop();
- callers.pop(); // unstack, we are done
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "
" : "\n" : this.HTML ? " " : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, " " );
- }
- return new Array( this.depth + ( extra || 0 ) ).join(chr);
- },
- up: function( a ) {
- this.depth += a || 1;
- },
- down: function( a ) {
- this.depth -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- depth: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- /*jshint forin:false */
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "<" : "<",
- close = QUnit.jsDump.HTML ? ">" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( hasOwn.call( ns, i ) ) {
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "" + out.o[i] + oSpace[i] + "";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "" + out.o[n] + oSpace[n] + "";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "" + out.n[i] + nSpace[i] + "";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "" + out.o[n] + oSpace[n] + "";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// For browser, export only select globals
-if ( typeof window !== "undefined" ) {
- extend( window, QUnit.constructor.prototype );
- window.QUnit = QUnit;
-}
-
-// For CommonJS environments, export everything
-if ( typeof module !== "undefined" && module.exports ) {
- module.exports = QUnit;
-}
-
-
-// Get a reference to the global object, like window in browsers
-}( (function() {
- return this;
-})() ));
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/affix.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/affix.html
deleted file mode 100644
index 5e677eb5755..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/affix.html
+++ /dev/null
@@ -1,238 +0,0 @@
-
-
-
- Affix
-
-
-
-
-
-
-
-
-
-
-
-
- - Cras justo odio
- - Dapibus ac facilisis in
- - Morbi leo risus
- - Porta ac consectetur ac
- - Vestibulum at eros
- - Cras justo odio
- - Dapibus ac facilisis in
- - Morbi leo risus
- - Porta ac consectetur ac
- - Vestibulum at eros
- - Cras justo odio
- - Dapibus ac facilisis in
- - Morbi leo risus
- - Porta ac consectetur ac
- - Vestibulum at eros
- - Porta ac consectetur ac
-
-
-
-
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.
-
-
Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.
-
-
Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.
-
-
Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/alert.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/alert.html
deleted file mode 100644
index 688e6362cc3..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/alert.html
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
- Alert
-
-
-
-
-
-
-
-
-
-
- Holy guacamole! Best check yo self, you're not looking too good.
-
-
-
-
-
Oh snap! You got an error!
-
Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/button.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/button.html
deleted file mode 100644
index 01c7dd4b341..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/button.html
+++ /dev/null
@@ -1,64 +0,0 @@
-
-
-
- Button
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/carousel.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/carousel.html
deleted file mode 100644
index aaf48b05988..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/carousel.html
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
- Carousel
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/collapse.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/collapse.html
deleted file mode 100644
index 792ba796dd4..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/collapse.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
- Collapse
-
-
-
-
-
-
-
-
-
-
-
-
-
- Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
-
-
-
-
-
-
-
- Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
-
-
-
-
-
-
-
- Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/dropdown.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/dropdown.html
deleted file mode 100644
index 9b275c96d42..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/dropdown.html
+++ /dev/null
@@ -1,97 +0,0 @@
-
-
-
- Dropdown
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/modal.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/modal.html
deleted file mode 100644
index f4f61f47fce..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/modal.html
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
-
- Modal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Text in a modal
-
Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
-
-
Popover in a modal
-
This button should trigger a popover on click.
-
-
Tooltips in a modal
-
This link and that link should have tooltips on hover.
-
-
-
-
Overflowing text to show scroll behavior
-
Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.
-
Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.
-
Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.
-
Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.
-
Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
-
Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.
-
Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/popover.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/popover.html
deleted file mode 100644
index c09739ff905..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/popover.html
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
- Popover
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/scrollspy.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/scrollspy.html
deleted file mode 100644
index 9d581e33168..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/scrollspy.html
+++ /dev/null
@@ -1,98 +0,0 @@
-
-
-
- Scrollspy
-
-
-
-
-
-
-
-
-
-
@fat
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
-
@mdo
-
Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard. Freegan beard aliqua cupidatat mcsweeney's vero. Cupidatat four loko nisi, ea helvetica nulla carles. Tattooed cosby sweater food truck, mcsweeney's quis non freegan vinyl. Lo-fi wes anderson +1 sartorial. Carles non aesthetic exercitation quis gentrify. Brooklyn adipisicing craft beer vice keytar deserunt.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
-
one
-
Occaecat commodo aliqua delectus. Fap craft beer deserunt skateboard ea. Lomo bicycle rights adipisicing banh mi, velit ea sunt next level locavore single-origin coffee in magna veniam. High life id vinyl, echo park consequat quis aliquip banh mi pitchfork. Vero VHS est adipisicing. Consectetur nisi DIY minim messenger bag. Cred ex in, sustainable delectus consectetur fanny pack iphone.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
-
two
-
In incididunt echo park, officia deserunt mcsweeney's proident master cleanse thundercats sapiente veniam. Excepteur VHS elit, proident shoreditch +1 biodiesel laborum craft beer. Single-origin coffee wayfarers irure four loko, cupidatat terry richardson master cleanse. Assumenda you probably haven't heard of them art party fanny pack, tattooed nulla cardigan tempor ad. Proident wolf nesciunt sartorial keffiyeh eu banh mi sustainable. Elit wolf voluptate, lo-fi ea portland before they sold out four loko. Locavore enim nostrud mlkshk brooklyn nesciunt.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
-
three
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Keytar twee blog, culpa messenger bag marfa whatever delectus food truck. Sapiente synth id assumenda. Locavore sed helvetica cliche irony, thundercats you probably haven't heard of them consequat hoodie gluten-free lo-fi fap aliquip. Labore elit placeat before they sold out, terry richardson proident brunch nesciunt quis cosby sweater pariatur keffiyeh ut helvetica artisan. Cardigan craft beer seitan readymade velit. VHS chambray laboris tempor veniam. Anim mollit minim commodo ullamco thundercats.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/tab.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/tab.html
deleted file mode 100644
index 37921afecb4..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/tab.html
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
- Tab
-
-
-
-
-
-
-
-
-
-
-
-
-
Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.
-
Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.
-
-
-
Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.
-
Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.
-
-
-
Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.
-
Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.
-
-
-
Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.
-
Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/tooltip.html b/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/tooltip.html
deleted file mode 100644
index aaf4b767dac..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tests/visual/tooltip.html
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
- Tooltip
-
-
-
-
-
-
-
-
-
Tight pants next level keffiyeh you probably haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel have a terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan whatever keytar, scenester farm-to-table banksy Austin twitter handle freegan cred raw denim single-origin coffee viral.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/tooltip.js b/doc/_themes/odoodoc/static/bootstrap/js/tooltip.js
deleted file mode 100644
index 9cdb6c9e4de..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/tooltip.js
+++ /dev/null
@@ -1,457 +0,0 @@
-/* ========================================================================
- * Bootstrap: tooltip.js v3.2.0
- * http://getbootstrap.com/javascript/#tooltip
- * Inspired by the original jQuery.tipsy by Jason Frame
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- * ======================================================================== */
-
-
-+function ($) {
- 'use strict';
-
- // TOOLTIP PUBLIC CLASS DEFINITION
- // ===============================
-
- var Tooltip = function (element, options) {
- this.type =
- this.options =
- this.enabled =
- this.timeout =
- this.hoverState =
- this.$element = null
-
- this.init('tooltip', element, options)
- }
-
- Tooltip.VERSION = '3.2.0'
-
- Tooltip.DEFAULTS = {
- animation: true,
- placement: 'top',
- selector: false,
- template: '',
- trigger: 'hover focus',
- title: '',
- delay: 0,
- html: false,
- container: false,
- viewport: {
- selector: 'body',
- padding: 0
- }
- }
-
- Tooltip.prototype.init = function (type, element, options) {
- this.enabled = true
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
- this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
-
- var triggers = this.options.trigger.split(' ')
-
- for (var i = triggers.length; i--;) {
- var trigger = triggers[i]
-
- if (trigger == 'click') {
- this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
- } else if (trigger != 'manual') {
- var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
- var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
-
- this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
- this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
- }
- }
-
- this.options.selector ?
- (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
- this.fixTitle()
- }
-
- Tooltip.prototype.getDefaults = function () {
- return Tooltip.DEFAULTS
- }
-
- Tooltip.prototype.getOptions = function (options) {
- options = $.extend({}, this.getDefaults(), this.$element.data(), options)
-
- if (options.delay && typeof options.delay == 'number') {
- options.delay = {
- show: options.delay,
- hide: options.delay
- }
- }
-
- return options
- }
-
- Tooltip.prototype.getDelegateOptions = function () {
- var options = {}
- var defaults = this.getDefaults()
-
- this._options && $.each(this._options, function (key, value) {
- if (defaults[key] != value) options[key] = value
- })
-
- return options
- }
-
- Tooltip.prototype.enter = function (obj) {
- var self = obj instanceof this.constructor ?
- obj : $(obj.currentTarget).data('bs.' + this.type)
-
- if (!self) {
- self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
- $(obj.currentTarget).data('bs.' + this.type, self)
- }
-
- clearTimeout(self.timeout)
-
- self.hoverState = 'in'
-
- if (!self.options.delay || !self.options.delay.show) return self.show()
-
- self.timeout = setTimeout(function () {
- if (self.hoverState == 'in') self.show()
- }, self.options.delay.show)
- }
-
- Tooltip.prototype.leave = function (obj) {
- var self = obj instanceof this.constructor ?
- obj : $(obj.currentTarget).data('bs.' + this.type)
-
- if (!self) {
- self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
- $(obj.currentTarget).data('bs.' + this.type, self)
- }
-
- clearTimeout(self.timeout)
-
- self.hoverState = 'out'
-
- if (!self.options.delay || !self.options.delay.hide) return self.hide()
-
- self.timeout = setTimeout(function () {
- if (self.hoverState == 'out') self.hide()
- }, self.options.delay.hide)
- }
-
- Tooltip.prototype.show = function () {
- var e = $.Event('show.bs.' + this.type)
-
- if (this.hasContent() && this.enabled) {
- this.$element.trigger(e)
-
- var inDom = $.contains(document.documentElement, this.$element[0])
- if (e.isDefaultPrevented() || !inDom) return
- var that = this
-
- var $tip = this.tip()
-
- var tipId = this.getUID(this.type)
-
- this.setContent()
- $tip.attr('id', tipId)
- this.$element.attr('aria-describedby', tipId)
-
- if (this.options.animation) $tip.addClass('fade')
-
- var placement = typeof this.options.placement == 'function' ?
- this.options.placement.call(this, $tip[0], this.$element[0]) :
- this.options.placement
-
- var autoToken = /\s?auto?\s?/i
- var autoPlace = autoToken.test(placement)
- if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
-
- $tip
- .detach()
- .css({ top: 0, left: 0, display: 'block' })
- .addClass(placement)
- .data('bs.' + this.type, this)
-
- this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
-
- var pos = this.getPosition()
- var actualWidth = $tip[0].offsetWidth
- var actualHeight = $tip[0].offsetHeight
-
- if (autoPlace) {
- var orgPlacement = placement
- var $parent = this.$element.parent()
- var parentDim = this.getPosition($parent)
-
- placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
- placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
- placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
- placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
- placement
-
- $tip
- .removeClass(orgPlacement)
- .addClass(placement)
- }
-
- var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
-
- this.applyPlacement(calculatedOffset, placement)
-
- var complete = function () {
- that.$element.trigger('shown.bs.' + that.type)
- that.hoverState = null
- }
-
- $.support.transition && this.$tip.hasClass('fade') ?
- $tip
- .one('bsTransitionEnd', complete)
- .emulateTransitionEnd(150) :
- complete()
- }
- }
-
- Tooltip.prototype.applyPlacement = function (offset, placement) {
- var $tip = this.tip()
- var width = $tip[0].offsetWidth
- var height = $tip[0].offsetHeight
-
- // manually read margins because getBoundingClientRect includes difference
- var marginTop = parseInt($tip.css('margin-top'), 10)
- var marginLeft = parseInt($tip.css('margin-left'), 10)
-
- // we must check for NaN for ie 8/9
- if (isNaN(marginTop)) marginTop = 0
- if (isNaN(marginLeft)) marginLeft = 0
-
- offset.top = offset.top + marginTop
- offset.left = offset.left + marginLeft
-
- // $.fn.offset doesn't round pixel values
- // so we use setOffset directly with our own function B-0
- $.offset.setOffset($tip[0], $.extend({
- using: function (props) {
- $tip.css({
- top: Math.round(props.top),
- left: Math.round(props.left)
- })
- }
- }, offset), 0)
-
- $tip.addClass('in')
-
- // check to see if placing tip in new offset caused the tip to resize itself
- var actualWidth = $tip[0].offsetWidth
- var actualHeight = $tip[0].offsetHeight
-
- if (placement == 'top' && actualHeight != height) {
- offset.top = offset.top + height - actualHeight
- }
-
- var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
-
- if (delta.left) offset.left += delta.left
- else offset.top += delta.top
-
- var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
- var arrowPosition = delta.left ? 'left' : 'top'
- var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
-
- $tip.offset(offset)
- this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
- }
-
- Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
- this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
- }
-
- Tooltip.prototype.setContent = function () {
- var $tip = this.tip()
- var title = this.getTitle()
-
- $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
- $tip.removeClass('fade in top bottom left right')
- }
-
- Tooltip.prototype.hide = function () {
- var that = this
- var $tip = this.tip()
- var e = $.Event('hide.bs.' + this.type)
-
- this.$element.removeAttr('aria-describedby')
-
- function complete() {
- if (that.hoverState != 'in') $tip.detach()
- that.$element.trigger('hidden.bs.' + that.type)
- }
-
- this.$element.trigger(e)
-
- if (e.isDefaultPrevented()) return
-
- $tip.removeClass('in')
-
- $.support.transition && this.$tip.hasClass('fade') ?
- $tip
- .one('bsTransitionEnd', complete)
- .emulateTransitionEnd(150) :
- complete()
-
- this.hoverState = null
-
- return this
- }
-
- Tooltip.prototype.fixTitle = function () {
- var $e = this.$element
- if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {
- $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
- }
- }
-
- Tooltip.prototype.hasContent = function () {
- return this.getTitle()
- }
-
- Tooltip.prototype.getPosition = function ($element) {
- $element = $element || this.$element
- var el = $element[0]
- var isBody = el.tagName == 'BODY'
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
- scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
- width: isBody ? $(window).width() : $element.outerWidth(),
- height: isBody ? $(window).height() : $element.outerHeight()
- }, isBody ? { top: 0, left: 0 } : $element.offset())
- }
-
- Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
- return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
- placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
- placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
- /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
-
- }
-
- Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
- var delta = { top: 0, left: 0 }
- if (!this.$viewport) return delta
-
- var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
- var viewportDimensions = this.getPosition(this.$viewport)
-
- if (/right|left/.test(placement)) {
- var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
- var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
- if (topEdgeOffset < viewportDimensions.top) { // top overflow
- delta.top = viewportDimensions.top - topEdgeOffset
- } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
- delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
- }
- } else {
- var leftEdgeOffset = pos.left - viewportPadding
- var rightEdgeOffset = pos.left + viewportPadding + actualWidth
- if (leftEdgeOffset < viewportDimensions.left) { // left overflow
- delta.left = viewportDimensions.left - leftEdgeOffset
- } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
- delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
- }
- }
-
- return delta
- }
-
- Tooltip.prototype.getTitle = function () {
- var title
- var $e = this.$element
- var o = this.options
-
- title = $e.attr('data-original-title')
- || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
-
- return title
- }
-
- Tooltip.prototype.getUID = function (prefix) {
- do prefix += ~~(Math.random() * 1000000)
- while (document.getElementById(prefix))
- return prefix
- }
-
- Tooltip.prototype.tip = function () {
- return (this.$tip = this.$tip || $(this.options.template))
- }
-
- Tooltip.prototype.arrow = function () {
- return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
- }
-
- Tooltip.prototype.validate = function () {
- if (!this.$element[0].parentNode) {
- this.hide()
- this.$element = null
- this.options = null
- }
- }
-
- Tooltip.prototype.enable = function () {
- this.enabled = true
- }
-
- Tooltip.prototype.disable = function () {
- this.enabled = false
- }
-
- Tooltip.prototype.toggleEnabled = function () {
- this.enabled = !this.enabled
- }
-
- Tooltip.prototype.toggle = function (e) {
- var self = this
- if (e) {
- self = $(e.currentTarget).data('bs.' + this.type)
- if (!self) {
- self = new this.constructor(e.currentTarget, this.getDelegateOptions())
- $(e.currentTarget).data('bs.' + this.type, self)
- }
- }
-
- self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
- }
-
- Tooltip.prototype.destroy = function () {
- clearTimeout(this.timeout)
- this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
- }
-
-
- // TOOLTIP PLUGIN DEFINITION
- // =========================
-
- function Plugin(option) {
- return this.each(function () {
- var $this = $(this)
- var data = $this.data('bs.tooltip')
- var options = typeof option == 'object' && option
-
- if (!data && option == 'destroy') return
- if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
- if (typeof option == 'string') data[option]()
- })
- }
-
- var old = $.fn.tooltip
-
- $.fn.tooltip = Plugin
- $.fn.tooltip.Constructor = Tooltip
-
-
- // TOOLTIP NO CONFLICT
- // ===================
-
- $.fn.tooltip.noConflict = function () {
- $.fn.tooltip = old
- return this
- }
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/js/transition.js b/doc/_themes/odoodoc/static/bootstrap/js/transition.js
deleted file mode 100644
index 83f85bf45f9..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/js/transition.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ========================================================================
- * Bootstrap: transition.js v3.2.0
- * http://getbootstrap.com/javascript/#transitions
- * ========================================================================
- * Copyright 2011-2014 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/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'
- }
-
- for (var name in transEndEventNames) {
- if (el.style[name] !== undefined) {
- return { end: transEndEventNames[name] }
- }
- }
-
- return false // explicit for ie8 ( ._.)
- }
-
- // http://blog.alexmaccaw.com/css-transitions
- $.fn.emulateTransitionEnd = function (duration) {
- var called = false
- var $el = this
- $(this).one('bsTransitionEnd', function () { called = true })
- var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
- setTimeout(callback, duration)
- return this
- }
-
- $(function () {
- $.support.transition = transitionEnd()
-
- if (!$.support.transition) return
-
- $.event.special.bsTransitionEnd = {
- bindType: $.support.transition.end,
- delegateType: $.support.transition.end,
- handle: function (e) {
- if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
- }
- }
- })
-
-}(jQuery);
diff --git a/doc/_themes/odoodoc/static/bootstrap/less/bootstrap.less b/doc/_themes/odoodoc/static/bootstrap/less/bootstrap.less
deleted file mode 100644
index 4d6f8aacfdc..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/less/bootstrap.less
+++ /dev/null
@@ -1,50 +0,0 @@
-// Core variables and mixins
-@import "variables";
-@import "mixins";
-
-// Reset and dependencies
-@import "normalize";
-@import "print";
-@import "glyphicons";
-
-// Core CSS
-@import "scaffolding";
-@import "type";
-@import "code";
-@import "grid";
-@import "tables";
-@import "forms";
-@import "buttons";
-
-// Components
-@import "component-animations";
-@import "dropdowns";
-@import "button-groups";
-@import "input-groups";
-@import "navs";
-@import "navbar";
-@import "breadcrumbs";
-@import "pagination";
-@import "pager";
-@import "labels";
-@import "badges";
-@import "jumbotron";
-@import "thumbnails";
-@import "alerts";
-@import "progress-bars";
-@import "media";
-@import "list-group";
-@import "panels";
-@import "responsive-embed";
-@import "wells";
-@import "close";
-
-// Components w/ JavaScript
-@import "modals";
-@import "tooltip";
-@import "popovers";
-@import "carousel";
-
-// Utility classes
-@import "utilities";
-@import "responsive-utilities";
diff --git a/doc/_themes/odoodoc/static/bootstrap/less/media.less b/doc/_themes/odoodoc/static/bootstrap/less/media.less
deleted file mode 100644
index 5ad22cd6d54..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/less/media.less
+++ /dev/null
@@ -1,56 +0,0 @@
-// Media objects
-// Source: http://stubbornella.org/content/?p=497
-// --------------------------------------------------
-
-
-// Common styles
-// -------------------------
-
-// Clear the floats
-.media,
-.media-body {
- overflow: hidden;
- zoom: 1;
-}
-
-// Proper spacing between instances of .media
-.media,
-.media .media {
- margin-top: 15px;
-}
-.media:first-child {
- margin-top: 0;
-}
-
-// For images and videos, set to block
-.media-object {
- display: block;
-}
-
-// Reset margins on headings for tighter default spacing
-.media-heading {
- margin: 0 0 5px;
-}
-
-
-// Media image alignment
-// -------------------------
-
-.media {
- > .pull-left {
- margin-right: 10px;
- }
- > .pull-right {
- margin-left: 10px;
- }
-}
-
-
-// Media list variation
-// -------------------------
-
-// Undo default ul/ol styles
-.media-list {
- padding-left: 0;
- list-style: none;
-}
diff --git a/doc/_themes/odoodoc/static/bootstrap/less/mixins.less b/doc/_themes/odoodoc/static/bootstrap/less/mixins.less
deleted file mode 100644
index b565f013a40..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/less/mixins.less
+++ /dev/null
@@ -1,39 +0,0 @@
-// Mixins
-// --------------------------------------------------
-
-// Utilities
-@import "mixins/hide-text";
-@import "mixins/opacity";
-@import "mixins/image";
-@import "mixins/labels";
-@import "mixins/reset-filter";
-@import "mixins/resize";
-@import "mixins/responsive-visibility";
-@import "mixins/size";
-@import "mixins/tab-focus";
-@import "mixins/text-emphasis";
-@import "mixins/text-overflow";
-@import "mixins/vendor-prefixes";
-
-// Components
-@import "mixins/alerts";
-@import "mixins/buttons";
-@import "mixins/panels";
-@import "mixins/pagination";
-@import "mixins/list-group";
-@import "mixins/nav-divider";
-@import "mixins/forms";
-@import "mixins/progress-bar";
-@import "mixins/table-row";
-
-// Skins
-@import "mixins/background-variant";
-@import "mixins/border-radius";
-@import "mixins/gradients";
-
-// Layout
-@import "mixins/clearfix";
-@import "mixins/center-block";
-@import "mixins/nav-vertical-align";
-@import "mixins/grid-framework";
-@import "mixins/grid";
diff --git a/doc/_themes/odoodoc/static/bootstrap/less/print.less b/doc/_themes/odoodoc/static/bootstrap/less/print.less
deleted file mode 100644
index 3655d03953a..00000000000
--- a/doc/_themes/odoodoc/static/bootstrap/less/print.less
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-// Basic print styles
-// --------------------------------------------------
-// Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css
-
-@media print {
-
- * {
- text-shadow: none !important;
- color: #000 !important; // Black prints faster: h5bp.com/s
- background: transparent !important;
- box-shadow: none !important;
- }
-
- a,
- a:visited {
- text-decoration: underline;
- }
-
- a[href]:after {
- content: " (" attr(href) ")";
- }
-
- abbr[title]:after {
- content: " (" attr(title) ")";
- }
-
- // Don't show links for images, or javascript/internal links
- a[href^="javascript:"]:after,
- a[href^="#"]:after {
- content: "";
- }
-
- pre,
- blockquote {
- border: 1px solid #999;
- page-break-inside: avoid;
- }
-
- thead {
- display: table-header-group; // h5bp.com/t
- }
-
- tr,
- img {
- page-break-inside: avoid;
- }
-
- img {
- max-width: 100% !important;
- }
-
- p,
- h2,
- h3 {
- orphans: 3;
- widows: 3;
- }
-
- h2,
- h3 {
- page-break-after: avoid;
- }
-
- // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245
- // Once fixed, we can just straight up remove this.
- select {
- background: #fff !important;
- }
-
- // Bootstrap components
- .navbar {
- display: none;
- }
- .table {
- td,
- th {
- background-color: #fff !important;
- }
- }
- .btn,
- .dropup > .btn {
- > .caret {
- border-top-color: #000 !important;
- }
- }
- .label {
- border: 1px solid #000;
- }
-
- .table {
- border-collapse: collapse !important;
- }
- .table-bordered {
- th,
- td {
- border: 1px solid #ddd !important;
- }
- }
-
-}
diff --git a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.eot b/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.eot
deleted file mode 100644
index 4a4ca865d67..00000000000
Binary files a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.eot and /dev/null differ
diff --git a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.svg b/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.svg
deleted file mode 100644
index e3e2dc739dd..00000000000
--- a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.svg
+++ /dev/null
@@ -1,229 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.ttf b/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.ttf
deleted file mode 100644
index 67fa00bf838..00000000000
Binary files a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.ttf and /dev/null differ
diff --git a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.woff b/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.woff
deleted file mode 100644
index 8c54182aa5d..00000000000
Binary files a/doc/_themes/odoodoc/static/fonts/glyphicons-halflings-regular.woff and /dev/null differ
diff --git a/doc/_themes/odoodoc/static/github-link.png b/doc/_themes/odoodoc/static/github-link.png
deleted file mode 100644
index f0a638362db..00000000000
Binary files a/doc/_themes/odoodoc/static/github-link.png and /dev/null differ
diff --git a/doc/_themes/odoodoc/static/odoodoc.css_t b/doc/_themes/odoodoc/static/odoodoc.css_t
deleted file mode 100644
index 64a14dc61e4..00000000000
--- a/doc/_themes/odoodoc/static/odoodoc.css_t
+++ /dev/null
@@ -1 +0,0 @@
-@import url("style.css");
diff --git a/doc/_themes/odoodoc/static/style.less b/doc/_themes/odoodoc/static/style.less
deleted file mode 100644
index 9d693d5624a..00000000000
--- a/doc/_themes/odoodoc/static/style.less
+++ /dev/null
@@ -1,850 +0,0 @@
-@import "bootstrap/less/bootstrap";
-@import url(https://fonts.googleapis.com/css?family=Lato);
-
-@icon-font-path: 'fonts/';
-@brand-primary: #a24689;
-@brand-dark: darken(@brand-primary, 6%);
-@brand-light: lighten(@brand-primary, 10%);
-@brand-text: saturate(lighten(@brand-primary, 46%), 5%);
-
-@headings-font-family: Lato, Arial, sans-serif;
-
-@navbar-margin-bottom: 0;
-
-@navbar-default-bg: white;
-@navbar-default-border: 0;
-
-// indent level for various items list e.g. dl, fields lists, ...
-@item-indent: 30px;
-
-* {
- box-sizing: border-box;
-}
-body {
- overflow: auto;
- position: relative;
-}
-
-.document-super:not(.stripe) {
- .container();
-}
-.document-super.stripe {
- .container-fluid();
-}
-
-.document {
- .make-row();
-}
-
-.documentwrapper {
- .make-md-column(12);
-}
-.with-sidebar .documentwrapper {
- .make-md-column(9);
-}
-.sphinxsidebar {
- .make-md-column(3);
-}
-
-.btn-outline {
- color: @brand-primary;
- background-color: transparent;
- border-color: @brand-primary;
- &:hover, &:focus, &:active {
- color: #fff;
- background-color: @brand-primary;
- border-color: @brand-primary;
- }
-}
-
-
-.btn-outline-inverse {
- color: #fff;
- background-color: transparent;
- border-color: @brand-text;
- &:hover, &:focus, &:active {
- color: @brand-primary;
- text-shadow: none;
- background-color: #fff;
- border-color: #fff;
- }
-}
-/*
- * Main navigation
- */
-.docs-nav {
- .navbar-brand,
- .navbar-nav > li > a {
- position: relative;
- }
-
- .navbar-nav > li {
- > a:hover:before, &.current a:before {
- bottom: 10px;
- opacity: 1;
- }
- > a:before {
- display: block;
- position: absolute;
- bottom: 0;
- left: 10px;
- content: "";
- right: 10px;
- height: 3px;
- background: @brand-primary;
- opacity: 0;
- .transition(all 0.3s ease-out);
- }
- &.dropdown {
- > a:after {
- content: " ";
- display: inline-block;
- width: 0;
- height: 0;
- margin-left: 5px;
- vertical-align: middle;
- border-top: 4px solid @gray-light;
- border-right: 4px solid transparent;
- border-left: 4px solid transparent;
- }
- .dropdown-menu > li.current > a.current {
- background-color: @brand-primary;
- color: white;
- }
- }
- }
- /* version switcher */
- div.versions {
- position: relative;
- cursor: pointer;
- font-size: 300%;
- display: inline-block;
-
- > a {
- font-size: 40%;
- margin: 0.2em;
- color: #999;
- font-family: Lato, Arial, sans-serif;
- &:hover, &:focus {
- text-decoration: none;
- }
- }
- }
-}
-
-// FIXME: protocol-relative urls for remote but absolute for local (file://)?
-.o_logo {
- display: inline-block;
- font-size: 300%;
- .o_logo_main {
- background-image: url(odoo_logo_rgb.png);
- background-repeat: no-repeat;
- background-position: center center;
- background-size: contain;
- color: rgba(255, 255, 255, 0);
- text-decoration: none;
- }
- .o_logo_app {
- text-decoration: none;
- color: rgb(143, 143, 143);
- font-family: Lato, Arial, sans-serif;
- font-size: 50%;
- margin: 0.2em;
- }
-}
-
-/*
- * Side navigation
- *
- * Scrollspy and affixed enhanced navigation to highlight sections and secondary
- * sections of docs content.
- */
-
-/* By default it's not affixed in mobile views, so undo that */
-.sphinxsidebarwrapper.affix {
- position: static;
-}
-@media (min-width: @screen-sm-min) {
- .sphinxsidebarwrapper {
- padding-left: 20px;
- }
-}
-
-/* Side navigation visibility changes */
-.sphinxsidebarwrapper {
- > .nav { // root (contains document categories), always show
- .nav {
- // hide sub-everything by default
- display: none;
- }
-
- li.active > .nav,
- li.current > .nav {
- // sub-items of a current or active li are shown
- display: block;
- }
- }
-}
-
-/* Side navigation graphical styling */
-@nav-spacing: 20px;
-@nav-spacing-increment: 5px;
-@nav-hover-offset: 1px;
-@nav-hover: @nav-spacing - @nav-hover-offset;
-@nav-current-offset: 2px;
-@nav-current: @nav-spacing - @nav-current-offset;
-
-.sphinxsidebar {
- z-index: 1;
-}
-.sphinxsidebarwrapper {
- width: 100%;
- font-size: 13px;
- z-index: 1;
-
- .hidden-xs();
- .hidden-sm();
- .hidden-print();
-
- /* First level of nav */
- > .nav {
- margin-top: 20px;
- margin-bottom: 20px;
- }
-
- .nav > li > a {
- font-weight: bold;
- padding-left: @nav-spacing;
- }
- .nav .nav > li > a {
- font-size: 12px;
- padding-left: @nav-spacing + @nav-spacing-increment;
- }
- .nav .nav .nav > li > a {
- font-weight: normal;
- padding-left: @nav-spacing + 2*@nav-spacing-increment;
- }
- .nav .nav .nav .nav > li > a {
- font-size: 11px;
- padding-left: @nav-spacing + 3*@nav-spacing-increment;
- }
-
- /* All levels of nav */
- .nav {
- > li > a {
- display: block;
- padding: 4px @nav-spacing;
- color: #999;
-
- &:hover, &:focus {
- padding-left: @nav-hover;
- color: @brand-primary;
- text-decoration: none;
- background-color: transparent;
- border-left: @nav-hover-offset solid @brand-primary;
- }
- }
-
- // before scrollspy is applied, need to use current for docs
- > .current > a, > .current:hover > a, > .current:focus > a,
- > .active > a, > .active:hover > a, > .active:focus > a {
- padding-left: @nav-current;
- font-weight: bold;
- color: @brand-primary;
- background-color: transparent;
- border-left: @nav-current-offset solid @brand-primary;
- }
- }
- .nav .nav {
- > li > a:hover, > li > a:focus {
- padding-left: @nav-hover + @nav-spacing-increment;
- }
- > .current > a, > .current:hover > a, > .current:focus > a,
- > .active > a, > .active:hover > a, > .active:focus > a {
- padding-left: @nav-current + @nav-spacing-increment;
- }
- }
- .nav .nav .nav {
- padding-bottom: 10px;
-
- > li > a {
- padding-top: 1px;
- padding-bottom: 1px;
- }
-
- > li > a:hover, > li > a:focus {
- padding-left: @nav-hover + 2 * @nav-spacing-increment;
- }
- > .active > a, > .active:hover > a, > .active:focus > a {
- padding-left: @nav-current + 2 * @nav-spacing-increment;
- font-weight: bold;
- }
- }
- .nav .nav .nav .nav {
- > li > a:hover, > li > a:focus {
- padding-left: @nav-hover + 3 * @nav-spacing-increment;
- }
- > .active > a, > .active:hover > a, > .active:focus > a {
- padding-left: @nav-current + 3 * @nav-spacing-increment;
- }
- }
-}
-/* github link for current document */
-.sphinxsidebarwrapper > p {
- margin: 5px 10px 10px;
- a {
- font-size: 13px;
- &:hover {
- text-decoration: none;
- }
-
- &.github {
- padding-left: 15px;
- position: relative;
- &:before {
- left: 0;
- top: 1px;
- content: '';
- position: absolute;
- width: 13px;
- height: 13px;
- background: url(github-link.png) left bottom / 13px no-repeat;
- }
- &:hover:before {
- background-position: left top;
- }
- }
- }
-}
-
-/* Show and affix the side nav when space allows it */
-@media (min-width: @screen-md-min) {
- .sphinxsidebarwrapper {
- .nav .nav > .active > ul {
- display: block;
- }
- /* Widen the fixed sidebar */
- &.affix, &.affix-bottom {
- width: 213px;
- }
- &.affix {
- position: fixed; /* Undo the static from mobile first approach */
- top: 20px;
- }
- &.affix-bottom {
- position: absolute; /* Undo the static from mobile first approach */
- }
- &.affix-bottom > .nav, &.affix > .nav {
- margin-top: 0;
- margin-bottom: 0;
- }
- }
-}
-@media (min-width: @screen-lg-min) {
- /* Widen the fixed sidebar again */
- .sphinxsidebarwrapper.affix-bottom,
- .sphinxsidebarwrapper.affix {
- width: 263px;
- }
-}
-
-/*
- * Footer
- *
- * Separated section of content at the bottom of all pages, save the homepage.
- */
-
-.footer {
- padding-top: 40px;
- padding-bottom: 40px;
- margin-top: 100px;
- color: #777;
- text-align: center;
- border-top: 1px solid #e5e5e5;
-}
-.docs-footer-links {
- padding-left: 0;
- margin-top: 20px;
- color: #999;
-}
-.docs-footer-links li {
- display: inline;
- padding: 0 2px;
-}
-.docs-footer-links li:first-child {
- padding-left: 0;
-}
-
-@media (min-width: 768px) {
- .footer p {
- margin-bottom: 0;
- }
-}
-
-// move [source] link to the right
-.viewcode-link {
- font-weight: normal;
- float: right;
- display: none;
-}
-dt:hover > a > .viewcode-link {
- display: inline;
-}
-
-// either that or overwrite visit_attribution/depart_attribution
-blockquote p.attribution:extend(blockquote footer) {}
-blockquote.highlights {
- border: none;
-}
-
-div.section > h1 {
- .page-header();
- font-size: floor((@font-size-base * 3.05));
-}
-
-div.section > h2 {
- .page-header();
- font-size: @font-size-h1;
- padding-top: 20px;
- margin-top: 0;
-}
-// ~docs-section
-.body {
- // otherwise main section right column content may not be visible
- position: relative;
- > .section > .section {
- margin-bottom: 60px;
- }
-}
-
-.literal:extend(code) {}
-
-.admonition {
- padding: 20px;
- margin: 20px 0;
- border: 1px solid @gray-lighter;
- border-left-width: 5px;
- border-radius: 3px;
-
- .admonition-title:after {
- content: ": ";
- }
- > .admonition-title,
- // only "aphorisms" should have the same size as the admonition category
- &.aphorism > .admonition-title + p,
- &.exercise > .admonition-title + p {
- display: inline-block;
- margin-top: 0;
- margin-bottom: 5px;
-
- font-family: @headings-font-family;
- font-weight: @headings-font-weight;
- line-height: @headings-line-height;
- color: @headings-color;
-
- font-size: @font-size-h4;
- }
-
- p:last-child {
- margin-bottom: 0;
- }
-
- &.tip {
- border-left-color: @brand-info;
- > .admonition-title {
- color: @brand-info;
- }
- }
- &.warning {
- border-left-color: @brand-warning;
- > .admonition-title {
- color: @brand-warning;
- }
- }
- &.danger {
- border-left-color: @brand-danger;
- > .admonition-title {
- color: @brand-danger;
- }
- }
- &.exercise {
- border-left-color: @gray-light;
- > .admonition-title {
- color: @gray;
- }
- }
-}
-
-.highlight {
- position: relative;
-
- // move styling from pre to highlight so can have multiple pre elements in
- // a single "code block" for ease of adding and removing setup code &al
- color: @gray-dark;
- // force override of pygments yellow background background
- background: @gray-lighter none !important;
- border: 1px solid @gray-light;
- border-radius: @border-radius-base 0 @border-radius-base @border-radius-base;
- margin: 10px 0;
-
- pre {
- padding: 0;
- margin: 10px;
- font-size: 75%;
- // don't break lines within words
- word-break: normal;
- word-wrap: normal;
-
- background: none;
- border: none;
- }
-
- &:hover .btn-show-setup {
- display: block;
- }
- .btn-show-setup {
- display: none;
- position: absolute;
- bottom: 100%;
- right: 0;
- z-index: 3;
- padding: 5px 8px;
- font-size: 12px;
- color: @gray-light;
- cursor: pointer;
- border: 1px solid @gray-light;
- border-radius: @border-radius-base @border-radius-base 0 0;
- background: inherit;
-
- &:focus {
- outline: none;
- }
- }
-}
-
-// rST styles
-img.align-center {
- display: block;
- margin: 0 auto;
-}
-
-dd {
- // Reinstate dd indent, looks horrible and illegible otherwise
- margin-left: @item-indent;
-}
-
-// By default there's (browser) padding on ``ul`` so lists of >1 field are
-// nicely separated from the section name (e.g. ``Parameters``) but single
-// fields/items are stuck to it and look horrible. Make everything neatly-ish
-// aligned. Other option: half and half so list bullets are aligned to text
-// instead of text to text
-td.field-body {
- padding-left: @item-indent;
- ul {
- padding-left: @item-indent;
- }
- > ul {
- padding-left: 0;
- }
-}
-
-// naming collision, rST generates .container nodes with completely different
-// semantics so go away
-.section .container {
- width: auto;
- margin: 0;
- padding: 0;
-}
-
-// lighten js namespace/class name
-.descclassname {
- opacity: 0.5;
-}
-
-
-.index-tree {
- ul, li {
- list-style: none;
- padding: 0;
- margin: 0;
- }
- > ul > li {
- margin-bottom: 0.5em;
- > a {
- .h3();
- text-align: center;
- }
- > ul {
- display: -webkit-flex;
- display: flex;
- -webkit-flex-wrap: wrap;
- flex-wrap: wrap;
- > li {
- width: 50%;
- a {
- .h4();
- padding-left: 10%;
- padding-right: 10%;
- }
- }
- }
- a {
- display: block;
- color: @link-color !important;
- padding: 0.3em 0;
- margin: 3px !important;
- &:hover {
- background-color: @gray-lighter;
- }
- }
- }
-}
-
-@background-right: @gray-dark;
-@color-right: @gray-lighter;
-@color-right-code: lighten(#000, 80%);
-@separator-right: @gray-light;
-// STRIPE-STYLE PAGES
-.stripe {
- .section {
- margin-bottom: 2em;
- }
-
- // === columning only on medium+ ===
- @media (min-width: @screen-md-min) {
- // column 1
- .section:not(.force-right) > *,
- .section:not(.force-right) > .force-left {
- width: 49%;
- float: left;
- clear: left;
- }
- // column 2
- .section:not(.force-right) > .force-right {
- padding-left: 1em;
- padding-right: 1em;
- }
- .section:not(.force-right) > .force-right,
- .section:not(.force-right) > [class*=highlight-] {
- float: none;
- clear: none;
- margin-left: 50%;
- width: 50%;
- color: @color-right;
- legend {
- color: inherit;
- }
- input {
- color: inherit;
- background-color: @gray;
- }
- a {
- color: lighten(@link-color, 30%);
- }
- code, .literal {
- color: @code-bg;
- background-color: @gray;
- }
- &:not(.highlight-json) .highlight {
- border-bottom-color: @separator-right;
- }
- &.admonition {
- margin-left: 51%;
- width: 49%;
- border-top-color: @separator-right;
- border-bottom-color: @separator-right;
- border-right-color: @separator-right;
- }
- .table th, .table td {
- border-color: @gray-light;
- }
- .highlight {
- border-color: @gray;
- border-style: solid;
- border-width: 1px 0;
- border-radius: 0;
- // solarized-ish from https://gist.github.com/qguv/7936275
- color: @color-right-code;
- background: none !important;
- .lineno { color: #586e75 } /* Line Numbers */
- .c { color: #586e75 } /* Comment */
- .err { color: @color-right-code } /* Error */
- .g { color: @color-right-code } /* Generic */
- .k { color: #859900 } /* Keyword */
- .l { color: @color-right-code } /* Literal */
- .n { color: @color-right-code } /* Name */
- .o { color: #859900 } /* Operator */
- .x { color: #cb4b16 } /* Other */
- .p { color: @color-right-code } /* Punctuation */
- .cm { color: #586e75 } /* Comment.Multiline */
- .cp { color: #859900 } /* Comment.Preproc */
- .c1 { color: #586e75 } /* Comment.Single */
- .cs { color: #859900 } /* Comment.Special */
- .gd { color: #2aa198 } /* Generic.Deleted */
- .ge { color: @color-right-code; font-style: italic } /* Generic.Emph */
- .gr { color: #dc322f } /* Generic.Error */
- .gh { color: #cb4b16 } /* Generic.Heading */
- .gi { color: #859900 } /* Generic.Inserted */
- .go { color: @color-right-code } /* Generic.Output */
- .gp { color: @color-right-code } /* Generic.Prompt */
- .gs { color: @color-right-code; font-weight: bold } /* Generic.Strong */
- .gu { color: #cb4b16 } /* Generic.Subheading */
- .gt { color: @color-right-code } /* Generic.Traceback */
- .kc { color: #cb4b16 } /* Keyword.Constant */
- .kd { color: #268bd2 } /* Keyword.Declaration */
- .kn { color: #859900 } /* Keyword.Namespace */
- .kp { color: #859900 } /* Keyword.Pseudo */
- .kr { color: #268bd2 } /* Keyword.Reserved */
- .kt { color: #dc322f } /* Keyword.Type */
- .ld { color: @color-right-code } /* Literal.Date */
- .m { color: #2aa198 } /* Literal.Number */
- .s { color: #2aa198 } /* Literal.String */
- .na { color: @color-right-code } /* Name.Attribute */
- .nb { color: #B58900 } /* Name.Builtin */
- .nc { color: #268bd2 } /* Name.Class */
- .no { color: #cb4b16 } /* Name.Constant */
- .nd { color: #268bd2 } /* Name.Decorator */
- .ni { color: #cb4b16 } /* Name.Entity */
- .ne { color: #cb4b16 } /* Name.Exception */
- .nf { color: #268bd2 } /* Name.Function */
- .nl { color: @color-right-code } /* Name.Label */
- .nn { color: @color-right-code } /* Name.Namespace */
- .nx { color: @color-right-code } /* Name.Other */
- .py { color: @color-right-code } /* Name.Property */
- .nt { color: #268bd2 } /* Name.Tag */
- .nv { color: #268bd2 } /* Name.Variable */
- .ow { color: #859900 } /* Operator.Word */
- .w { color: @color-right-code } /* Text.Whitespace */
- .mf { color: #2aa198 } /* Literal.Number.Float */
- .mh { color: #2aa198 } /* Literal.Number.Hex */
- .mi { color: #2aa198 } /* Literal.Number.Integer */
- .mo { color: #2aa198 } /* Literal.Number.Oct */
- .sb { color: #586e75 } /* Literal.String.Backtick */
- .sc { color: #2aa198 } /* Literal.String.Char */
- .sd { color: @color-right-code } /* Literal.String.Doc */
- .s2 { color: #2aa198 } /* Literal.String.Double */
- .se { color: #cb4b16 } /* Literal.String.Escape */
- .sh { color: @color-right-code } /* Literal.String.Heredoc */
- .si { color: #2aa198 } /* Literal.String.Interpol */
- .sx { color: #2aa198 } /* Literal.String.Other */
- .sr { color: #dc322f } /* Literal.String.Regex */
- .s1 { color: #2aa198 } /* Literal.String.Single */
- .ss { color: #2aa198 } /* Literal.String.Symbol */
- .bp { color: #268bd2 } /* Name.Builtin.Pseudo */
- .vc { color: #268bd2 } /* Name.Variable.Class */
- .vg { color: #268bd2 } /* Name.Variable.Global */
- .vi { color: #268bd2 } /* Name.Variable.Instance */
- .il { color: #2aa198 } /* Literal.Number.Integer.Long */
- }
- }
- // separator above H2
- .body > .section > {
- .section {
- border-top: 1px solid @color-right;
- }
- // but not if subsection directly follows an h1 (no introductory
- // document paragraph)
- h1 + .section {
- border-top: none;
- }
- }
- .section:not(.force-right) > h1, .section:not(.force-right) > h2,
- .section:not(.force-right) > h3, .section:not(.force-right) > h4,
- .section:not(.force-right) > h5, .section:not(.force-right) > h6 {
- max-width: 50%;
-
- }
- .section:not(.force-right) > h1, .section:not(.force-right) > h2,
- .section:not(.force-right) > h3, .section:not(.force-right) > h4,
- .section:not(.force-right) > h5, .section:not(.force-right) > h6,
- .section > .section:not(.force-right) {
- position: relative;
- width: auto;
- float: none;
- clear: both;
- }
-
- .documentwrapper {
- overflow: auto;
- // middle separator
- &:before {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 50%;
- content: "";
- width: 50%;
- background: @background-right;
- }
- }
-
- .highlight pre {
- // but allow additional line-breaks between "words" to avoid overflow
- white-space: pre-wrap;
- }
-
- .btn-show-setup {
- background-color: transparent;
- color: @color-right;
- border-color: @separator-right;
-
- &.active {
- background-color: @gray;
- .transition(background-color .5s linear);
- }
- }
- }
-
- .switcher {
- color: white;
- width: auto !important;
- float: none !important;
-
- position: absolute;
- display: -webkit-flex;
- display: flex;
- -webkit-justify-content: flex-end;
- justify-content: flex-end;
-
- right: 0.5em;
- list-style: none;
- padding: 0;
- margin: 0;
- z-index: 5;
- &.affix {
- position: fixed;
- top: 0;
- }
-
- li {
- background-color: #0f131a;
- padding: 0.4em 1em;
- border: 1px solid #333;
- border-left-width: 0;
- cursor: pointer;
- &:first-child {
- border-left-width: 1px;
- border-radius: 0 0 0 5px;
- }
- &:last-child {
- border-radius: 0 0 5px 0;
- }
- &:hover {
- background-color: #222;
- }
- &.active {
- background-color: #333;
- }
- }
- }
-
- // === show/hide code snippets ===
- [class*=only-],
- .switchable > .highlight {
- display: none;
- }
- // must be final rule of page
- .only-python, .highlight-python > .highlight {
- display: block;
- }
-}
diff --git a/doc/api_integration.rst b/doc/api_integration.rst
index 0d9bd9b9eab..49bcc60ced6 100644
--- a/doc/api_integration.rst
+++ b/doc/api_integration.rst
@@ -1,4 +1,8 @@
-:classes: stripe
+:banner: banners/web_service_api.jpg
+:types: api
+
+
+:code-column:
===============
Web Service API
@@ -90,7 +94,9 @@ Configuration
If you already have an Odoo server installed, you can just use its
parameters
-.. rst-class:: switchable setup
+.. rst-class:: setup doc-aside
+
+.. switcher::
.. code-block:: python
@@ -123,7 +129,9 @@ parameters
To make exploration simpler, you can also ask https://demo.odoo.com for a test
database:
-.. rst-class:: switchable setup
+.. rst-class:: setup doc-aside
+
+.. switcher::
.. code-block:: python
@@ -139,51 +147,51 @@ database:
url, db, username, password = \
info['host'], info['database'], info['user'], info['password']
- .. code-block:: php
+ .. case:: PHP
- require_once('ripcord.php');
- $info = ripcord::client('https://demo.odoo.com/start')->start();
- list($url, $db, $username, $password) =
- array($info['host'], $info['database'], $info['user'], $info['password']);
+ .. code-block:: php
- .. code-block:: java
+ require_once('ripcord.php');
+ $info = ripcord::client('https://demo.odoo.com/start')->start();
+ list($url, $db, $username, $password) =
+ array($info['host'], $info['database'], $info['user'], $info['password']);
- final XmlRpcClient client = new XmlRpcClient();
+ .. note::
- final XmlRpcClientConfigImpl start_config = new XmlRpcClientConfigImpl();
- start_config.setServerURL(new URL("https://demo.odoo.com/start"));
- final Map info = (Map)client.execute(
- start_config, "start", emptyList());
+ These examples use the `Ripcord `_
+ library, which provides a simple XML-RPC API. Ripcord requires that
+ `XML-RPC support be enabled
+ `_ in your PHP
+ installation.
- final String url = info.get("host"),
- db = info.get("database"),
- username = info.get("user"),
- password = info.get("password");
+ Since calls are performed over
+ `HTTPS `_, it also requires that
+ the `OpenSSL extension
+ `_ be enabled.
-.. rst-class:: force-right
+ .. case:: Java
- .. note::
- :class: only-php
+ .. code-block:: java
- These examples use the `Ripcord `_
- library, which provides a simple XML-RPC API. Ripcord requires that
- `XML-RPC support be enabled
- `_ in your PHP
- installation.
+ final XmlRpcClient client = new XmlRpcClient();
- Since calls are performed over
- `HTTPS `_, it also requires that
- the `OpenSSL extension
- `_ be enabled.
+ final XmlRpcClientConfigImpl start_config = new XmlRpcClientConfigImpl();
+ start_config.setServerURL(new URL("https://demo.odoo.com/start"));
+ final Map info = (Map)client.execute(
+ start_config, "start", emptyList());
- .. note::
- :class: only-java
+ final String url = info.get("host"),
+ db = info.get("database"),
+ username = info.get("user"),
+ password = info.get("password");
- These examples use the `Apache XML-RPC library
- `_
+ .. note::
- The examples do not include imports as these imports couldn't be
- pasted in the code.
+ These examples use the `Apache XML-RPC library
+ `_
+
+ The examples do not include imports as these imports couldn't be
+ pasted in the code.
Logging in
----------
@@ -199,7 +207,9 @@ authentication itself is done through the ``authenticate`` function and
returns a user identifier (``uid``) used in authenticated calls instead of
the login.
-.. rst-class:: switchable setup
+.. rst-class:: setup doc-aside
+
+.. switcher::
.. code-block:: python
@@ -223,6 +233,8 @@ the login.
new URL(String.format("%s/xmlrpc/2/common", url)));
client.execute(common_config, "version", emptyList());
+.. rst-class:: doc-aside
+
.. code-block:: json
{
@@ -232,7 +244,9 @@ the login.
"protocol_version": 1,
}
-.. rst-class:: switchable setup
+.. rst-class:: setup doc-aside
+
+.. switcher::
.. code-block:: python
@@ -268,55 +282,57 @@ Each call to ``execute_kw`` takes the following parameters:
* an array/list of parameters passed by position
* a mapping/dict of parameters to pass by keyword (optional)
-.. rst-class:: force-right
+.. container:: doc-aside
-For instance to see if we can read the ``res.partner`` model we can call
-``check_access_rights`` with ``operation`` passed by position and
-``raise_exception`` passed by keyword (in order to get a true/false result
-rather than true/error):
+ For instance to see if we can read the ``res.partner`` model we can call
+ ``check_access_rights`` with ``operation`` passed by position and
+ ``raise_exception`` passed by keyword (in order to get a true/false result
+ rather than true/error):
-.. rst-class:: switchable setup
+ .. rst-class:: setup
- .. code-block:: python
+ .. switcher::
- models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
- models.execute_kw(db, uid, password,
- 'res.partner', 'check_access_rights',
- ['read'], {'raise_exception': False})
+ .. code-block:: python
- .. code-block:: ruby
+ models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url))
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'check_access_rights',
+ ['read'], {'raise_exception': False})
- models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
- models.execute_kw(db, uid, password,
- 'res.partner', 'check_access_rights',
- ['read'], {raise_exception: false})
+ .. code-block:: ruby
- .. code-block:: php
+ models = XMLRPC::Client.new2("#{url}/xmlrpc/2/object").proxy
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'check_access_rights',
+ ['read'], {raise_exception: false})
- $models = ripcord::client("$url/xmlrpc/2/object");
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'check_access_rights',
- array('read'), array('raise_exception' => false));
+ .. code-block:: php
- .. code-block:: java
+ $models = ripcord::client("$url/xmlrpc/2/object");
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'check_access_rights',
+ array('read'), array('raise_exception' => false));
- final XmlRpcClient models = new XmlRpcClient() {{
- setConfig(new XmlRpcClientConfigImpl() {{
- setServerURL(new URL(String.format("%s/xmlrpc/2/object", url)));
- }});
- }};
- models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "check_access_rights",
- asList("read"),
- new HashMap() {{ put("raise_exception", false); }}
- ));
+ .. code-block:: java
-.. code-block:: json
+ final XmlRpcClient models = new XmlRpcClient() {{
+ setConfig(new XmlRpcClientConfigImpl() {{
+ setServerURL(new URL(String.format("%s/xmlrpc/2/object", url)));
+ }});
+ }};
+ models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "check_access_rights",
+ asList("read"),
+ new HashMap() {{ put("raise_exception", false); }}
+ ));
- true
+ .. code-block:: json
-.. todo:: this should be runnable and checked
+ true
+
+ .. todo:: this should be runnable and checked
List records
------------
@@ -328,40 +344,42 @@ Records can be listed and filtered via :meth:`~openerp.models.Model.search`.
database identifiers of all records matching the filter. To list customer
companies for instance:
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- models.execute_kw(db, uid, password,
- 'res.partner', 'search',
- [[['is_company', '=', True], ['customer', '=', True]]])
+ .. code-block:: python
- .. code-block:: ruby
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search',
+ [[['is_company', '=', True], ['customer', '=', True]]])
- models.execute_kw(db, uid, password,
- 'res.partner', 'search',
- [[['is_company', '=', true], ['customer', '=', true]]])
+ .. code-block:: ruby
- .. code-block:: php
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search',
+ [[['is_company', '=', true], ['customer', '=', true]]])
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'search', array(
- array(array('is_company', '=', true),
- array('customer', '=', true))));
+ .. code-block:: php
- .. code-block:: java
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'search', array(
+ array(array('is_company', '=', true),
+ array('customer', '=', true))));
- asList((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "search",
- asList(asList(
- asList("is_company", "=", true),
- asList("customer", "=", true)))
- )));
+ .. code-block:: java
-.. code-block:: json
+ asList((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search",
+ asList(asList(
+ asList("is_company", "=", true),
+ asList("customer", "=", true)))
+ )));
- [7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
+ .. code-block:: json
+
+ [7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74]
Pagination
''''''''''
@@ -370,44 +388,46 @@ By default a research will return the ids of all records matching the
condition, which may be a huge number. ``offset`` and ``limit`` parameters are
available to only retrieve a subset of all matched records.
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
-
- models.execute_kw(db, uid, password,
- 'res.partner', 'search',
- [[['is_company', '=', True], ['customer', '=', True]]],
- {'offset': 10, 'limit': 5})
-
- .. code-block:: ruby
-
- models.execute_kw(db, uid, password,
- 'res.partner', 'search',
- [[['is_company', '=', true], ['customer', '=', true]]],
- {offset: 10, limit: 5})
-
- .. code-block:: php
-
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'search',
- array(array(array('is_company', '=', true),
- array('customer', '=', true))),
- array('offset'=>10, 'limit'=>5));
-
- .. code-block:: java
-
- asList((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "search",
- asList(asList(
- asList("is_company", "=", true),
- asList("customer", "=", true))),
- new HashMap() {{ put("offset", 10); put("limit", 5); }}
- )));
-
-.. code-block:: json
-
- [13, 20, 30, 22, 29]
+ .. switcher::
+
+ .. code-block:: python
+
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search',
+ [[['is_company', '=', True], ['customer', '=', True]]],
+ {'offset': 10, 'limit': 5})
+
+ .. code-block:: ruby
+
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search',
+ [[['is_company', '=', true], ['customer', '=', true]]],
+ {offset: 10, limit: 5})
+
+ .. code-block:: php
+
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'search',
+ array(array(array('is_company', '=', true),
+ array('customer', '=', true))),
+ array('offset'=>10, 'limit'=>5));
+
+ .. code-block:: java
+
+ asList((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search",
+ asList(asList(
+ asList("is_company", "=", true),
+ asList("customer", "=", true))),
+ new HashMap() {{ put("offset", 10); put("limit", 5); }}
+ )));
+
+ .. code-block:: json
+
+ [13, 20, 30, 22, 29]
Count records
-------------
@@ -418,40 +438,42 @@ only the number of records matching the query. It takes the same
:ref:`domain ` filter as
:meth:`~openerp.models.Model.search` and no other parameter.
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
-
- models.execute_kw(db, uid, password,
- 'res.partner', 'search_count',
- [[['is_company', '=', True], ['customer', '=', True]]])
-
- .. code-block:: ruby
-
- models.execute_kw(db, uid, password,
- 'res.partner', 'search_count',
- [[['is_company', '=', true], ['customer', '=', true]]])
-
- .. code-block:: php
-
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'search_count',
- array(array(array('is_company', '=', true),
- array('customer', '=', true))));
-
- .. code-block:: java
-
- (Integer)models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "search_count",
- asList(asList(
- asList("is_company", "=", true),
- asList("customer", "=", true)))
- ));
-
-.. code-block:: json
-
- 19
+ .. switcher::
+
+ .. code-block:: python
+
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search_count',
+ [[['is_company', '=', True], ['customer', '=', True]]])
+
+ .. code-block:: ruby
+
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search_count',
+ [[['is_company', '=', true], ['customer', '=', true]]])
+
+ .. code-block:: php
+
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'search_count',
+ array(array(array('is_company', '=', true),
+ array('customer', '=', true))));
+
+ .. code-block:: java
+
+ (Integer)models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search_count",
+ asList(asList(
+ asList("is_company", "=", true),
+ asList("customer", "=", true)))
+ ));
+
+ .. code-block:: json
+
+ 19
.. warning::
@@ -468,103 +490,107 @@ which takes a list of ids (as returned by
fetch. By default, it will fetch all the fields the current user can read,
which tends to be a huge amount.
-.. rst-class:: switchable
-
- .. code-block:: python
-
- ids = models.execute_kw(db, uid, password,
- 'res.partner', 'search',
- [[['is_company', '=', True], ['customer', '=', True]]],
- {'limit': 1})
- [record] = models.execute_kw(db, uid, password,
- 'res.partner', 'read', [ids])
- # count the number of fields fetched by default
- len(record)
-
- .. code-block:: ruby
-
- ids = models.execute_kw(db, uid, password,
- 'res.partner', 'search',
- [[['is_company', '=', true], ['customer', '=', true]]],
- {limit: 1})
- record = models.execute_kw(db, uid, password,
- 'res.partner', 'read', [ids]).first
- # count the number of fields fetched by default
- record.length
-
- .. code-block:: php
-
- $ids = $models->execute_kw($db, $uid, $password,
- 'res.partner', 'search',
- array(array(array('is_company', '=', true),
- array('customer', '=', true))),
- array('limit'=>1));
- $records = $models->execute_kw($db, $uid, $password,
- 'res.partner', 'read', array($ids));
- // count the number of fields fetched by default
- count($records[0]);
-
- .. code-block:: java
-
- final List ids = asList((Object[])models.execute(
- "execute_kw", asList(
- db, uid, password,
- "res.partner", "search",
- asList(asList(
- asList("is_company", "=", true),
- asList("customer", "=", true))),
- new HashMap() {{ put("limit", 1); }})));
- final Map record = (Map)((Object[])models.execute(
- "execute_kw", asList(
- db, uid, password,
- "res.partner", "read",
- asList(ids)
- )
- ))[0];
- // count the number of fields fetched by default
- record.size();
-
-.. code-block:: json
-
- 121
+.. container:: doc-aside
+
+ .. switcher::
+
+ .. code-block:: python
+
+ ids = models.execute_kw(db, uid, password,
+ 'res.partner', 'search',
+ [[['is_company', '=', True], ['customer', '=', True]]],
+ {'limit': 1})
+ [record] = models.execute_kw(db, uid, password,
+ 'res.partner', 'read', [ids])
+ # count the number of fields fetched by default
+ len(record)
+
+ .. code-block:: ruby
+
+ ids = models.execute_kw(db, uid, password,
+ 'res.partner', 'search',
+ [[['is_company', '=', true], ['customer', '=', true]]],
+ {limit: 1})
+ record = models.execute_kw(db, uid, password,
+ 'res.partner', 'read', [ids]).first
+ # count the number of fields fetched by default
+ record.length
+
+ .. code-block:: php
+
+ $ids = $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'search',
+ array(array(array('is_company', '=', true),
+ array('customer', '=', true))),
+ array('limit'=>1));
+ $records = $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'read', array($ids));
+ // count the number of fields fetched by default
+ count($records[0]);
+
+ .. code-block:: java
+
+ final List ids = asList((Object[])models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search",
+ asList(asList(
+ asList("is_company", "=", true),
+ asList("customer", "=", true))),
+ new HashMap() {{ put("limit", 1); }})));
+ final Map record = (Map)((Object[])models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "res.partner", "read",
+ asList(ids)
+ )
+ ))[0];
+ // count the number of fields fetched by default
+ record.size();
+
+ .. code-block:: json
+
+ 121
Conversedly, picking only three fields deemed interesting.
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- models.execute_kw(db, uid, password,
- 'res.partner', 'read',
- [ids], {'fields': ['name', 'country_id', 'comment']})
+ .. code-block:: python
- .. code-block:: ruby
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'read',
+ [ids], {'fields': ['name', 'country_id', 'comment']})
- models.execute_kw(db, uid, password,
- 'res.partner', 'read',
- [ids], {fields: %w(name country_id comment)})
+ .. code-block:: ruby
- .. code-block:: php
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'read',
+ [ids], {fields: %w(name country_id comment)})
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'read',
- array($ids),
- array('fields'=>array('name', 'country_id', 'comment')));
+ .. code-block:: php
- .. code-block:: java
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'read',
+ array($ids),
+ array('fields'=>array('name', 'country_id', 'comment')));
- asList((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "read",
- asList(ids),
- new HashMap() {{
- put("fields", asList("name", "country_id", "comment"));
- }}
- )));
+ .. code-block:: java
-.. code-block:: json
+ asList((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "read",
+ asList(ids),
+ new HashMap() {{
+ put("fields", asList("name", "country_id", "comment"));
+ }}
+ )));
- [{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]
+ .. code-block:: json
+
+ [{"comment": false, "country_id": [21, "Belgium"], "id": 7, "name": "Agrolait"}]
.. note:: even if the ``id`` field is not requested, it is always returned
@@ -581,75 +607,77 @@ for a human user are ``string`` (the field's label), ``help`` (a help text if
available) and ``type`` (to know which values to expect, or to send when
updating a record):
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- models.execute_kw(
- db, uid, password, 'res.partner', 'fields_get',
- [], {'attributes': ['string', 'help', 'type']})
+ .. code-block:: python
- .. code-block:: ruby
+ models.execute_kw(
+ db, uid, password, 'res.partner', 'fields_get',
+ [], {'attributes': ['string', 'help', 'type']})
- models.execute_kw(
- db, uid, password, 'res.partner', 'fields_get',
- [], {attributes: %w(string help type)})
+ .. code-block:: ruby
- .. code-block:: php
+ models.execute_kw(
+ db, uid, password, 'res.partner', 'fields_get',
+ [], {attributes: %w(string help type)})
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'fields_get',
- array(), array('attributes' => array('string', 'help', 'type')));
+ .. code-block:: php
- .. code-block:: java
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'fields_get',
+ array(), array('attributes' => array('string', 'help', 'type')));
- (Map>)models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "fields_get",
- emptyList(),
- new HashMap() {{
- put("attributes", asList("string", "help", "type"));
- }}
- ));
+ .. code-block:: java
-.. code-block:: json
+ (Map>)models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "fields_get",
+ emptyList(),
+ new HashMap() {{
+ put("attributes", asList("string", "help", "type"));
+ }}
+ ));
- {
- "ean13": {
- "type": "char",
- "help": "BarCode",
- "string": "EAN13"
- },
- "property_account_position": {
- "type": "many2one",
- "help": "The fiscal position will determine taxes and accounts used for the partner.",
- "string": "Fiscal Position"
- },
- "signup_valid": {
- "type": "boolean",
- "help": "",
- "string": "Signup Token is Valid"
- },
- "date_localization": {
- "type": "date",
- "help": "",
- "string": "Geo Localization Date"
- },
- "ref_companies": {
- "type": "one2many",
- "help": "",
- "string": "Companies that refers to partner"
- },
- "sale_order_count": {
- "type": "integer",
- "help": "",
- "string": "# of Sales Order"
- },
- "purchase_order_count": {
- "type": "integer",
- "help": "",
- "string": "# of Purchase Order"
- },
+ .. code-block:: json
+
+ {
+ "ean13": {
+ "type": "char",
+ "help": "BarCode",
+ "string": "EAN13"
+ },
+ "property_account_position": {
+ "type": "many2one",
+ "help": "The fiscal position will determine taxes and accounts used for the partner.",
+ "string": "Fiscal Position"
+ },
+ "signup_valid": {
+ "type": "boolean",
+ "help": "",
+ "string": "Signup Token is Valid"
+ },
+ "date_localization": {
+ "type": "date",
+ "help": "",
+ "string": "Geo Localization Date"
+ },
+ "ref_companies": {
+ "type": "one2many",
+ "help": "",
+ "string": "Companies that refers to partner"
+ },
+ "sale_order_count": {
+ "type": "integer",
+ "help": "",
+ "string": "# of Sales Order"
+ },
+ "purchase_order_count": {
+ "type": "integer",
+ "help": "",
+ "string": "# of Purchase Order"
+ },
Search and read
---------------
@@ -664,78 +692,80 @@ Its arguments are similar to :meth:`~openerp.models.Model.search`'s, but it
can also take a list of ``fields`` (like :meth:`~openerp.models.Model.read`,
if that list is not provided it'll fetch all fields of matched records):
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- models.execute_kw(db, uid, password,
- 'res.partner', 'search_read',
- [[['is_company', '=', True], ['customer', '=', True]]],
- {'fields': ['name', 'country_id', 'comment'], 'limit': 5})
+ .. code-block:: python
- .. code-block:: ruby
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search_read',
+ [[['is_company', '=', True], ['customer', '=', True]]],
+ {'fields': ['name', 'country_id', 'comment'], 'limit': 5})
- models.execute_kw(db, uid, password,
- 'res.partner', 'search_read',
- [[['is_company', '=', true], ['customer', '=', true]]],
- {fields: %w(name country_id comment), limit: 5})
+ .. code-block:: ruby
- .. code-block:: php
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search_read',
+ [[['is_company', '=', true], ['customer', '=', true]]],
+ {fields: %w(name country_id comment), limit: 5})
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'search_read',
- array(array(array('is_company', '=', true),
- array('customer', '=', true))),
- array('fields'=>array('name', 'country_id', 'comment'), 'limit'=>5));
+ .. code-block:: php
- .. code-block:: java
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'search_read',
+ array(array(array('is_company', '=', true),
+ array('customer', '=', true))),
+ array('fields'=>array('name', 'country_id', 'comment'), 'limit'=>5));
- asList((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "search_read",
- asList(asList(
- asList("is_company", "=", true),
- asList("customer", "=", true))),
- new HashMap() {{
- put("fields", asList("name", "country_id", "comment"));
- put("limit", 5);
- }}
- )));
+ .. code-block:: java
-.. code-block:: json
+ asList((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search_read",
+ asList(asList(
+ asList("is_company", "=", true),
+ asList("customer", "=", true))),
+ new HashMap() {{
+ put("fields", asList("name", "country_id", "comment"));
+ put("limit", 5);
+ }}
+ )));
- [
- {
- "comment": false,
- "country_id": [ 21, "Belgium" ],
- "id": 7,
- "name": "Agrolait"
- },
- {
- "comment": false,
- "country_id": [ 76, "France" ],
- "id": 18,
- "name": "Axelor"
- },
- {
- "comment": false,
- "country_id": [ 233, "United Kingdom" ],
- "id": 12,
- "name": "Bank Wealthy and sons"
- },
- {
- "comment": false,
- "country_id": [ 105, "India" ],
- "id": 14,
- "name": "Best Designers"
- },
- {
- "comment": false,
- "country_id": [ 76, "France" ],
- "id": 17,
- "name": "Camptocamp"
- }
- ]
+ .. code-block:: json
+
+ [
+ {
+ "comment": false,
+ "country_id": [ 21, "Belgium" ],
+ "id": 7,
+ "name": "Agrolait"
+ },
+ {
+ "comment": false,
+ "country_id": [ 76, "France" ],
+ "id": 18,
+ "name": "Axelor"
+ },
+ {
+ "comment": false,
+ "country_id": [ 233, "United Kingdom" ],
+ "id": 12,
+ "name": "Bank Wealthy and sons"
+ },
+ {
+ "comment": false,
+ "country_id": [ 105, "India" ],
+ "id": 14,
+ "name": "Best Designers"
+ },
+ {
+ "comment": false,
+ "country_id": [ 76, "France" ],
+ "id": 17,
+ "name": "Camptocamp"
+ }
+ ]
Create records
@@ -748,37 +778,39 @@ method will create a single record and return its database identifier.
to initialize the record. For any field which has a default value and is not
set through the mapping argument, the default value will be used.
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
- 'name': "New Partner",
- }])
+ .. code-block:: python
- .. code-block:: ruby
+ id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
+ 'name': "New Partner",
+ }])
- id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
- name: "New Partner",
- }])
+ .. code-block:: ruby
- .. code-block:: php
+ id = models.execute_kw(db, uid, password, 'res.partner', 'create', [{
+ name: "New Partner",
+ }])
- $id = $models->execute_kw($db, $uid, $password,
- 'res.partner', 'create',
- array(array('name'=>"New Partner")));
+ .. code-block:: php
- .. code-block:: java
+ $id = $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'create',
+ array(array('name'=>"New Partner")));
- final Integer id = (Integer)models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "create",
- asList(new HashMap() {{ put("name", "New Partner"); }})
- ));
+ .. code-block:: java
-.. code-block:: json
+ final Integer id = (Integer)models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "create",
+ asList(new HashMap() {{ put("name", "New Partner"); }})
+ ));
- 78
+ .. code-block:: json
+
+ 78
.. warning::
@@ -804,52 +836,54 @@ values for the fields being set. It is not currently possible to perform
"computed" updates (where the value being set depends on an existing value of
a record).
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], {
- 'name': "Newer partner"
- }])
- # get record name after having changed it
- models.execute_kw(db, uid, password, 'res.partner', 'name_get', [[id]])
+ .. code-block:: python
- .. code-block:: ruby
+ models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], {
+ 'name': "Newer partner"
+ }])
+ # get record name after having changed it
+ models.execute_kw(db, uid, password, 'res.partner', 'name_get', [[id]])
- models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], {
- name: "Newer partner"
- }])
- # get record name after having changed it
- models.execute_kw(db, uid, password, 'res.partner', 'name_get', [[id]])
+ .. code-block:: ruby
- .. code-block:: php
+ models.execute_kw(db, uid, password, 'res.partner', 'write', [[id], {
+ name: "Newer partner"
+ }])
+ # get record name after having changed it
+ models.execute_kw(db, uid, password, 'res.partner', 'name_get', [[id]])
- $models->execute_kw($db, $uid, $password, 'res.partner', 'write',
- array(array($id), array('name'=>"Newer partner")));
- // get record name after having changed it
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'name_get', array(array($id)));
+ .. code-block:: php
- .. code-block:: java
+ $models->execute_kw($db, $uid, $password, 'res.partner', 'write',
+ array(array($id), array('name'=>"Newer partner")));
+ // get record name after having changed it
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'name_get', array(array($id)));
- models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "write",
- asList(
- asList(id),
- new HashMap() {{ put("name", "Newer Partner"); }}
- )
- ));
- // get record name after having changed it
- asList((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "name_get",
- asList(asList(id))
- )));
+ .. code-block:: java
-.. code-block:: json
+ models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "write",
+ asList(
+ asList(id),
+ new HashMap() {{ put("name", "Newer Partner"); }}
+ )
+ ));
+ // get record name after having changed it
+ asList((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "name_get",
+ asList(asList(id))
+ )));
- [[78, "Newer partner"]]
+ .. code-block:: json
+
+ [[78, "Newer partner"]]
Delete records
--------------
@@ -857,48 +891,50 @@ Delete records
Records can be deleted in bulk by providing the ids of all records to remove
to :meth:`~openerp.models.Model.unlink`.
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]])
- # check if the deleted record is still in the database
- models.execute_kw(db, uid, password,
- 'res.partner', 'search', [[['id', '=', id]]])
+ .. code-block:: python
- .. code-block:: ruby
+ models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]])
+ # check if the deleted record is still in the database
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search', [[['id', '=', id]]])
- models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]])
- # check if the deleted record is still in the database
- models.execute_kw(db, uid, password,
- 'res.partner', 'search', [[['id', '=', id]]])
+ .. code-block:: ruby
- .. code-block:: php
+ models.execute_kw(db, uid, password, 'res.partner', 'unlink', [[id]])
+ # check if the deleted record is still in the database
+ models.execute_kw(db, uid, password,
+ 'res.partner', 'search', [[['id', '=', id]]])
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'unlink',
- array(array($id)));
- // check if the deleted record is still in the database
- $models->execute_kw($db, $uid, $password,
- 'res.partner', 'search',
- array(array(array('id', '=', $id))));
+ .. code-block:: php
- .. code-block:: java
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'unlink',
+ array(array($id)));
+ // check if the deleted record is still in the database
+ $models->execute_kw($db, $uid, $password,
+ 'res.partner', 'search',
+ array(array(array('id', '=', $id))));
- models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "unlink",
- asList(asList(id))));
- // check if the deleted record is still in the database
- asList((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "search",
- asList(asList(asList("id", "=", 78)))
- )));
+ .. code-block:: java
-.. code-block:: json
+ models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "unlink",
+ asList(asList(id))));
+ // check if the deleted record is still in the database
+ asList((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search",
+ asList(asList(asList("id", "=", 78)))
+ )));
- []
+ .. code-block:: json
+
+ []
Inspection and introspection
----------------------------
@@ -953,111 +989,111 @@ Provides informations about Odoo models themselves via its various fields
not be loaded
* it is not possible to add new *methods* to a custom model, only fields
-.. rst-class:: force-right
+.. container:: doc-aside
a custom model will initially contain only the "built-in" fields available
on all models:
-.. rst-class:: switchable
+ .. switcher::
- .. code-block:: python
+ .. code-block:: python
- models.execute_kw(db, uid, password, 'ir.model', 'create', [{
- 'name': "Custom Model",
- 'model': "x_custom_model",
- 'state': 'manual',
- }])
- models.execute_kw(
- db, uid, password, 'x_custom_model', 'fields_get',
- [], {'attributes': ['string', 'help', 'type']})
-
- .. code-block:: php
-
- $models->execute_kw(
- $db, $uid, $password,
- 'ir.model', 'create', array(array(
- 'name' => "Custom Model",
- 'model' => 'x_custom_model',
- 'state' => 'manual'
- ))
- );
- $models->execute_kw(
- $db, $uid, $password,
- 'x_custom_model', 'fields_get',
- array(),
- array('attributes' => array('string', 'help', 'type'))
- );
-
- .. code-block:: ruby
-
- models.execute_kw(
- db, uid, password,
- 'ir.model', 'create', [{
- name: "Custom Model",
- model: 'x_custom_model',
- state: 'manual'
+ models.execute_kw(db, uid, password, 'ir.model', 'create', [{
+ 'name': "Custom Model",
+ 'model': "x_custom_model",
+ 'state': 'manual',
}])
- fields = models.execute_kw(
- db, uid, password, 'x_custom_model', 'fields_get',
- [], {attributes: %w(string help type)})
+ models.execute_kw(
+ db, uid, password, 'x_custom_model', 'fields_get',
+ [], {'attributes': ['string', 'help', 'type']})
- .. code-block:: java
+ .. code-block:: php
- models.execute(
- "execute_kw", asList(
+ $models->execute_kw(
+ $db, $uid, $password,
+ 'ir.model', 'create', array(array(
+ 'name' => "Custom Model",
+ 'model' => 'x_custom_model',
+ 'state' => 'manual'
+ ))
+ );
+ $models->execute_kw(
+ $db, $uid, $password,
+ 'x_custom_model', 'fields_get',
+ array(),
+ array('attributes' => array('string', 'help', 'type'))
+ );
+
+ .. code-block:: ruby
+
+ models.execute_kw(
db, uid, password,
- "ir.model", "create",
- asList(new HashMap() {{
- put("name", "Custom Model");
- put("model", "x_custom_model");
- put("state", "manual");
- }})
- ));
- final Object fields = models.execute(
- "execute_kw", asList(
- db, uid, password,
- "x_custom_model", "fields_get",
- emptyList(),
- new HashMap () {{
- put("attributes", asList(
- "string",
- "help",
- "type"));
- }}
- ));
+ 'ir.model', 'create', [{
+ name: "Custom Model",
+ model: 'x_custom_model',
+ state: 'manual'
+ }])
+ fields = models.execute_kw(
+ db, uid, password, 'x_custom_model', 'fields_get',
+ [], {attributes: %w(string help type)})
-.. code-block:: json
+ .. code-block:: java
- {
- "create_uid": {
- "type": "many2one",
- "string": "Created by"
- },
- "create_date": {
- "type": "datetime",
- "string": "Created on"
- },
- "__last_update": {
- "type": "datetime",
- "string": "Last Modified on"
- },
- "write_uid": {
- "type": "many2one",
- "string": "Last Updated by"
- },
- "write_date": {
- "type": "datetime",
- "string": "Last Updated on"
- },
- "display_name": {
- "type": "char",
- "string": "Display Name"
- },
- "id": {
- "type": "integer",
- "string": "Id"
+ models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "ir.model", "create",
+ asList(new HashMap() {{
+ put("name", "Custom Model");
+ put("model", "x_custom_model");
+ put("state", "manual");
+ }})
+ ));
+ final Object fields = models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "x_custom_model", "fields_get",
+ emptyList(),
+ new HashMap () {{
+ put("attributes", asList(
+ "string",
+ "help",
+ "type"));
+ }}
+ ));
+
+ .. code-block:: json
+
+ {
+ "create_uid": {
+ "type": "many2one",
+ "string": "Created by"
+ },
+ "create_date": {
+ "type": "datetime",
+ "string": "Created on"
+ },
+ "__last_update": {
+ "type": "datetime",
+ "string": "Last Modified on"
+ },
+ "write_uid": {
+ "type": "many2one",
+ "string": "Last Updated by"
+ },
+ "write_date": {
+ "type": "datetime",
+ "string": "Last Updated on"
+ },
+ "display_name": {
+ "type": "char",
+ "string": "Display Name"
+ },
+ "id": {
+ "type": "integer",
+ "string": "Id"
+ }
}
- }
.. _reference/webservice/inspection/fields:
@@ -1097,143 +1133,145 @@ activated as actual fields on the model.
.. todo:: maybe new-API fields could store constant ``default`` in a new
column, maybe JSON-encoded?
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- id = models.execute_kw(db, uid, password, 'ir.model', 'create', [{
- 'name': "Custom Model",
- 'model': "x_custom",
- 'state': 'manual',
- }])
- models.execute_kw(
- db, uid, password,
- 'ir.model.fields', 'create', [{
- 'model_id': id,
- 'name': 'x_name',
- 'ttype': 'char',
+ .. code-block:: python
+
+ id = models.execute_kw(db, uid, password, 'ir.model', 'create', [{
+ 'name': "Custom Model",
+ 'model': "x_custom",
'state': 'manual',
- 'required': True,
}])
- record_id = models.execute_kw(
- db, uid, password,
- 'x_custom', 'create', [{
- 'x_name': "test record",
- }])
- models.execute_kw(db, uid, password, 'x_custom', 'read', [[record_id]])
-
- .. code-block:: php
-
- $id = $models->execute_kw(
- $db, $uid, $password,
- 'ir.model', 'create', array(array(
- 'name' => "Custom Model",
- 'model' => 'x_custom',
- 'state' => 'manual'
- ))
- );
- $models->execute_kw(
- $db, $uid, $password,
- 'ir.model.fields', 'create', array(array(
- 'model_id' => $id,
- 'name' => 'x_name',
- 'ttype' => 'char',
- 'state' => 'manual',
- 'required' => true
- ))
- );
- $record_id = $models->execute_kw(
- $db, $uid, $password,
- 'x_custom', 'create', array(array(
- 'x_name' => "test record"
- ))
- );
- $models->execute_kw(
- $db, $uid, $password,
- 'x_custom', 'read',
- array(array($record_id)));
-
- .. code-block:: ruby
-
- id = models.execute_kw(
- db, uid, password,
- 'ir.model', 'create', [{
- name: "Custom Model",
- model: "x_custom",
- state: 'manual'
- }])
- models.execute_kw(
- db, uid, password,
- 'ir.model.fields', 'create', [{
- model_id: id,
- name: "x_name",
- ttype: "char",
- state: "manual",
- required: true
- }])
- record_id = models.execute_kw(
- db, uid, password,
- 'x_custom', 'create', [{
- x_name: "test record"
- }])
- models.execute_kw(
- db, uid, password,
- 'x_custom', 'read', [[record_id]])
-
- .. code-block:: java
-
- final Integer id = (Integer)models.execute(
- "execute_kw", asList(
+ models.execute_kw(
db, uid, password,
- "ir.model", "create",
- asList(new HashMap() {{
- put("name", "Custom Model");
- put("model", "x_custom");
- put("state", "manual");
- }})
- ));
- models.execute(
- "execute_kw", asList(
+ 'ir.model.fields', 'create', [{
+ 'model_id': id,
+ 'name': 'x_name',
+ 'ttype': 'char',
+ 'state': 'manual',
+ 'required': True,
+ }])
+ record_id = models.execute_kw(
db, uid, password,
- "ir.model.fields", "create",
- asList(new HashMap() {{
- put("model_id", id);
- put("name", "x_name");
- put("ttype", "char");
- put("state", "manual");
- put("required", true);
- }})
- ));
- final Integer record_id = (Integer)models.execute(
- "execute_kw", asList(
+ 'x_custom', 'create', [{
+ 'x_name': "test record",
+ }])
+ models.execute_kw(db, uid, password, 'x_custom', 'read', [[record_id]])
+
+ .. code-block:: php
+
+ $id = $models->execute_kw(
+ $db, $uid, $password,
+ 'ir.model', 'create', array(array(
+ 'name' => "Custom Model",
+ 'model' => 'x_custom',
+ 'state' => 'manual'
+ ))
+ );
+ $models->execute_kw(
+ $db, $uid, $password,
+ 'ir.model.fields', 'create', array(array(
+ 'model_id' => $id,
+ 'name' => 'x_name',
+ 'ttype' => 'char',
+ 'state' => 'manual',
+ 'required' => true
+ ))
+ );
+ $record_id = $models->execute_kw(
+ $db, $uid, $password,
+ 'x_custom', 'create', array(array(
+ 'x_name' => "test record"
+ ))
+ );
+ $models->execute_kw(
+ $db, $uid, $password,
+ 'x_custom', 'read',
+ array(array($record_id)));
+
+ .. code-block:: ruby
+
+ id = models.execute_kw(
db, uid, password,
- "x_custom", "create",
- asList(new HashMap() {{
- put("x_name", "test record");
- }})
- ));
-
- client.execute(
- "execute_kw", asList(
+ 'ir.model', 'create', [{
+ name: "Custom Model",
+ model: "x_custom",
+ state: 'manual'
+ }])
+ models.execute_kw(
db, uid, password,
- "x_custom", "read",
- asList(asList(record_id))
- ));
+ 'ir.model.fields', 'create', [{
+ model_id: id,
+ name: "x_name",
+ ttype: "char",
+ state: "manual",
+ required: true
+ }])
+ record_id = models.execute_kw(
+ db, uid, password,
+ 'x_custom', 'create', [{
+ x_name: "test record"
+ }])
+ models.execute_kw(
+ db, uid, password,
+ 'x_custom', 'read', [[record_id]])
-.. code-block:: json
+ .. code-block:: java
- [
- {
- "create_uid": [1, "Administrator"],
- "x_name": "test record",
- "__last_update": "2014-11-12 16:32:13",
- "write_uid": [1, "Administrator"],
- "write_date": "2014-11-12 16:32:13",
- "create_date": "2014-11-12 16:32:13",
- "id": 1,
- "display_name": "test record"
- }
- ]
+ final Integer id = (Integer)models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "ir.model", "create",
+ asList(new HashMap() {{
+ put("name", "Custom Model");
+ put("model", "x_custom");
+ put("state", "manual");
+ }})
+ ));
+ models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "ir.model.fields", "create",
+ asList(new HashMap() {{
+ put("model_id", id);
+ put("name", "x_name");
+ put("ttype", "char");
+ put("state", "manual");
+ put("required", true);
+ }})
+ ));
+ final Integer record_id = (Integer)models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "x_custom", "create",
+ asList(new HashMap() {{
+ put("x_name", "test record");
+ }})
+ ));
+
+ client.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "x_custom", "read",
+ asList(asList(record_id))
+ ));
+
+ .. code-block:: json
+
+ [
+ {
+ "create_uid": [1, "Administrator"],
+ "x_name": "test record",
+ "__last_update": "2014-11-12 16:32:13",
+ "write_uid": [1, "Administrator"],
+ "write_date": "2014-11-12 16:32:13",
+ "create_date": "2014-11-12 16:32:13",
+ "id": 1,
+ "display_name": "test record"
+ }
+ ]
Workflow manipulations
----------------------
@@ -1245,116 +1283,117 @@ Instead of using the top-level ``execute_kw``, signals are sent using
Signals are sent to a specific record, and possibly trigger a transition on
the workflow instance associated with the record.
-.. warning:: requires that the ``account`` module be installed
- :class: force-right
+.. container:: doc-aside
-.. rst-class:: switchable
+ .. warning:: requires that the ``account`` module be installed
- .. code-block:: python
+ .. switcher::
- client = models.execute_kw(
- db, uid, password,
- 'res.partner', 'search_read',
- [[('customer', '=', True)]],
- {'limit': 1, 'fields': [
- 'property_account_receivable',
- 'property_payment_term',
- 'property_account_position']
- })[0]
- invoice_id = models.execute_kw(
- db, uid, password,
- 'account.invoice', 'create', [{
- 'partner_id': client['id'],
- 'account_id': client['property_account_receivable'][0],
- 'invoice_line': [(0, False, {'name': "AAA"})]
- }])
+ .. code-block:: python
- models.exec_workflow(
- db, uid, password, 'account.invoice', 'invoice_open', invoice_id)
-
- .. code-block:: php
-
- $client = $models->execute_kw(
- $db, $uid, $password,
- 'res.partner', 'search_read',
- array(array(array('customer', '=', true))),
- array(
- 'limit' => 1,
- 'fields' => array(
+ client = models.execute_kw(
+ db, uid, password,
+ 'res.partner', 'search_read',
+ [[('customer', '=', True)]],
+ {'limit': 1, 'fields': [
'property_account_receivable',
'property_payment_term',
- 'property_account_position'
- )))[0];
- $invoice_id = $models->execute_kw(
- $db, $uid, $password,
- 'account.invoice', 'create', array(array(
- 'partner_id' => $client['id'],
- 'account_id' => $client['property_account_receivable'][0],
- 'invoice_line' => array(array(0, false, array('name' => "AAA")))
- )));
+ 'property_account_position']
+ })[0]
+ invoice_id = models.execute_kw(
+ db, uid, password,
+ 'account.invoice', 'create', [{
+ 'partner_id': client['id'],
+ 'account_id': client['property_account_receivable'][0],
+ 'invoice_line': [(0, False, {'name': "AAA"})]
+ }])
- $models->exec_workflow(
- $db, $uid, $password,
- 'account.invoice', 'invoice_open',
- $invoice_id);
+ models.exec_workflow(
+ db, uid, password, 'account.invoice', 'invoice_open', invoice_id)
- .. code-block:: ruby
+ .. code-block:: php
- client = models.execute_kw(
- db, uid, password,
- 'res.partner', 'search_read',
- [[['customer', '=', true]]],
- {limit: 1, fields: %w(property_account_receivable property_payment_term property_account_position)}
- )[0]
- invoice_id = models.execute_kw(
- db, uid, password,
- 'account.invoice', 'create', [{
- partner_id: client['id'],
- account_id: client['property_account_receivable'][0],
- invoice_line: [[0, false, {name: "AAA"}]]
- }])
+ $client = $models->execute_kw(
+ $db, $uid, $password,
+ 'res.partner', 'search_read',
+ array(array(array('customer', '=', true))),
+ array(
+ 'limit' => 1,
+ 'fields' => array(
+ 'property_account_receivable',
+ 'property_payment_term',
+ 'property_account_position'
+ )))[0];
+ $invoice_id = $models->execute_kw(
+ $db, $uid, $password,
+ 'account.invoice', 'create', array(array(
+ 'partner_id' => $client['id'],
+ 'account_id' => $client['property_account_receivable'][0],
+ 'invoice_line' => array(array(0, false, array('name' => "AAA")))
+ )));
- models.exec_workflow(
- db, uid, password,
- 'account.invoice', 'invoice_open', invoice_id)
+ $models->exec_workflow(
+ $db, $uid, $password,
+ 'account.invoice', 'invoice_open',
+ $invoice_id);
- .. code-block:: java
+ .. code-block:: ruby
- final Map c = (Map)
- ((Object[])models.execute("execute_kw", asList(
- db, uid, password,
- "res.partner", "search_read",
- asList(
+ client = models.execute_kw(
+ db, uid, password,
+ 'res.partner', 'search_read',
+ [[['customer', '=', true]]],
+ {limit: 1, fields: %w(property_account_receivable property_payment_term property_account_position)}
+ )[0]
+ invoice_id = models.execute_kw(
+ db, uid, password,
+ 'account.invoice', 'create', [{
+ partner_id: client['id'],
+ account_id: client['property_account_receivable'][0],
+ invoice_line: [[0, false, {name: "AAA"}]]
+ }])
+
+ models.exec_workflow(
+ db, uid, password,
+ 'account.invoice', 'invoice_open', invoice_id)
+
+ .. code-block:: java
+
+ final Map c = (Map)
+ ((Object[])models.execute("execute_kw", asList(
+ db, uid, password,
+ "res.partner", "search_read",
asList(
- asList("customer", "=", true))),
- new HashMap() {{
- put("limit", 1);
- put("fields", asList(
- "property_account_receivable",
- "property_payment_term",
- "property_account_position"
- ));
- }}
- )))[0];
- final Integer invoice_id = (Integer)models.execute(
- "execute_kw", asList(
- db, uid, password,
- "account.invoice", "create",
- asList(new HashMap() {{
- put("partner_id", c.get("id"));
- put("account_id", ((Object[])c.get("property_account_receivable"))[0]);
- put("invoice_line", asList(
- asList(0, false, new HashMap() {{
- put("name", "AAA");
- }})
- ));
- }})
- ));
+ asList(
+ asList("customer", "=", true))),
+ new HashMap() {{
+ put("limit", 1);
+ put("fields", asList(
+ "property_account_receivable",
+ "property_payment_term",
+ "property_account_position"
+ ));
+ }}
+ )))[0];
+ final Integer invoice_id = (Integer)models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "account.invoice", "create",
+ asList(new HashMap() {{
+ put("partner_id", c.get("id"));
+ put("account_id", ((Object[])c.get("property_account_receivable"))[0]);
+ put("invoice_line", asList(
+ asList(0, false, new HashMap() {{
+ put("name", "AAA");
+ }})
+ ));
+ }})
+ ));
- models.execute(
- "exec_workflow", asList(
- db, uid, password,
- "account.invoice", "invoice_open", invoice_id));
+ models.execute(
+ "exec_workflow", asList(
+ db, uid, password,
+ "account.invoice", "invoice_open", invoice_id));
Report printing
---------------
@@ -1375,70 +1414,71 @@ Reports can be printed over RPC with the following information:
* the name of the report (``report_name``)
* the ids of the records to include in the report
-.. rst-class:: switchable
+.. container:: doc-aside
- .. code-block:: python
+ .. switcher::
- invoice_ids = models.execute_kw(
- db, uid, password, 'account.invoice', 'search',
- [[('type', '=', 'out_invoice'), ('state', '=', 'open')]])
- report = xmlrpclib.ServerProxy('{}/xmlrpc/2/report'.format(url))
- result = report.render_report(
- db, uid, password, 'account.report_invoice', invoice_ids)
- report_data = result['result'].decode('base64')
+ .. code-block:: python
- .. code-block:: php
+ invoice_ids = models.execute_kw(
+ db, uid, password, 'account.invoice', 'search',
+ [[('type', '=', 'out_invoice'), ('state', '=', 'open')]])
+ report = xmlrpclib.ServerProxy('{}/xmlrpc/2/report'.format(url))
+ result = report.render_report(
+ db, uid, password, 'account.report_invoice', invoice_ids)
+ report_data = result['result'].decode('base64')
- $invoice_ids = $models->execute_kw(
- $db, $uid, $password,
- 'account.invoice', 'search',
- array(array(array('type', '=', 'out_invoice'),
- array('state', '=', 'open'))));
- $report = ripcord::client("$url/xmlrpc/2/report");
- $result = $report->render_report(
- $db, $uid, $password,
- 'account.report_invoice', $invoice_ids);
- $report_data = base64_decode($result['result']);
+ .. code-block:: php
- .. code-block:: ruby
+ $invoice_ids = $models->execute_kw(
+ $db, $uid, $password,
+ 'account.invoice', 'search',
+ array(array(array('type', '=', 'out_invoice'),
+ array('state', '=', 'open'))));
+ $report = ripcord::client("$url/xmlrpc/2/report");
+ $result = $report->render_report(
+ $db, $uid, $password,
+ 'account.report_invoice', $invoice_ids);
+ $report_data = base64_decode($result['result']);
- require 'base64'
- invoice_ids = models.execute_kw(
- db, uid, password,
- 'account.invoice', 'search',
- [[['type', '=', 'out_invoice'], ['state', '=', 'open']]])
- report = XMLRPC::Client.new2("#{url}/xmlrpc/2/report").proxy
- result = report.render_report(
- db, uid, password,
- 'account.report_invoice', invoice_ids)
- report_data = Base64.decode64(result['result'])
+ .. code-block:: ruby
- .. code-block:: java
-
- final Object[] invoice_ids = (Object[])models.execute(
- "execute_kw", asList(
+ require 'base64'
+ invoice_ids = models.execute_kw(
db, uid, password,
- "account.invoice", "search",
- asList(asList(
- asList("type", "=", "out_invoice"),
- asList("state", "=", "open")))
- ));
- final XmlRpcClientConfigImpl report_config = new XmlRpcClientConfigImpl();
- report_config.setServerURL(
- new URL(String.format("%s/xmlrpc/2/report", url)));
- final Map result = (Map)client.execute(
- report_config, "render_report", asList(
+ 'account.invoice', 'search',
+ [[['type', '=', 'out_invoice'], ['state', '=', 'open']]])
+ report = XMLRPC::Client.new2("#{url}/xmlrpc/2/report").proxy
+ result = report.render_report(
db, uid, password,
- "account.report_invoice",
- invoice_ids));
- final byte[] report_data = DatatypeConverter.parseBase64Binary(
- (String)result.get("result"));
+ 'account.report_invoice', invoice_ids)
+ report_data = Base64.decode64(result['result'])
-.. note::
- :class: force-right
+ .. code-block:: java
- the report is sent as PDF binary data encoded in base64_, it must be
- decoded and may need to be saved to disk before use
+ final Object[] invoice_ids = (Object[])models.execute(
+ "execute_kw", asList(
+ db, uid, password,
+ "account.invoice", "search",
+ asList(asList(
+ asList("type", "=", "out_invoice"),
+ asList("state", "=", "open")))
+ ));
+ final XmlRpcClientConfigImpl report_config = new XmlRpcClientConfigImpl();
+ report_config.setServerURL(
+ new URL(String.format("%s/xmlrpc/2/report", url)));
+ final Map result = (Map)client.execute(
+ report_config, "render_report", asList(
+ db, uid, password,
+ "account.report_invoice",
+ invoice_ids));
+ final byte[] report_data = DatatypeConverter.parseBase64Binary(
+ (String)result.get("result"));
+
+ .. note::
+
+ the report is sent as PDF binary data encoded in base64_, it must be
+ decoded and may need to be saved to disk before use
.. _PostgreSQL: http://www.postgresql.org
.. _XML-RPC: http://en.wikipedia.org/wiki/XML-RPC
diff --git a/doc/business.rst b/doc/business.rst
index 02a955c2efe..4847aa345bf 100644
--- a/doc/business.rst
+++ b/doc/business.rst
@@ -5,5 +5,5 @@ Business Mementoes
.. toctree::
Accounting Memento (US GAAP)
- Double-Entry Inventory
- Inventory Valuations
+ Double-Entry Inventory
+ Inventory Valuations
diff --git a/doc/conf.py b/doc/conf.py
index 91fd81bf07b..8ae57282314 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -8,14 +8,14 @@ import sphinx
DIR = os.path.dirname(__file__)
sys.path.append(
os.path.abspath(
- os.path.join(DIR, '_themes')))
+ os.path.join(DIR, '_extensions')))
# autodoc
sys.path.append(os.path.abspath(os.path.join(DIR, '..')))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-needs_sphinx = '1.1'
+needs_sphinx = '1.2'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
@@ -24,13 +24,13 @@ extensions = [
'sphinx.ext.todo',
'sphinx.ext.autodoc',
'sphinx.ext.intersphinx',
- 'odoodoc',
+ 'sphinx.ext.linkcode',
+ 'github_link',
+ 'odoo',
+ 'html_domain',
+ 'exercise_admonition',
'patchqueue'
]
-if sphinx.__version__.split('.') >= ['1', '2']:
- # linkcode is only available from Sphinx 1.2
- extensions.insert(0, 'sphinx.ext.linkcode')
-
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
@@ -91,7 +91,15 @@ pygments_style = 'odoo'
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'odoodoc'
+html_theme = 'odoo'
+html_translator_class = 'odoo.translator.BootstrapTranslator'
+
+odoo_cover_default = 'banners/installing_odoo.jpg'
+odoo_cover_external = {
+ 'https://odoo.com/documentation/functional/accounting.html' : 'banners/m_accounting.jpg',
+ 'https://odoo.com/documentation/functional/double-entry.html' : 'banners/m_1.jpg',
+ 'https://odoo.com/documentation/functional/valuation.html' : 'banners/m_2.jpg',
+}
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -99,7 +107,7 @@ html_theme = 'odoodoc'
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-html_theme_path = ['_themes']
+html_theme_path = ['_extensions']
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
@@ -122,9 +130,7 @@ html_theme_path = ['_themes']
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
-html_style = "odoo.css"
-
-html_add_permalinks = False
+html_add_permalinks = u''
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
@@ -185,6 +191,11 @@ intersphinx_mapping = {
github_user = 'odoo'
github_project = 'odoo'
+# monkeypatch PHP lexer to not require `::
+`jsonrpclib `_::
import jsonrpclib
diff --git a/doc/howtos/theme_tutorial_assets/img/Intro.jpg b/doc/howtos/theme_tutorial_assets/img/Intro.jpg
new file mode 100644
index 00000000000..1061e96620d
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/Intro.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/after-menu.png b/doc/howtos/theme_tutorial_assets/img/after-menu.png
new file mode 100755
index 00000000000..5608b235669
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/after-menu.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/cms.jpg b/doc/howtos/theme_tutorial_assets/img/cms.jpg
new file mode 100755
index 00000000000..006ec697005
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/cms.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/def_structure.jpg b/doc/howtos/theme_tutorial_assets/img/def_structure.jpg
new file mode 100644
index 00000000000..70f1e6828cf
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/def_structure.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/folder.jpg b/doc/howtos/theme_tutorial_assets/img/folder.jpg
new file mode 100755
index 00000000000..fbd790f2536
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/folder.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/functionalities.jpg b/doc/howtos/theme_tutorial_assets/img/functionalities.jpg
new file mode 100755
index 00000000000..dfe9b8d62d8
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/functionalities.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/page.jpg b/doc/howtos/theme_tutorial_assets/img/page.jpg
new file mode 100755
index 00000000000..50558c37a46
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/page.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/page_structure.jpg b/doc/howtos/theme_tutorial_assets/img/page_structure.jpg
new file mode 100755
index 00000000000..2170f65d0b2
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/page_structure.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/restart.png b/doc/howtos/theme_tutorial_assets/img/restart.png
new file mode 100644
index 00000000000..c39a4fa7e80
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/restart.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/seo_promote.png b/doc/howtos/theme_tutorial_assets/img/seo_promote.png
new file mode 100644
index 00000000000..750fe259dd9
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/seo_promote.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/seo_snippet_good.png b/doc/howtos/theme_tutorial_assets/img/seo_snippet_good.png
new file mode 100644
index 00000000000..e042fbc0648
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/seo_snippet_good.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/seo_snippet_wrong.png b/doc/howtos/theme_tutorial_assets/img/seo_snippet_wrong.png
new file mode 100644
index 00000000000..0363a754a70
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/seo_snippet_wrong.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/services_page_menu.png b/doc/howtos/theme_tutorial_assets/img/services_page_menu.png
new file mode 100755
index 00000000000..4ea2a426a86
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/services_page_menu.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/services_page_nostyle.png b/doc/howtos/theme_tutorial_assets/img/services_page_nostyle.png
new file mode 100755
index 00000000000..7ebc937e0fb
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/services_page_nostyle.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/services_page_styled.png b/doc/howtos/theme_tutorial_assets/img/services_page_styled.png
new file mode 100755
index 00000000000..6d5646bdcd1
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/services_page_styled.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/snippet.jpg b/doc/howtos/theme_tutorial_assets/img/snippet.jpg
new file mode 100755
index 00000000000..0ab285bae9a
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/snippet.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/snippet_bar.png b/doc/howtos/theme_tutorial_assets/img/snippet_bar.png
new file mode 100755
index 00000000000..07817746ef8
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/snippet_bar.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/snippet_custom_method.png b/doc/howtos/theme_tutorial_assets/img/snippet_custom_method.png
new file mode 100644
index 00000000000..ab7dcd46b57
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/snippet_custom_method.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/snippet_default.png b/doc/howtos/theme_tutorial_assets/img/snippet_default.png
new file mode 100755
index 00000000000..62de684f59a
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/snippet_default.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/snippet_options.png b/doc/howtos/theme_tutorial_assets/img/snippet_options.png
new file mode 100755
index 00000000000..5f72f15fe6a
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/snippet_options.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/snippet_options2.png b/doc/howtos/theme_tutorial_assets/img/snippet_options2.png
new file mode 100755
index 00000000000..dcc1113633b
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/snippet_options2.png differ
diff --git a/doc/howtos/theme_tutorial_assets/img/styles.jpg b/doc/howtos/theme_tutorial_assets/img/styles.jpg
new file mode 100755
index 00000000000..02f44240b80
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/styles.jpg differ
diff --git a/doc/howtos/theme_tutorial_assets/img/upgrade_module.png b/doc/howtos/theme_tutorial_assets/img/upgrade_module.png
new file mode 100644
index 00000000000..ffeca7d4fc5
Binary files /dev/null and b/doc/howtos/theme_tutorial_assets/img/upgrade_module.png differ
diff --git a/doc/howtos/themes.rst b/doc/howtos/themes.rst
index dbc59f6392d..9aa83478ba9 100644
--- a/doc/howtos/themes.rst
+++ b/doc/howtos/themes.rst
@@ -1,485 +1,973 @@
-.. highlight:: xml
+:banner: banners/build_a_theme.jpg
-===============
-Building Themes
-===============
+=====================
+Theme Tutorial
+=====================
-Basic set up
-============
+.. rst-class:: lead
-Create a basic theme module with :command:`odoo.py scaffold` and the ``theme``
-template: from the root Odoo folder, use
+Odoo celebrates freedom. Freedom for the designer to go further and
+freedom for the user to customize everything according to their needs.
-.. code-block:: console
+Ready to create your own theme? Great. Here some things you should know before you begin. This tutorial is a guide to creating an Odoo theme.
- $ ./odoo.py scaffold -t theme "Dummy Theme" addons
+.. image:: theme_tutorial_assets/img/Intro.jpg
-this should create a new folder ``dummy_theme`` in the ``addons`` directory
-with the structure:
+.. warning::
-.. code-block:: text
+ This tutorial requires having installed Odoo v8.0 and the Theme Support Engine (website_less) module. https://www.odoo.com/apps/8.0/website_less/
- addons/dummy_theme
- |-- __init__.py
- |-- __openerp__.py
- |-- static
- | `-- style
- | `-- custom.less
- `-- views
- |-- options.xml
- |-- pages.xml
- `-- snippets.xml
-``static/style`` contains your stylesheet(s), ``views`` contains the various
-XML files describing the theme and theme features to Odoo.
+An introduction for web designers
+=================================
-Static Page
------------
+If you are a web designer using Odoo for the first time, you are in the right place.
+This introduction will outline the basics of Odoo theme creation.
-Creating a new template
-'''''''''''''''''''''''
+.. note::
-Create a new file :file:`odoo/addons/theme_dummy/views/pages.xml` and open it.
+ Odoo’s team has created a framework that’s powerful and easy to use. There’s no need to know special syntaxes to use this set of tools.
-In odoo, a page means a new template. You don't need special skills, simply
-copy paste the lines::
+From common CMS to Odoo
+-----------------------
-
-
-
-
-
-
+.. note::
-Comment the lines about ``options.xml`` and ``pages.xml`` in ``__openerp__.py``.
+ If you always think and work in the same way, you’ll probably get the same results. If you want something completely new, then try something different.
-Run the server and update the theme (``./odoo.py -u dummy_theme``), then
-install the theme in the settings menu.
+..
-Go to ``http://localhost:8069/page/hello`` feel the hit.
+ Where is my header.php file?
-Editing content on a page
-'''''''''''''''''''''''''
+This is usually the first question from a web designer used to working with Wordpress or Joomla and coming to Odoo for the first time.
-You can now add your content! You should always use the Bootstrap structure as
-below::
+.. container:: col-sm-4
-
-
-
-
-
-
-
This is Your Content
-
Isn't amazing to edit everything inline?
-
-
-
-
-
-
+ .. image:: theme_tutorial_assets/img/cms.jpg
+
+.. container:: col-sm-7
+
+ Indeed, when using common CMSs, you have to code several files (like header.php, page.php, post.php, etc.) in order to create a basic structure for your website. With those systems, this base structure acts as a design foundation that you have to update over time to ensure compatibility within your CMS. So, even after you have spent hours coding the files, you have not even started on the design yet.
+
+ This **does not** apply to creating Odoo themes.
+
+
+.. note::
+ :class: col-sm-12
+
+ We think that theme design should be simple (and powerful). When we created our Website Builder, we decided to start from scratch instead of relying on what already existed. This approach gave us the freedom to focus on the things that are really important for designers: styles, content and the logic behind them. No more struggling with technical stuff.
+
+Odoo default theme structure
+----------------------------
+
+.. container:: col-sm-8
+
+ Odoo comes with a default theme structure.
+ It is a very basic “theme” that provides minimal structure and layout. When you create a new theme, you are actually extending this.
+ Indeed it’s always enabled in your setup and it acts exactly like the CMS’s base structure we mentioned above, except that you don’t have to create or maintain it.
+ It will upgrade automatically within your Odoo installation and, since it is included in the Website Builder module, everything is smoothly integrated by default.
+
+ As a result, you are totally free to focus on design while this structure does the job of providing integrations and functionality.
+
+.. container:: col-sm-4
+
+ .. image:: theme_tutorial_assets/img/def_structure.jpg
+
+.. container:: col-md-6
+
+ **Main features:**
+
+ * Basic layouts for pages, blog and eCommerce
+ * Website Builder integration
+ * Basic Snippets
+ * Automatic Less/Sass compiling
+ * Automatic Js and CSS minification and combination
+
+.. container:: col-md-6
+
+ **Main technologies:**
+
+ * Twitter Bootstrap
+ * jQuery
+ * jQuery UI
+ * underscore.js
+
+Thinking "modular"
+==================
+
+An Odoo theme is not a folder containing HTML or PHP files, it’s a modular framework written in XML. Never worked with XML files before? Don’t worry, after following the tutorial, you’ll be able to create your first theme with only basic knowledge of HTML.
+
+Using classical web design workflows, you usually code the layout of the entire page. The result of this is a “static” web page. You can update the content, of course, but your client will need you to work on making even basic changes.
+
+Creating themes for Odoo is a total change of perspective. Instead of defining the complete layout for a page, you can create blocks (snippets) at let the user choose where to “drag&drop” them, creating the page layout on their own.
+We call this modular design.
+
+Imagine an Odoo theme as a “list” of elements and options that you have to create and style.
+As a designer, your goal is to style these elements in order to achieve a wonderful result, regardless of where the end user chooses to place them.
+
+Let’s take a tour of our “list” elements:
+
+.. row
+
+.. figure:: theme_tutorial_assets/img/snippet.jpg
+ :figclass: col-sm-6
+
+ Snippets (or building-blocks)
+
+ A piece of HTML code. The user will drag&drop, modify and combine them using our built-in Website Builder interface. You can define sets of options and styles for each snippet. The user will choose from them according to their needs.
+
+.. figure:: theme_tutorial_assets/img/page.jpg
+ :figclass: col-sm-6
+
+ Pages
+
+ These are normal web pages, except that they will be editable by the final user and that you can define an empty area that the user can “fill” by dragging snippets into it.
+
+.. /row
+.. raw:: html
+
+
+
+.. figure:: theme_tutorial_assets/img/styles.jpg
+ :figclass: col-sm-6
+
+ Styles
+
+ Styles are defined using standard CSS files (or Less/Sass). You can define a style as **default** or **optional**. The default styles are always active in your theme, the optional styles can be enabled or disabled by the user.
+
+.. figure:: theme_tutorial_assets/img/functionalities.jpg
+ :figclass: col-sm-6
+
+ Functionalities
+
+ Thanks to Odoo’s modularity, everything can be personalized even more. This means there are endless possibilities for your creativity. Adding functionalities is easy and it’s simple to provide the end user with customizable options.
+
+.. /row
+
+Odoo's XML files, an overview
+-----------------------------
+
+Any Odoo XML file starts with encoding specifications.
+After that, you have to write your code inside a ```` tag, placed into an ```` tag.
+
+.. code-block:: xml
+
+ [XML]
+
+
+
+ ## YOUR CODE HERE
+
+
+
+Almost every element and option that you create has to be placed inside a ```` tag, like in this example.
+
+.. code-block:: xml
+
+ [XML]
+
+ This is an HTML block
+ And this is a subtitle
-Adding new item in the menu
-'''''''''''''''''''''''''''
+.. important::
-Adding these few more lines will put the new page in your menu::
+ don't misunderstand what ``template`` means. A template tag only
+ defines a piece of html code or options - but it does not
+ necessarily coincide with a visual arrangement of elements.
-
+The previous code defines a title, but it will not be displayed
+anywhere because that *template* is not associated with any part of
+the **Odoo default structure**. In order to do that you can use
+**xpath**, **qWeb** or a combination of both. Keep reading the
+tutorial to learn to how properly extend it with your own code.
-Congrats! It's online! Now drag and drop some snippets on the page and let's
-style!
+Keep reading the tutorial to learn to how properly extend it with your own code.
-Pimp Your Theme
----------------
+Update your theme
+-----------------
-Easy styling with less
-''''''''''''''''''''''
+.. container:: col-sm-6
-In ``odoo/addons/theme_dummy/static`` create a new folder and name it
-``style``. In the new folder ``odoo/addons/theme_dummy/static/style`` create a
-file and name it ``custom.less``. Open ``custom.less`` in the text editor and
-modify these lines as below:
+ Since XML files are only loaded when you install the theme, you will have to force reloading every time you make changes on an xml file.
+
+ To do that, click on the Upgrade button in the module’s page.
+
+ .. image:: theme_tutorial_assets/img/restart.png
+
+.. container:: col-sm-5
+
+ .. image:: theme_tutorial_assets/img/upgrade_module.png
-.. code-block:: css
- h1 {
- color: #215487;
- }
- span {
- border: 2px solid black;
- background-color: #eee;
- }
+Create a theme module
+======================
-Compile your file (http://lesscss.org/usage/#command-line-usage) to get the
-``custom.css`` file.
+Odoo’s themes are packaged like modules. Even if you are designing a very simple website for your company or client, you need to package the theme like an Odoo module.
-Add this asset to your template in ``page.xml``::
+``main folder``
+ Create a folder and name it like this: ``theme_`` followed by your
+ theme's name.
-
-
-
-
-
+``__openerp__.py``
+ Create an empty document and save it to your folder as
+ ``__openerp__.py``. This will contain the configuration info for
+ your theme.
-Refresh the page and feel the hit.
+``__init__.py``
+ Create another empty file and name it ``__init__.py``. It's a
+ mandatory system file. Create and leave it blank.
-Get the most of the dom
-'''''''''''''''''''''''
+``view`` and ``static`` folders
+ Create them in the main folder. In ``view`` you'll place your xml
+ files that define your snippets, your pages and your
+ options. ``static`` folder is the right place for your style ,
+ images and custom js code.
-Right-Click, inspect element. You can go deeper by styling the main layout
-container. Here we try with the 'wrapwrap' id.
+.. important::
-.. code-block:: css
+ Use two underscore characters at the beginning
+ and two at the end of openerp and init file names.
- #wrapwrap {
- background-color: #222;
- width: 80%;
- margin: 0 auto;
- }
+The final result should be something like this:
-Easy layout with bootstrap
-''''''''''''''''''''''''''
+.. image:: theme_tutorial_assets/img/folder.jpg
-Open :file:`odoo/addons/theme_dummy/views/pages.xml` and add a new section::
+Edit ``__openerp__.py``
+-----------------------
-
-
-
-
-
-
BLUE it!
-
-
-
GREEN THAT!
-
-
-
-
-
-Refresh the page and check how it looks.
-
-The background of the alert component is the default Bootstrap primary color.
-The two other div your created have no custom styles applied yet. Open
-:file:`odoo/addons/theme_dummy/static/style/custom.less` and add these lines:
-
-.. code-block:: css
-
- @brand-primary: #1abc9c;
- @color-blue: #3498db;
- @color-green: #2ecc71;
-
- .bg-blue { background: @color-blue; }
- .bg-green { background: @color-green; }
-
- .h2 { color: white; }
-
-As you see, the default primary has changed and your new colors are shining!
-
-Build Your First Snippet
-------------------------
-
-Setting up __openerp__.py
-'''''''''''''''''''''''''
-
-Open ``__openerp__.py`` and add a new line as below:
+Open the ``__openerp__.py`` you created and copy/paste the following:
.. code-block:: python
- {
- 'name': 'Dummy Theme',
- 'description': 'Dummy Theme',
- 'category': 'Website',
- 'version': '1.0',
- 'author': 'OpenERP SA',
- 'depends': ['website'],
- 'data': [
- 'views/snippets.xml',
- ],
- 'application': True,
- }
+ {
+ 'name':'Tutorial theme',
+ 'description': 'A description for your theme.',
+ 'version':'1.0',
+ 'author':'Your name',
-In ``odoo/addons/theme_learn/views`` create a new xml file, name it
-``snippets.xml`` and open it in a text editor
+ 'data': [
+ ],
+ 'category': 'Theme/Creative',
+ 'depends': ['website', 'website_less'],
+ }
-Add your snippet in the menu
-''''''''''''''''''''''''''''
+Replace the first four property’s values with anything you like.
+These values will be used to identify your new theme in Odoo’s backend.
-Before typing your html code, you need to locate it in the WEBb. drop-down
-menu. In this case, we will add it at the end of the Structure section::
+The ``data`` property will contain the xml files list. Right now it’s empty, but we will add any new files created.
-
-
+``application: True`` is mandatory.
+
+``category`` defines your module category (always “Theme”) and, after a slash, the subcategory. You can use one subcategory from the Odoo Apps categories list. (https://www.odoo.com/apps/themes)
+
+
+``depends`` specifies the modules needed by our theme to work properly. For our tutorial theme, we only need website and website_less. If you need blogging or eCommerce features as well, you have to add those modules too.
+
+.. code-block:: python
+
+ ...
+ 'depends': ['website', 'website_blog', 'sale'],
+ ...
+
+
+
+Installing your theme
+---------------------
+
+To install your theme you just place your theme folder inside "addons"
+To install your theme, you just place your theme folder inside addons in your Odoo installation.
+
+After that, navigate to the Settings page, look for your theme and click on the install button.
+
+Structure of an Odoo page
+=========================
+
+An Odoo page is the visual result of a combination of 2 kind of elements, **cross-pages** and **unique**.
+By default, Odoo provides you with a **Header** and a **Footer** (cross-pages) and a unique main element that contains the content that makes your page unique.
+
+.. note::
+
+ Cross-pages elements will be the same on every page. Unique elements are related to a specific page only.
+
+.. image:: theme_tutorial_assets/img/page_structure.jpg
+
+To inspect the default layout, simply create a new page using the
+Website Builder. Click on :menuselection:`Content --> New Page` and
+add a page name. Inspect the page using your browser.
+
+.. code-block:: html
+
+
+
+
+
+
+
+Extend the default Header
+-------------------------
+
+By default, Odoo header contains a responsive navigation menu and the company’s logo. You can easily add new elements or style the existing one.
+
+To do so, create a **layout.xml** file in your **views** folder folder and add the default Odoo xml markup.
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+Create a new template into the ```` tag, copy-pasting the following
+code.
+
+.. code-block:: xml
+
+
+
-Now open a new div, do not give it any id or classes. It will contain your
-snippet::
+The first xpath will add the id ``my_header`` to the header. It’s the best option if you want to
+target css rules to that element and avoid these affecting other content on the page.
-
-
-
-
+.. warning::
-A thumbnail is also needed to create a more attractive link in the menu. You
-can use labels to focus on your themes snippets. Simply add a new div with
-the class ``oe_snippet_thumbnail`` and add your thumbnail image (100x79px)::
+ Be careful replacing default elements attributes. As your theme will extend the default one,
+ your changes will take priority in any future Odoo’s update.
-
-
-
-
-
SNIP IT!
-
-
-
+The second xpath will add a welcome message just after the navigation menu.
-And voila! Your new snippet is now ready to use. Just drag and drop it on your
-page to see it in action.
+The last step is to add layout.xml to the list of xml files used by
+the theme. To do that, edit your ``__openerp__.py`` file like this
-The snippet body
-''''''''''''''''
+.. code-block:: python
-A snippet has to be in a section with the class ``oe_snippet_body`` to work
-correctly. As Odoo use the Bootstrap framework, you have use containers and
-rows to hold your content. Please refer the the Bootstrap documentation::
+ 'data': [ 'views/layout.xml' ],
-
-
-
-
-
SNIP IT!
-
+Update your theme
-
-
-
+.. image:: theme_tutorial_assets/img/restart.png
-Inside your fresh new row, add some bootstraped contents::
+Great! We successfully added an id to the
+header and an element after the navigation menu. These changes will be
+applied to each page of the website.
-
-
A great Title
-
And a great subtitle too
-
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
-
+.. image:: theme_tutorial_assets/img/after-menu.png
+ :class: shadow-0
+Create a specific page layout
+=============================
-Adding images to your snippet
-'''''''''''''''''''''''''''''
+Imagine that we want to create a specific layout for a Services page.
+For this page, we need to add a list of services to the top and give the client the possibility of setting the rest of the page’s layout using snippets.
-You can easely add images in your snippets simply by setting up css
-backgrounds images.
+Inside your *views* folder, create a **pages.xml** file and add the
+default Odoo markup. Inside ```` create a ```` tag, set the
+``page`` attribute to ``True`` and add your code into it.
-Put your images in ``odoo/addons/theme_dummy/static/img``, or in sub-folders
-if needed. Open :file:`odoo/addons/theme_dummy/static/style/custom.less`, add
-these lines
+.. code-block:: xml
-.. code-block:: css
+
+
+
+
+
+ Our Services
+
+ - Cloud Hosting
+ - Support
+ - Unlimited space
+
+
+
+
- @img-01: url("../img/img-boy.png");
- .dummy-boy { background-image: @img-01; }
+The page title will be the template ID. In our case *Services* (from ``website.services``)
- @img-02: url("../img/img-girl.png");
- .dummy-girl { background-image: @img-02; }
+We successfully created a new page layout, but we haven't told the
+system **how to use it**. To do that, we can use **QWeb**. Wrap the
+html code into a ```` tag, like in this example.
-Add also the ``width`` and the ``height`` css attributes to theses new classes.
+.. code-block:: xml
-In :file:`odoo/addons/theme_dummy/views/pages.xml` change the correspondant
-lines as below::
+
+
+
+
+
+
Our Services
+
+ - Cloud Hosting
+ - Support
+ - Unlimited space
+
+
+
+
+
-
-
-
A great Title, prmize
-
And a great subtilte too
-
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
-
-
-
-
+Using ```` we will extend the Odoo
+default page layout with our code.
-Your new snippet is now ready to use. Just drag and drop it on your page to
-see it in action.
+As you can see, we wrapped our code into two ````, one with ID ``wrap`` and the other one with class ``container``. This is to provide a minimal layout.
-Advanced Customization
-======================
+The next step is to add an empty area that the user
+can fill with snippets. To archive this, just create a ``div`` with
+``oe_structure`` class just before closing the ``div#wrap`` element.
-Defining Your Theme Options
----------------------------
+.. code-block:: xml
-Understanding XPath
-'''''''''''''''''''
+
+
+
-As your stylesheets are running on the whole website, giving more option to
-your snippets and applying them independently will push your design
-forward. In ``odoo/addons/theme_dummy/views/`` create a new file, name it
-``options.xml`` and add these lines::
-
-
-
-
-
-
-Explain xpath
-"""""""""""""
-
-.. TODO:: syntax not correct (see website examples)
-
-Your option menu is now correctly set in the database, you can create an new
-dropdown menu.
-
-Let's say yout want three options which will change the text color and the
-background.
-
-In option.xml, add these lines inside the xpath::
-
- YOUR OPTION 1
-