diff --git a/addons/web/doc/Makefile b/addons/web/doc/Makefile deleted file mode 100644 index c1eff186583..00000000000 --- a/addons/web/doc/Makefile +++ /dev/null @@ -1,154 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -q -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = _build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . - -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - sed -i '/-99999/d' _build/dirhtml/_static/flasky.css - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenERPTechnicalDocumentation.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenERPTechnicalDocumentation.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/OpenERPTechnicalDocumentation" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenERPTechnicalDocumentation" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/addons/web/doc/_static/openerp.png b/addons/web/doc/_static/openerp.png deleted file mode 100644 index caa1b21d8d7..00000000000 Binary files a/addons/web/doc/_static/openerp.png and /dev/null differ diff --git a/addons/web/doc/_templates/sidebarintro.html b/addons/web/doc/_templates/sidebarintro.html deleted file mode 100644 index bbe4c472607..00000000000 --- a/addons/web/doc/_templates/sidebarintro.html +++ /dev/null @@ -1,16 +0,0 @@ - - -

Other Docs

- - -

Useful Links

- diff --git a/addons/web/doc/_templates/sidebarlogo.html b/addons/web/doc/_templates/sidebarlogo.html deleted file mode 100644 index de6e3e5c851..00000000000 --- a/addons/web/doc/_templates/sidebarlogo.html +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/addons/web/doc/_themes/LICENSE b/addons/web/doc/_themes/LICENSE deleted file mode 100644 index 8daab7ee6ef..00000000000 --- a/addons/web/doc/_themes/LICENSE +++ /dev/null @@ -1,37 +0,0 @@ -Copyright (c) 2010 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms of the theme, with or -without modification, are permitted provided that the following conditions -are met: - -* Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - -* The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -We kindly ask you to only use these themes in an unmodified manner just -for Flask and Flask-related products, not for unrelated projects. If you -like the visual style and want to use it for your own projects, please -consider making some larger changes to the themes (such as changing -font faces, sizes, colors or margins). - -THIS THEME IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS THEME, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/addons/web/doc/_themes/README b/addons/web/doc/_themes/README deleted file mode 100644 index b3292bdff8e..00000000000 --- a/addons/web/doc/_themes/README +++ /dev/null @@ -1,31 +0,0 @@ -Flask Sphinx Styles -=================== - -This repository contains sphinx styles for Flask and Flask related -projects. To use this style in your Sphinx documentation, follow -this guide: - -1. put this folder as _themes into your docs folder. Alternatively - you can also use git submodules to check out the contents there. -2. add this to your conf.py: - - sys.path.append(os.path.abspath('_themes')) - html_theme_path = ['_themes'] - html_theme = 'flask' - -The following themes exist: - -- 'flask' - the standard flask documentation theme for large - projects -- 'flask_small' - small one-page theme. Intended to be used by - very small addon libraries for flask. - -The following options exist for the flask_small theme: - - [options] - index_logo = '' filename of a picture in _static - to be used as replacement for the - h1 in the index.rst file. - index_logo_height = 120px height of the index logo - github_fork = '' repository name on github for the - "fork me" badge diff --git a/addons/web/doc/_themes/flask/layout.html b/addons/web/doc/_themes/flask/layout.html deleted file mode 100644 index ad08eccd38d..00000000000 --- a/addons/web/doc/_themes/flask/layout.html +++ /dev/null @@ -1,25 +0,0 @@ -{%- extends "basic/layout.html" %} -{%- block extrahead %} - {{ super() }} - {% if theme_touch_icon %} - - {% endif %} - -{% endblock %} -{%- block relbar2 %}{% endblock %} -{% block header %} - {{ super() }} - {% if pagename == 'index' %} -
- {% endif %} -{% endblock %} -{%- block footer %} - - {% if pagename == 'index' %} -
- {% endif %} -{%- endblock %} diff --git a/addons/web/doc/_themes/flask/relations.html b/addons/web/doc/_themes/flask/relations.html deleted file mode 100644 index 3bbcde85bb4..00000000000 --- a/addons/web/doc/_themes/flask/relations.html +++ /dev/null @@ -1,19 +0,0 @@ -

Related Topics

- diff --git a/addons/web/doc/_themes/flask/static/flasky.css_t b/addons/web/doc/_themes/flask/static/flasky.css_t deleted file mode 100644 index 9fec3190fc9..00000000000 --- a/addons/web/doc/_themes/flask/static/flasky.css_t +++ /dev/null @@ -1,396 +0,0 @@ -/* - * flasky.css_t - * ~~~~~~~~~~~~ - * - * :copyright: Copyright 2010 by Armin Ronacher. - * :license: Flask Design License, see LICENSE for details. - */ - -{% set page_width = '80em' %} -{% set sidebar_width = '16em' %} - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Georgia', serif; - font-size: 15px; - background-color: white; - color: #000; - margin: 0; - padding: 0; -} - -div.document { - width: {{ page_width }}; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 {{ sidebar_width }}; -} - -div.sphinxsidebar { - width: {{ sidebar_width }}; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 0px 0 0px; -} - -img.floatingflask { - padding: 0 0 10px 10px; - float: right; -} - -div.footer { - width: {{ page_width }}; - margin: 20px auto 30px auto; - font-size: 12px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -div.related { - display: none; -} - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebar { - font-size: 12px; - line-height: 1.5; -} - -div.sphinxsidebarwrapper { - padding: 0px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0 0 20px 0; - margin: 0; - text-align: center; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: 'Garamond', 'Georgia', serif; - color: #444; - font-size: 22px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 18px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: 'Georgia', serif; - font-size: 1em; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -{% if theme_index_logo %} -div.indexwrapper h1 { - /* We don't want it, I don't know why theme_index_logo is triggered. */ - /* text-indent: -999999px; */ - background: url({{ theme_index_logo }}) no-repeat center center; - height: {{ theme_index_logo_height }}; -} -{% endif %} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #ddd; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #eaeaea; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - background: #fafafa; - margin: 20px -30px; - padding: 10px 30px; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} - -div.admonition tt.xref, div.admonition a tt { - border-bottom: 1px solid #fafafa; -} - -dd div.admonition { - margin-left: -60px; - padding-left: 60px; -} - -div.admonition p.admonition-title { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - font-size: 22px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: white; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt { - font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -img.screenshot { -} - -tt.descname, tt.descclassname { - font-size: 0.95em; -} - -tt.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #eee; - background: #fdfdfd; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.footnote td.label { - width: 0px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #eee; - padding: 7px 30px; - margin: 15px -30px; - line-height: 1.3em; -} - -dl pre, blockquote pre, li pre { - margin-left: -60px; - padding-left: 60px; -} - -dl dl pre { - margin-left: -90px; - padding-left: 90px; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid white; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt { - background: #EEE; -} diff --git a/addons/web/doc/_themes/flask/static/small_flask.css b/addons/web/doc/_themes/flask/static/small_flask.css deleted file mode 100644 index 1c6df309edc..00000000000 --- a/addons/web/doc/_themes/flask/static/small_flask.css +++ /dev/null @@ -1,70 +0,0 @@ -/* - * small_flask.css_t - * ~~~~~~~~~~~~~~~~~ - * - * :copyright: Copyright 2010 by Armin Ronacher. - * :license: Flask Design License, see LICENSE for details. - */ - -body { - margin: 0; - padding: 20px 30px; -} - -div.documentwrapper { - float: none; - background: white; -} - -div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: white; -} - -div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, -div.sphinxsidebar h3 a { - color: white; -} - -div.sphinxsidebar a { - color: #aaa; -} - -div.sphinxsidebar p.logo { - display: none; -} - -div.document { - width: 100%; - margin: 0; -} - -div.related { - display: block; - margin: 0; - padding: 10px 0 20px 0; -} - -div.related ul, -div.related ul li { - margin: 0; - padding: 0; -} - -div.footer { - display: none; -} - -div.bodywrapper { - margin: 0; -} - -div.body { - min-height: 0; - padding: 0; -} diff --git a/addons/web/doc/_themes/flask/theme.conf b/addons/web/doc/_themes/flask/theme.conf deleted file mode 100644 index 18c720f804c..00000000000 --- a/addons/web/doc/_themes/flask/theme.conf +++ /dev/null @@ -1,9 +0,0 @@ -[theme] -inherit = basic -stylesheet = flasky.css -pygments_style = flask_theme_support.FlaskyStyle - -[options] -index_logo = '' -index_logo_height = 120px -touch_icon = diff --git a/addons/web/doc/_themes/flask_small/layout.html b/addons/web/doc/_themes/flask_small/layout.html deleted file mode 100644 index afd7a912729..00000000000 --- a/addons/web/doc/_themes/flask_small/layout.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "basic/layout.html" %} -{% block header %} - {{ super() }} - {% if pagename == 'index' %} -
- {% endif %} -{% endblock %} -{% block footer %} - {% if pagename == 'index' %} -
- {% endif %} -{% endblock %} -{# do not display relbars #} -{% block relbar1 %}{% endblock %} -{% block relbar2 %} - {% if theme_github_fork %} - Fork me on GitHub - {% endif %} -{% endblock %} -{% block sidebar1 %}{% endblock %} -{% block sidebar2 %}{% endblock %} diff --git a/addons/web/doc/_themes/flask_small/static/flasky.css_t b/addons/web/doc/_themes/flask_small/static/flasky.css_t deleted file mode 100644 index fe2141c565e..00000000000 --- a/addons/web/doc/_themes/flask_small/static/flasky.css_t +++ /dev/null @@ -1,287 +0,0 @@ -/* - * flasky.css_t - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- flasky theme based on nature theme. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: 'Georgia', serif; - font-size: 17px; - color: #000; - background: white; - margin: 0; - padding: 0; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 40px auto 0 auto; - width: 700px; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 30px 30px; -} - -img.floatingflask { - padding: 0 0 10px 10px; - float: right; -} - -div.footer { - text-align: right; - color: #888; - padding: 10px; - font-size: 14px; - width: 650px; - margin: 0 auto 40px auto; -} - -div.footer a { - color: #888; - text-decoration: underline; -} - -div.related { - line-height: 32px; - color: #888; -} - -div.related ul { - padding: 0 0 0 10px; -} - -div.related a { - color: #444; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body { - padding-bottom: 40px; /* saved for footer */ -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -{% if theme_index_logo %} -div.indexwrapper h1 { - text-indent: -999999px; - background: url({{ theme_index_logo }}) no-repeat center center; - height: {{ theme_index_logo_height }}; -} -{% endif %} - -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: white; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #eaeaea; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - background: #fafafa; - margin: 20px -30px; - padding: 10px 30px; - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc; -} - -div.admonition p.admonition-title { - font-family: 'Garamond', 'Georgia', serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight{ - background-color: white; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt { - font-family: 'Consolas', 'Menlo', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.85em; -} - -img.screenshot { -} - -tt.descname, tt.descclassname { - font-size: 0.95em; -} - -tt.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #eee; - -webkit-box-shadow: 2px 2px 4px #eee; - box-shadow: 2px 2px 4px #eee; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #eee; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.footnote td { - padding: 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -pre { - padding: 0; - margin: 15px -30px; - padding: 8px; - line-height: 1.3em; - padding: 7px 30px; - background: #eee; - border-radius: 2px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; -} - -dl pre { - margin-left: -60px; - padding-left: 60px; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, a tt { - background-color: #FBFBFB; -} - -a:hover tt { - background: #EEE; -} diff --git a/addons/web/doc/_themes/flask_small/static/forkme_right_darkblue_121621.png b/addons/web/doc/_themes/flask_small/static/forkme_right_darkblue_121621.png deleted file mode 100644 index 146ef8a8006..00000000000 Binary files a/addons/web/doc/_themes/flask_small/static/forkme_right_darkblue_121621.png and /dev/null differ diff --git a/addons/web/doc/_themes/flask_small/theme.conf b/addons/web/doc/_themes/flask_small/theme.conf deleted file mode 100644 index 542b462515d..00000000000 --- a/addons/web/doc/_themes/flask_small/theme.conf +++ /dev/null @@ -1,10 +0,0 @@ -[theme] -inherit = basic -stylesheet = flasky.css -nosidebar = true -pygments_style = flask_theme_support.FlaskyStyle - -[options] -index_logo = '' -index_logo_height = 120px -github_fork = '' diff --git a/addons/web/doc/_themes/flask_theme_support.py b/addons/web/doc/_themes/flask_theme_support.py deleted file mode 100644 index 33f47449c11..00000000000 --- a/addons/web/doc/_themes/flask_theme_support.py +++ /dev/null @@ -1,86 +0,0 @@ -# flasky extensions. flasky pygments style based on tango style -from pygments.style import Style -from pygments.token import Keyword, Name, Comment, String, Error, \ - Number, Operator, Generic, Whitespace, Punctuation, Other, Literal - - -class FlaskyStyle(Style): - background_color = "#f8f8f8" - default_style = "" - - styles = { - # No corresponding class for the following: - #Text: "", # class: '' - Whitespace: "underline #f8f8f8", # class: 'w' - Error: "#a40000 border:#ef2929", # class: 'err' - Other: "#000000", # class 'x' - - Comment: "italic #8f5902", # class: 'c' - Comment.Preproc: "noitalic", # class: 'cp' - - Keyword: "bold #004461", # class: 'k' - Keyword.Constant: "bold #004461", # class: 'kc' - Keyword.Declaration: "bold #004461", # class: 'kd' - Keyword.Namespace: "bold #004461", # class: 'kn' - Keyword.Pseudo: "bold #004461", # class: 'kp' - Keyword.Reserved: "bold #004461", # class: 'kr' - Keyword.Type: "bold #004461", # class: 'kt' - - Operator: "#582800", # class: 'o' - Operator.Word: "bold #004461", # class: 'ow' - like keywords - - Punctuation: "bold #000000", # class: 'p' - - # because special names such as Name.Class, Name.Function, etc. - # are not recognized as such later in the parsing, we choose them - # to look the same as ordinary variables. - Name: "#000000", # class: 'n' - Name.Attribute: "#c4a000", # class: 'na' - to be revised - Name.Builtin: "#004461", # class: 'nb' - Name.Builtin.Pseudo: "#3465a4", # class: 'bp' - Name.Class: "#000000", # class: 'nc' - to be revised - Name.Constant: "#000000", # class: 'no' - to be revised - Name.Decorator: "#888", # class: 'nd' - to be revised - Name.Entity: "#ce5c00", # class: 'ni' - Name.Exception: "bold #cc0000", # class: 'ne' - Name.Function: "#000000", # class: 'nf' - Name.Property: "#000000", # class: 'py' - Name.Label: "#f57900", # class: 'nl' - Name.Namespace: "#000000", # class: 'nn' - to be revised - Name.Other: "#000000", # class: 'nx' - Name.Tag: "bold #004461", # class: 'nt' - like a keyword - Name.Variable: "#000000", # class: 'nv' - to be revised - Name.Variable.Class: "#000000", # class: 'vc' - to be revised - Name.Variable.Global: "#000000", # class: 'vg' - to be revised - Name.Variable.Instance: "#000000", # class: 'vi' - to be revised - - Number: "#990000", # class: 'm' - - Literal: "#000000", # class: 'l' - Literal.Date: "#000000", # class: 'ld' - - String: "#4e9a06", # class: 's' - String.Backtick: "#4e9a06", # class: 'sb' - String.Char: "#4e9a06", # class: 'sc' - String.Doc: "italic #8f5902", # class: 'sd' - like a comment - String.Double: "#4e9a06", # class: 's2' - String.Escape: "#4e9a06", # class: 'se' - String.Heredoc: "#4e9a06", # class: 'sh' - String.Interpol: "#4e9a06", # class: 'si' - String.Other: "#4e9a06", # class: 'sx' - String.Regex: "#4e9a06", # class: 'sr' - String.Single: "#4e9a06", # class: 's1' - String.Symbol: "#4e9a06", # class: 'ss' - - Generic: "#000000", # class: 'g' - Generic.Deleted: "#a40000", # class: 'gd' - Generic.Emph: "italic #000000", # class: 'ge' - Generic.Error: "#ef2929", # class: 'gr' - Generic.Heading: "bold #000080", # class: 'gh' - Generic.Inserted: "#00A000", # class: 'gi' - Generic.Output: "#888", # class: 'go' - Generic.Prompt: "#745334", # class: 'gp' - Generic.Strong: "bold #000000", # class: 'gs' - Generic.Subheading: "bold #800080", # class: 'gu' - Generic.Traceback: "bold #a40000", # class: 'gt' - } diff --git a/addons/web/doc/addon-structure.txt b/addons/web/doc/addon-structure.txt deleted file mode 100644 index 19b38689641..00000000000 --- a/addons/web/doc/addon-structure.txt +++ /dev/null @@ -1,12 +0,0 @@ - - +-- __manifest__.py - +-- controllers/ - +-- static/ - +-- lib/ - +-- src/ - +-- css/ - +-- img/ - +-- js/ - +-- xml/ - +-- test/ - +-- test/ diff --git a/addons/web/doc/client_action.rst b/addons/web/doc/client_action.rst deleted file mode 100644 index 4852400df10..00000000000 --- a/addons/web/doc/client_action.rst +++ /dev/null @@ -1,114 +0,0 @@ -.. highlight:: javascript - -Client actions -============== - -Client actions are the client-side version of OpenERP's "Server -Actions": instead of allowing for semi-arbitrary code to be executed -in the server, they allow for execution of client-customized code. - -On the server side, a client action is an action of type -``ir.actions.client``, which has (at most) two properties: a mandatory -``tag``, which is an arbitrary string by which the client will -identify the action, and an optional ``params`` which is simply a map -of keys and values sent to the client as-is (this way, client actions -can be made generic and reused in multiple contexts). - -General Structure ------------------ - -In the OpenERP Web code, a client action only requires two pieces of -information: - -* Mapping the action's ``tag`` to an object - -* Providing said object. Two different types of objects can be mapped - to a client action: - - * An OpenERP Web widget, which must inherit from - :js:class:`openerp.web.Widget` - - * A regular javascript function - -The major difference is in the lifecycle of these: - -* if the client action maps to a function, the function will be called - when executing the action. The function can have no further - interaction with the Web Client itself, although it can return an - action which will be executed after it. - - The function takes 2 parameters: the ActionManager calling it and - the descriptor for the current action (the ``ir.actions.client`` - dictionary). - -* if, on the other hand, the client action maps to a - :js:class:`~openerp.web.Widget`, that - :js:class:`~openerp.web.Widget` will be instantiated and added to - the web client's canvas, with the usual - :js:class:`~openerp.web.Widget` lifecycle (essentially, it will - either take over the content area of the client or it will be - integrated within a dialog). - -For example, to create a client action displaying a ``res.widget`` -object:: - - // Registers the object 'openerp.web_dashboard.Widget' to the client - // action tag 'board.home.widgets' - instance.web.client_actions.add( - 'board.home.widgets', 'instance.web_dashboard.Widget'); - instance.web_dashboard.Widget = instance.web.Widget.extend({ - template: 'HomeWidget' - }); - -At this point, the generic :js:class:`~openerp.web.Widget` lifecycle -takes over, the template is rendered, inserted in the client DOM, -bound on the object's ``$el`` property and the object is started. - -The second parameter to the constructor is the descriptor for the -action itself, which contains any parameter provided:: - - init: function (parent, action) { - // execute the Widget's init - this._super(parent); - // board.home.widgets only takes a single param, the identifier of the - // res.widget object it should display. Store it for later - this.widget_id = action.params.widget_id; - } - -More complex initialization (DOM manipulations, RPC requests, ...) -should be performed in the :js:func:`~openerp.web.Widget.start()` -method. - -.. note:: - - As required by :js:class:`~openerp.web.Widget`'s contract, if - :js:func:`~openerp.web.Widget.start()` executes any asynchronous - code it should return a ``Promise`` so callers know when it's - ready for interaction. - -.. code-block:: javascript - - start: function () { - return Promise.all([ - this._super(), - // Simply read the res.widget object this action should display - new instance.web.Model('res.widget').call( - 'read', [[this.widget_id], ['title']]) - .then(this.proxy('on_widget_loaded') - ]); - } - -The client action can then behave exactly as it wishes to within its -root (``this.$el``). In this case, it performs further renderings once -its widget's content is retrieved:: - - on_widget_loaded: function (widgets) { - var widget = widgets[0]; - var url = _.sprintf( - '/web_dashboard/widgets/content?session_id=%s&widget_id=%d', - this.session.session_id, widget.id); - this.$el.html(QWeb.render('HomeWidget.content', { - widget: widget, - url: url - })); - } diff --git a/addons/web/doc/conf.py b/addons/web/doc/conf.py deleted file mode 100644 index 111018ad303..00000000000 --- a/addons/web/doc/conf.py +++ /dev/null @@ -1,260 +0,0 @@ -# -*- coding: utf-8 -*- -# -# OpenERP Technical Documentation configuration file, created by -# sphinx-quickstart on Fri Feb 17 16:14:06 2012. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.append(os.path.abspath('_themes')) -sys.path.insert(0, os.path.abspath('../addons')) -sys.path.insert(0, os.path.abspath('..')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', 'sphinx.ext.viewcode', - 'patchqueue' -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'OpenERP Web Developers Documentation' -copyright = u'2012, OpenERP s.a.' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = '7.0' -# The full version, including alpha/beta/rc tags. -release = '7.0' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- 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 = 'flask' - -# 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 -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -html_theme_path = ['_themes'] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -html_sidebars = { - 'index': ['sidebarintro.html', 'sourcelink.html', 'searchbox.html'], - '**': ['sidebarlogo.html', 'localtoc.html', 'relations.html', - 'sourcelink.html', 'searchbox.html'] -} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'openerp-web-doc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'openerp-web-doc.tex', u'OpenERP Web Developers Documentation', - u'OpenERP s.a.', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'openerp-web-doc', u'OpenERP Web Developers Documentation', - [u'OpenERP s.a.'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'OpenERPWebDocumentation', u'OpenERP Web Developers Documentation', - u'OpenERP s.a.', 'OpenERPWebDocumentation', 'Developers documentation for the openerp-web project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -todo_include_todos = True - -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - 'python': ('http://docs.python.org/', None), - 'openerpserver': ('http://doc.openerp.com/trunk/developers/server', None), -} diff --git a/addons/web/doc/form_view.rst b/addons/web/doc/form_view.rst deleted file mode 100644 index 98d4a4de67e..00000000000 --- a/addons/web/doc/form_view.rst +++ /dev/null @@ -1,55 +0,0 @@ -Notes on the usage of the Form View as a sub-widget -=================================================== - -Undocumented stuff ------------------- - -* ``initial_mode`` *option* defines the starting mode of the form - view, one of ``view`` and ``edit`` (?). Default value is ``view`` - (non-editable form). - -* ``embedded_view`` *attribute* has to be set separately when - providing a view directly, no option available for that usage. - - * View arch **must** contain node with - ``@class="oe_form_container"``, otherwise everything will break - without any info - - * Root element of view arch not being ``form`` may or may not work - correctly, no idea. - - * Freeform views => ``@version="7.0"`` - -* Form is not entirely loaded (some widgets may not appear) unless - ``on_record_loaded`` is called (or ``do_show``, which itself calls - ``on_record_loaded``). - -* "Empty" form => ``on_button_new`` (...), or manually call - ``default_get`` + ``on_record_loaded`` - -* Form fields default to width: 100%, padding, !important margin, can - be reached via ``.oe_form_field`` - -* Form *will* render buttons and a pager, offers options to locate - both outside of form itself (``$buttons`` and ``$pager``), providing - empty jquery objects (``$()``) seems to stop displaying both but not - sure if there are deleterious side-effects. - - Other options: - - * Pass in ``$(document.createDocumentFragment)`` to ensure it's a - DOM-compatible tree completely outside of the actual DOM. - - * ??? - -* readonly fields probably don't have a background, beware if need of - overlay - - * What is the difference between ``readonly`` and - ``effective_readonly``? - -* No facilities for DOM events handling/delegations e.g. handling - keyup/keydown/keypress from a form fields into the form's user. - - * Also no way to reverse from a DOM node (e.g. DOMEvent#target) back to a - form view field easily diff --git a/addons/web/doc/guidelines.rst b/addons/web/doc/guidelines.rst deleted file mode 100644 index 8721d372f5b..00000000000 --- a/addons/web/doc/guidelines.rst +++ /dev/null @@ -1,194 +0,0 @@ -Guidelines and Recommendations -============================== - -Web Module Recommendations --------------------------- - -Identifiers (``id`` attribute) should be avoided -'''''''''''''''''''''''''''''''''''''''''''''''' - -In generic applications and modules, ``@id`` limits the reusabily of -components and tends to make code more brittle. - -Just about all the time, they can be replaced with nothing, with -classes or with keeping a reference to a DOM node or a jQuery element -around. - -.. note:: - - If it is *absolutely necessary* to have an ``@id`` (because a - third-party library requires one and can't take a DOM element), it - should be generated with `_.uniqueId - `_ or some other similar - method. - -Avoid predictable/common CSS class names -'''''''''''''''''''''''''''''''''''''''' - -Class names such as "content" or "navigation" might match the desired -meaning/semantics, but it is likely an other developer will have the -same need, creating a naming conflict and unintended behavior. Generic -class names should be prefixed with e.g. the name of the component -they belong to (creating "informal" namespaces, much as in C or -Objective-C) - -Global selectors should be avoided -'''''''''''''''''''''''''''''''''' - -Because a component may be used several times in a single page (an -example in OpenERP is dashboards), queries should be restricted to a -given component's scope. Unfiltered selections such as ``$(selector)`` -or ``document.querySelectorAll(selector)`` will generally lead to -unintended or incorrect behavior. - -OpenERP Web's :js:class:`~openerp.web.Widget` has an attribute -providing its DOM root :js:attr:`Widget.$el `, -and a shortcut to select nodes directly :js:attr:`Widget.$ -`. - -More generally, never assume your components own or controls anything -beyond its own personal DOM. - -Understand deferreds -'''''''''''''''''''' - -Deferreds, promises, futures, … - -Known under many names, these objects are essential to and (in OpenERP -Web) widely used for making :doc:`asynchronous javascript operations -` palatable and understandable. - -OpenERP Web guidelines ----------------------- - -* HTML templating/rendering should use :doc:`qweb` unless absolutely - trivial. - -* All interactive components (components displaying information to the - screen or intercepting DOM events) must inherit from - :class:`~openerp.web.Widget` and correctly implement and use its API - and lifecycle. - -* All css classes must be prefixed with *oe_* . - -* Asynchronous functions (functions which call :ref:`session.rpc - ` directly or indirectly at the very least) *must* return - deferreds, so that callers of overriders can correctly synchronize - with them. - -New Javascript guidelines -------------------------- - -From v11, we introduce a new coding standard for Odoo Javascript code. Here it -is: - -* add "use strict"; on top of every odoo JS module - -* name all entities exported by a JS module. So, instead of - - .. code-block:: javascript - - return Widget.extend({ - ... - }); - -you should use: - - .. code-block:: javascript - - var MyWidget = Widget.extend({ - ... - }); - - return MyWidget - -* there should be one space between function and the left parenthesis: - - .. code-block:: javascript - - function (a, b) {} - -* JS files should have a (soft) limit of 80 chars width, and a hard limit of 100 - -* document every functions and every files, with the style JSDoc. - -* for function overriding other functions, consider adding the tag @override in - the JS Doc. Also, you can mention which method is overridden: - - .. code-block:: javascript - - /** - * When a save operation has been confirmed from the model, this method is - * called. - * - * @override method from field manager mixin - * @param {string} id - * @returns {Deferred} - */ - _confirmSave: function (id) { - -* there should be an empty line between the main function comments and the tags, - or parameter descriptions - -* avoid introspection: don't build dynamically a method name and call it. It is - more fragile and more difficult to refactor - -* methods should be private if possible - -* never read an attribute of an attribute on somethig that you have a reference. - So, this is not good: - - .. code-block:: javascript - - this.myObject.propA.propB - -* never use a reference to the parent widget - -* avoid using the 'include' functionality: extending a class is fine and does - not cause issue, including a class is much more fragile, and may not work. - -* For the widgets, here is how the various attributes/functions should be - ordered: - - 1. all static attributes, such as template, events, custom_events, ... - - 2. all methods from the lifecycle of a widget, in this order: init, willStart, - start, destroy - - 3. If there are public methods, a section titled "Public", with an empty line - before and after - - 4. all public methods, camelcased, in alphabetic order - - 5. If there are private methods, a section titled "Private", with an empty line - before and after - - 6. all private methods, camelcased and prefixed with _, in alphabetic order - - 7. If there are event handlers, a section titled "Handlers", with an empty line - before and after - - 8. all handlers, camelcased and prefixed with _on, in alphabetic order - - 9. If there are static methods, they should be in a section titled "Static". - All static methods are considered public, camelcased with no _. - -* write unit tests - -* for the event handlers defined by the key 'event' or 'custom_events', don't - inline the function. Always add a string name, and add the definition in the - handler section - -* one space after if and for - -* never call private methods on another object - -* object definition on more than one line: each element should have a trailing - comma. - -* strings: double quotes for all textual strings (such as "Hello"), and single - quotes for all other strings, such as a css selector '.o_form_view' - -* always use this._super.apply(this, arguments); - -* keys in an object: ordered by alphabetic order \ No newline at end of file diff --git a/addons/web/doc/images/db-query.png b/addons/web/doc/images/db-query.png deleted file mode 100644 index e063b724001..00000000000 Binary files a/addons/web/doc/images/db-query.png and /dev/null differ diff --git a/addons/web/doc/images/runner.png b/addons/web/doc/images/runner.png deleted file mode 100644 index bd48e9d2922..00000000000 Binary files a/addons/web/doc/images/runner.png and /dev/null differ diff --git a/addons/web/doc/images/runner2.png b/addons/web/doc/images/runner2.png deleted file mode 100644 index 38ea2949cfc..00000000000 Binary files a/addons/web/doc/images/runner2.png and /dev/null differ diff --git a/addons/web/doc/images/tests.png b/addons/web/doc/images/tests.png deleted file mode 100644 index 84083d9e5ed..00000000000 Binary files a/addons/web/doc/images/tests.png and /dev/null differ diff --git a/addons/web/doc/images/tests2.png b/addons/web/doc/images/tests2.png deleted file mode 100644 index c8a6f8ae9ee..00000000000 Binary files a/addons/web/doc/images/tests2.png and /dev/null differ diff --git a/addons/web/doc/images/tests3.png b/addons/web/doc/images/tests3.png deleted file mode 100644 index 247f70716af..00000000000 Binary files a/addons/web/doc/images/tests3.png and /dev/null differ diff --git a/addons/web/doc/index.rst b/addons/web/doc/index.rst deleted file mode 100644 index 5a862d2937d..00000000000 --- a/addons/web/doc/index.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. OpenERP Web documentation master file, created by - sphinx-quickstart on Fri Mar 18 16:31:55 2011. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -OpenERP Web Reference Documentation -=================================== - -See also the `OpenERP Web Training`_. - -.. _OpenERP Web Training: https://doc.openerp.com/trunk/training/ - -Basics ------- - -.. toctree:: - :maxdepth: 1 - - module - changelog-7.0 - -Server-Side Web Framework -------------------------- - -.. toctree:: - :maxdepth: 1 - - web_controllers - -Javascript ----------- - -.. toctree:: - :maxdepth: 1 - - guidelines - client_action - testing - -Views ------ - -.. toctree:: - :maxdepth: 1 - - search_view - list_view - form_view - -Indices and tables ------------------- - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/addons/web/doc/list_view.rst b/addons/web/doc/list_view.rst deleted file mode 100644 index f73abafe2f2..00000000000 --- a/addons/web/doc/list_view.rst +++ /dev/null @@ -1,531 +0,0 @@ -List View -========= - -Style Hooks ------------ - -The list view provides a few style hook classes for re-styling of list views in -various situations: - -``.oe_list`` - - The root element of the list view, styling rules should be rooted - on that class. - -``table.oe_list_content`` - - The root table for the listview, accessory components may be - generated or added outside this section, this is the list view - "proper". - -``.oe_list_buttons`` - - The action buttons array for the list view, with its sub-elements - - ``.oe_list_add`` - - The default "Create"/"Add" button of the list view - - ``.oe_alternative`` - - The "alternative choice" for the list view, by default text - along the lines of "or import" with a link. - -``.oe_list_field_cell`` - - The cell (``td``) for a given field of the list view, cells which - are *not* fields (e.g. name of a group, or number of items in a - group) will not have this class. The field cell can be further - specified: - - ``.oe_number`` - - Numeric cell types (integer and float) - - ``.oe_button`` - - Action button (``button`` tag in the view) inside the cell - - ``.o_readonly_modifier`` - - Readonly field cell - - ``.oe_list_field_$type`` - - Additional class for the precise type of the cell, ``$type`` - is the field's @widget if there is one, otherwise it's the - field's type. - -``.oe_list_record_selector`` - - Selector cells - -Editable list view -++++++++++++++++++ - -The editable list view module adds a few supplementary style hook -classes, for edition situations: - -``.o_list_editable`` - - Added to the ``.oe_list`` when the list is editable (however that - was done). The class may be removed on-the-fly if the list becomes - non-editable. - -``.oe_editing`` - - Added to both ``.oe_list`` and ``.oe_list_button`` (as the - buttons may be outside of the list view) when a row of the list is - currently being edited. - -``tr.oe_edition`` - - Class set on the row being edited itself. Note that the edition - form is *not* contained within the row, this allows for styling or - modifying the row while it's being edited separately. Mostly for - fields which can not be edited (e.g. read-only fields). - -Columns display customization ------------------------------ - -The list view provides a registry to -:js:class:`openerp.web.list.Column` objects allowing for the -customization of a column's display (e.g. so that a binary field is -rendered as a link to the binary file directly in the list view). - -The registry is ``instance.web.list.columns``, the keys are of the -form ``tag.type`` where ``tag`` can be ``field`` or ``button``, and -``type`` can be either the field's type or the field's ``@widget`` (in -the view). - -Most of the time, you'll want to define a ``tag.widget`` key -(e.g. ``field.progressbar``). - -.. js:class:: openerp.web.list.Column(id, tag, attrs) - - .. js:function:: openerp.web.list.Column.format(record_data, options) - - Top-level formatting method, returns an empty string if the - column is invisible (unless the ``process_modifiers=false`` - option is provided); returns ``options.value_if_empty`` or an - empty string if there is no value in the record for the - column. - - Otherwise calls :js:func:`~openerp.web.list.Column._format` - and returns its result. - - This method only needs to be overridden if the column has no - concept of values (and needs to bypass that check), for a - button for instance. - - Otherwise, custom columns should generally override - :js:func:`~openerp.web.list.Column._format` instead. - - :returns: String - - .. js:function:: openerp.web.list.Column._format(record_data, options) - - Never called directly, called if the column is visible and has - a value. - - The default implementation calls - :js:func:`~openerp.web.format_value` and htmlescapes the - result (via ``_.escape``). - - Note that the implementation of - :js:func:`~openerp.web.list.Column._format` *must* escape the - data provided to it, its output will *not* be escaped by - :js:func:`~openerp.web.list.Column.format`. - - :returns: String - -Editable list view ------------------- - -List view edition is an extension to the base listview providing the -capability of inline record edition by delegating to an embedded form -view. - -Editability status -++++++++++++++++++ - -The editability status of a list view can be queried through the -:js:func:`~openerp.web.ListView.editable` method, will return a falsy -value if the listview is not currently editable. - -The editability status is based on three flags: - -``tree/@editable`` - - If present, can be either ``"top"`` or ``"bottom"``. Either will - make the list view editable, with new records being respectively - created at the top or at the bottom of the view. - -``context.set_editable`` - - Boolean flag extracted from a search context (during the - :js:func:`~openerp.web.ListView.do_search`` handler), ``true`` - will make the view editable (from the top), ``false`` or the - absence of the flag is a noop. - -``defaults.editable`` - - Like ``tree/@editable``, one of absent (``null``)), ``"top"`` or - ``"bottom"``, fallback for the list view if none of the previous - two flags are set. - -These three flags can only *make* a listview editable, they can *not* -override a previously set flag. To do that, a listview user should -instead cancel :ref:`the edit:before event `. - -The editable list view module adds a number of methods to the list -view, on top of implementing the :js:class:`EditorDelegate` protocol: - -Interaction Methods -+++++++++++++++++++ - -.. js:function:: openerp.web.ListView.ensure_saved - - Attempts to resolve the pending edition, if any, by saving the - edited row's current state. - - :returns: delegate resolving to all editions having been saved, or - rejected if a pending edition could not be saved - (e.g. validation failure) - -.. js:function:: openerp.web.ListView.start_edition([record][, options]) - - Starts editing the provided record inline, through an overlay form - view of editable fields in the record. - - If no record is provided, creates a new one according to the - editability configuration of the list view. - - This method resolves any pending edition when invoked, before - starting a new edition. - - :param record: record to edit, or null to create a new record - :type record: :js:class:`~openerp.web.list.Record` - :param EditOptions options: - :returns: delegate to the form used for the edition - -.. js:function:: openerp.web.ListView.save_edition - - Resolves the pending edition. - - :returns: delegate to the save being completed, resolves to an - object with two attributes ``created`` (flag indicating - whether the saved record was just created or was - updated) and ``record`` the reloaded record having been - edited. - -.. js:function:: openerp.web.ListView.cancel_edition([force=false]) - - Cancels pending edition, cleans up the list view in case of - creation (removes the empty record being created). - - :param Boolean force: doesn't check if the user has added any - data, discards the edition unconditionally - -Utility Methods -+++++++++++++++ - -.. js:function:: openerp.web.ListView.get_cells_for(row) - - Extracts the cells from a listview row, and puts them in a - {fieldname: cell} mapping for analysis and manipulation. - - :param jQuery row: - :rtype: Object - -.. js:function:: openerp.web.ListView.with_event(event_name, event, action[, args][, trigger_params]) - - Executes ``action`` in the context of the view's editor, - bracketing it with cancellable event signals. - - :param String event_name: base name for the bracketing event, will - be postfixed by ``:before`` and - ``:after`` before being called - (respectively before and after - ``action`` is executed) - :param Object event: object passed to the ``:before`` event - handlers. - :param Function action: function called with the view's editor as - its ``this``. May return a deferred. - :param Array args: arguments passed to ``action`` - :param Array trigger_params: arguments passed to the ``:after`` - event handler alongside the results - of ``action`` - -Behavioral Customizations -+++++++++++++++++++++++++ - -.. js:function:: openerp.web.ListView.handle_onwrite(record) - - Implements the handling of the ``onwrite`` listview attribute: - calls the RPC methods specified by ``@onwrite``, and if that - method returns an array of ids loads or reloads the records - corresponding to those ids. - - :param record: record being written having triggered the - ``onwrite`` callback - :type record: openerp.web.list.Record - :returns: deferred to all reloadings being done - -Events -++++++ - -For simpler interactions by/with external users of the listview, the -view provides a number of dedicated events to its lifecycle. - -.. note:: if an event is defined as *cancellable*, it means its first - parameter is an object on which the ``cancel`` attribute can - be set. If the ``cancel`` attribute is set, the view will - abort its current behavior as soon as possible, and rollback - any state modification. - - Generally speaking, an event should only be cancelled (by - setting the ``cancel`` flag to ``true``), uncancelling an - event is undefined as event handlers are executed on a - first-come-first-serve basis and later handlers may - re-cancel an uncancelled event. - -.. _listview-edit-before: - -``edit:before`` *cancellable* - - Invoked before the list view starts editing a record. - - Provided with an event object with a single property ``record``, - holding the attributes of the record being edited (``record`` is - empty *but not null* for a new record) - -``edit:after`` - - Invoked after the list view has gone into an edition state, - provided with the attributes of the record being edited (see - ``edit:before``) as first parameter and the form used for the - edition as second parameter. - -``save:before`` *cancellable* - - Invoked right before saving a pending edition, provided with an - event object holding the listview's editor (``editor``) and the - edition form (``form``) - -``save:after`` - - Invoked after a save has been completed - -``cancel:before`` *cancellable* - - Invoked before cancelling a pending edition, provided with the - same information as ``save:before``. - -``cancel:after`` - - Invoked after a pending edition has been cancelled. - -DOM events -++++++++++ - -The list view has grown hooks for the ``keyup`` event on its edition -form (during edition): any such event bubbling out of the edition form -will be forwarded to a method ``keyup_EVENTNAME``, where ``EVENTNAME`` -is the name of the key in ``$.ui.keyCode``. - -The method will also get the event object (originally passed to the -``keyup`` handler) as its sole parameter. - -The base editable list view has handlers for the ``ENTER`` and -``ESCAPE`` keys. - -Editor ------- - -The list-edition modules does not generally interact with the embedded -formview, delegating instead to its -:js:class:`~openerp.web.list.Editor`. - -.. js:class:: openerp.web.list.Editor(parent[, options]) - - The editor object provides a more convenient interface to form - views, and simplifies the usage of form views for semi-arbitrary - edition of stuff. - - However, the editor does *not* task itself with being internally - consistent at this point: calling - e.g. :js:func:`~openerp.web.list.Editor.edit` multiple times in a - row without saving or cancelling each edit is undefined. - - :param parent: - :type parent: :js:class:`~openerp.web.Widget` - :param EditorOptions options: - - .. js:function:: openerp.web.list.Editor.is_editing([record_state]) - - Indicates whether the editor is currently in the process of - providing edition for a record. - - Can be filtered by the state of the record being edited - (whether it's a record being *created* or a record being - *altered*), in which case it asserts both that an edition is - underway and that the record being edited respectively does - not yet exist in the database or already exists there. - - :param record_state: state of the record being edited. - Either ``"new"`` or ``"edit"``. - :type record_state: String - :rtype: Boolean - - .. js:function:: openerp.web.list.Editor.edit(record, configureField[, options]) - - Loads the provided record into the internal form view and - displays the form view. - - Will also attempt to focus the first visible field of the form - view. - - :param Object record: record to load into the form view - (key:value mapping similar to the result - of a ``read``) - :param configureField: function called with each field of the - form view right after the form is - displayed, lets whoever called this - method do some last-minute - configuration of form fields. - :type configureField: Function - :param EditOptions options: - :returns: jQuery delegate to the form object - - .. js:function:: openerp.web.list.Editor.save - - Attempts to save the internal form, then hide it - - :returns: delegate to the record under edition (with ``id`` - added for a creation). The record is not updated - from when it was passed in, aside from the ``id`` - attribute. - - .. js:function:: openerp.web.list.Editor.cancel([force=false]) - - Attemps to cancel the edition of the internal form, then hide - the form - - :param Boolean force: unconditionally cancels the edition of - the internal form, even if the user has - already entered data in it. - :returns: delegate to the record under edition - -.. js:class:: EditorOptions - - .. js:attribute:: EditorOptions.formView - - Form view (sub)-class to instantiate and delegate edition to. - - By default, :js:class:`~openerp.web.FormView` - - .. js:attribute:: EditorOptions.delegate - - Object used to get various bits of information about how to - display stuff. - - By default, uses the editor's parent widget. See - :js:class:`EditorDelegate` for the methods and attributes to - provide. - -.. js:class:: EditorDelegate - - Informal protocol defining the methods and attributes expected of - the :js:class:`~openerp.web.list.Editor`'s delegate. - - .. js:attribute:: EditorDelegate.dataset - - The dataset passed to the form view to synchronize the form - view and the outer widget. - - .. js:function:: EditorDelegate.edition_view(editor) - - Called by the :js:class:`~openerp.web.list.Editor` object to - get a form view (JSON) to pass along to the form view it - created. - - The result should be a valid form view, see :doc:`Form Notes - ` for various peculiarities of the form view - format. - - :param editor: editor object asking for the view - :type editor: :js:class:`~openerp.web.list.Editor` - :returns: form view - :rtype: Object - - .. js:function:: EditorDelegate.prepends_on_create - - By default, the :js:class:`~openerp.web.list.Editor` will - append the ids of newly created records to the - :js:attr:`EditorDelegate.dataset`. If this method returns - ``true``, it will prepend these ids instead. - - :returns: whether new records should be prepended to the - dataset (instead of appended) - :rtype: Boolean - - -.. js:class:: EditOptions - - Options object optionally passed into a method starting an edition - to configure its setup and behavior - - .. js:attribute:: focus_field - - Name of the field to set focus on after setting up the edition - of the record. - - If this option is not provided, or the requested field can not - be focused (invisible, readonly or not in the view), the first - visible non-readonly field is focused. - -Changes from 6.1 ----------------- - -* The editable listview behavior has been rewritten pretty much from - scratch, any code touching on editability will have to be modified - - * The overloading of :js:class:`~openerp.web.ListView.Groups` and - :js:class:`~openerp.web.ListView.List` for editability has been - drastically simplified, and most of the behavior has been moved to - the list view itself. Only - :js:func:`~openerp.web.ListView.List.row_clicked` is still - overridden. - - * A new method ``get_row_for(record) -> jQuery(tr) | null`` has been - added to both ListView.List and ListView.Group, it can be called - from the list view to get the table row matching a record (if such - a row exists). - -* :js:func:`~openerp.web.ListView.do_button_action`'s core behavior - has been split away to - :js:func:`~openerp.web.ListView.handle_button`. This allows bypassing - overrides of :js:func:`~openerp.web.ListView.do_button_action` in a - parent class. - - Ideally, :js:func:`~openerp.web.ListView.handle_button` should not be - overridden. - -* Modifiers handling has been improved (all modifiers information - should now be available through :js:func:`~Column.modifiers_for`, - not just ``invisible``) - -* Changed some handling of the list view's record: a record may now - have no id, and the listview will handle that correctly (for new - records being created) as well as correctly handle the ``id`` being - set. - -* Extended the internal collections structure of the list view with - `#find`_, `#succ`_ and `#pred`_. - -.. _#find: http://underscorejs.org/#find - -.. _#succ: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:succ - -.. _#pred: http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:pred diff --git a/addons/web/doc/make.bat b/addons/web/doc/make.bat deleted file mode 100644 index 3e72cadb53b..00000000000 --- a/addons/web/doc/make.bat +++ /dev/null @@ -1,170 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=_build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenERPWeb.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenERPWeb.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/addons/web/doc/module.rst b/addons/web/doc/module.rst deleted file mode 100644 index ca808254567..00000000000 --- a/addons/web/doc/module.rst +++ /dev/null @@ -1,442 +0,0 @@ -.. _module: - -.. queue:: module/series - -Building a Web module -===================== - -There is no significant distinction between a Web module and -a regular module, the web part is mostly additional data and code -inside a regular module. This allows providing more seamless -features by integrating your module deeper into the web client. - -A Basic Module --------------- - -A very basic OpenERP module structure will be our starting point: - -.. code-block:: text - - web_example - ├── __init__.py - └── __manifest__.py - -.. patch:: - -This is a sufficient minimal declaration of a valid module. - -Web Declaration ---------------- - -There is no such thing as a "web module" declaration. An OpenERP -module is automatically recognized as "web-enabled" if it contains a -``static`` directory at its root, so: - -.. code-block:: text - - web_example - ├── __init__.py - ├── __manifest__.py - └── static - -is the extent of it. You should also change the dependency to list -``web``: - -.. patch:: - -.. note:: - - This does not matter in normal operation so you may not realize - it's wrong (the web module does the loading of everything else, so - it can only be loaded), but when e.g. testing the loading process - is slightly different than normal, and incorrect dependency may - lead to broken code. - -This makes the "web" discovery system consider the module as having a -"web part", and check if it has web controllers to mount or javascript -files to load. The content of the ``static/`` folder is also -automatically made available to web browser at the URL -``$module-name/static/$file-path``. This is sufficient to provide -pictures (of cats, usually) through your module. However there are -still a few more steps to running javascript code. - -Getting Things Done -------------------- - -The first one is to add javascript code. It's customary to put it in -``static/src/js``, to have room for e.g. other file types, or -third-party libraries. - -.. patch:: - -The client won't load any file unless specified, thus the new file -should be listed in the module's manifest file, under a new key ``js`` -(a list of file names, or glob patterns): - -.. patch:: - -At this point, if the module is installed and the client reloaded the -message should appear in your browser's development console. - -.. note:: - - Because the manifest file has been edited, you will have to - restart the OpenERP server itself for it to be taken in account. - - You may also want to open your browser's console *before* - reloading, depending on the browser messages printed while the - console is closed may not work or may not appear after opening it. - -.. note:: - - If the message does not appear, try cleaning your browser's caches - and ensure the file is correctly loaded from the server logs or - the "resources" tab of your browser's developers tools. - -At this point the code runs, but it runs only once when the module is -initialized, and it can't get access to the various APIs of the web -client (such as making RPC requests to the server). This is done by -providing a `javascript module`_: - -.. patch:: - -If you reload the client, you'll see a message in the console exactly -as previously. The differences, though invisible at this point, are: - -* All javascript files specified in the manifest (only this one so - far) have been fully loaded -* An instance of the web client and a namespace inside that instance - (with the same name as the module) have been created and are - available for use - -The latter point is what the ``instance`` parameter to the function -provides: an instance of the OpenERP Web client, with the contents of -all the new module's dependencies loaded in and initialized. These are -the entry points to the web client's APIs. - -To demonstrate, let's build a simple :doc:`client action -`: a stopwatch - -First, the action declaration: - -.. patch:: - -then set up the :doc:`client action hook ` to register -a function (for now): - -.. patch:: - -Updating the module (in order to load the XML description) and -re-starting the server should display a new menu *Example Client -Action* at the top-level. Opening said menu will make the message -appear, as usual, in the browser's console. - -Paint it black --------------- - -The next step is to take control of the page itself, rather than just -print little messages in the console. This we can do by replacing our -client action function by a :doc:`widget`. Our widget will simply use -its :js:func:`~openerp.web.Widget.start` to add some content to its -DOM: - -.. patch:: - -after reloading the client (to update the javascript file), instead of -printing to the console the menu item clears the whole screen and -displays the specified message in the page. - -Since we've added a class on the widget's :ref:`DOM root -` we can now see how to add a stylesheet to a module: -first create the stylesheet file: - -.. patch:: - -then add a reference to the stylesheet in the module's manifest (which -will require restarting the OpenERP Server to see the changes, as -usual): - -.. patch:: - -the text displayed by the menu item should now be huge, and -white-on-black (instead of small and black-on-white). From there on, -the world's your canvas. - -.. note:: - - Prefixing CSS rules with both ``.openerp`` (to ensure the rule - will apply only within the confines of the OpenERP Web client) and - a class at the root of your own hierarchy of widgets is strongly - recommended to avoid "leaking" styles in case the code is running - embedded in an other web page, and does not have the whole screen - to itself. - -So far we haven't built much (any, really) DOM content. It could all -be done in :js:func:`~openerp.web.Widget.start` but that gets unwieldy -and hard to maintain fast. It is also very difficult to extend by -third parties (trying to add or change things in your widgets) unless -broken up into multiple methods which each perform a little bit of the -rendering. - -The first way to handle this method is to delegate the content to -plenty of sub-widgets, which can be individually overridden. An other -method [#DOM-building]_ is to use `a template -`_ to render a widget's -DOM. - -OpenERP Web's template language is :doc:`qweb`. Although any -templating engine can be used (e.g. `mustache -`_ or `_.template -`_) QWeb has important features -which other template engines may not provide, and has special -integration to OpenERP Web widgets. - -Adding a template file is similar to adding a style sheet: - -.. patch:: - -The template can then easily be hooked in the widget: - -.. patch:: - -And finally the CSS can be altered to style the new (and more complex) -template-generated DOM, rather than the code-generated one: - -.. patch:: - -.. note:: - - The last section of the CSS change is an example of "state - classes": a CSS class (or set of classes) on the root of the - widget, which is toggled when the state of the widget changes and - can perform drastic alterations in rendering (usually - showing/hiding various elements). - - This pattern is both fairly simple (to read and understand) and - efficient (because most of the hard work is pushed to the - browser's CSS engine, which is usually highly optimized, and done - in a single repaint after toggling the class). - -The last step (until the next one) is to add some behavior and make -our stopwatch watch. First hook some events on the buttons to toggle -the widget's state: - -.. patch:: - -This demonstrates the use of the "events hash" and event delegation to -declaratively handle events on the widget's DOM. And already changes -the button displayed in the UI. Then comes some actual logic: - -.. patch:: - -* An initializer (the ``init`` method) is introduced to set-up a few - internal variables: ``_start`` will hold the start of the timer (as - a javascript Date object), and ``_watch`` will hold a ticker to - update the interface regularly and display the "current time". - -* ``update_counter`` is in charge of taking the time difference - between "now" and ``_start``, formatting as ``HH:MM:SS`` and - displaying the result on screen. - -* ``watch_start`` is augmented to initialize ``_start`` with its value - and set-up the update of the counter display every 33ms. - -* ``watch_stop`` disables the updater, does a final update of the - counter display and resets everything. - -* Finally, because javascript Interval and Timeout objects execute - "outside" the widget, they will keep going even after the widget has - been destroyed (especially an issue with intervals as they repeat - indefinitely). So ``_watch`` *must* be cleared when the widget is - destroyed (then the ``_super`` must be called as well in order to - perform the "normal" widget cleanup). - -Starting and stopping the watch now works, and correctly tracks time -since having started the watch, neatly formatted. - -Burning through the skies -------------------------- - -All work so far has been "local" outside of the original impetus -provided by the client action: the widget is self-contained and, once -started, does not communicate with anything outside itself. Not only -that, but it has no persistence: if the user leaves the stopwatch -screen (to go and see his inbox, or do some well-deserved accounting, -for instance) whatever was being timed will be lost. - -To prevent this irremediable loss, we can use OpenERP's support for -storing data as a model, allowing so that we don't lose our data and -can later retrieve, query and manipulate it. First let's create a -basic OpenERP model in which our data will be stored: - -.. patch:: - -then let's add saving times to the database every time the stopwatch -is stopped, using :js:class:`the "high-level" Model API -`: - -.. patch:: - -A look at the "Network" tab of your preferred browser's developer -tools while playing with the stopwatch will show that the save -(creation) request is indeed sent (and replied to, even though we're -ignoring the response at this point). - -These saved data should now be loaded and displayed when first opening -the action, so the user can see his previously recorded times. This is -done by overloading the model's ``start`` method: the purpose of -:js:func:`~openerp.base.Widget.start()` is to perform *asynchronous* -initialization steps, so the rest of the web client knows to "wait" -and gets a readiness signal. In this case, it will fetch the data -recorded previously using the :js:class:`~openerp.web.Query` interface -and add this data to an ordered list added to the widget's template: - -.. patch:: - -And for consistency's sake (so that the display a user leaves is -pretty much the same as the one he comes back to), newly created -records should also automatically be added to the list: - -.. patch:: - -Note that we're only displaying the record once we know it's been -saved from the database (the ``create`` call has returned without -error). - -Mic check, is this working? ---------------------------- - -So far, features have been implemented, code has been worked and -tentatively tried. However, there is no guarantee they will *keep -working* as new changes are performed, new features added, … - -The original author (you, dear reader) could keep a notebook with a -list of workflows to check, to ensure everything keeps working. And -follow the notebook day after day, every time something is changed in -the module. - -That gets repetitive after a while. And computers are good at doing -repetitive stuff, as long as you tell them how to do it. - -So let's add test to the module, so that in the future the computer -can take care of ensuring what works today keeps working tomorrow. - -.. note:: - - Here we're writing tests after having implemented the widget. This - may or may not work, we may need to alter bits and pieces of code - to get them in a testable state. An other testing methodology is - :abbr:`TDD (Test-Driven Development)` where the tests are written - first, and the code necessary to make these tests pass is written - afterwards. - - Both methods have their opponents and detractors, advantages and - inconvenients. Pick the one you prefer. - -The first step of :doc:`testing` is to set up the basic testing -structure: - -1. Creating a javascript file - - .. patch:: - -2. Containing a test section (and a few tests to make sure the tests - are correctly run) - - .. patch:: - -3. Then declaring the test file in the module's manifest - - .. patch:: - -4. And finally — after restarting OpenERP — navigating to the test - runner at ``/web/tests`` and selecting your soon-to-be-tested - module: - - .. image:: module/testing_0.png - :align: center - - the testing result do indeed match the test. - -The simplest tests to write are for synchronous pure -functions. Synchronous means no RPC call or any other such thing -(e.g. ``setTimeout``), only direct data processing, and pure means no -side-effect: the function takes some input, manipulates it and yields -an output. - -In our widget, only ``format_time`` fits the bill: it takes a duration -(in milliseconds) and returns an ``hours:minutes:second`` formatting -of it. Let's test it: - -.. patch:: - -This series of simple tests passes with no issue. The next easy-ish -test type is to test basic DOM alterations from provided input, such -as (for our widget) updating the counter or displaying a record to the -records list: while it's not pure (it alters the DOM "in-place") it -has well-delimited side-effects and these side-effects come solely -from the provided input. - -Because these methods alter the widget's DOM, the widget needs a -DOM. Looking up :doc:`a widget's lifecycle `, the widget -really only gets its DOM when adding it to the document. However a -side-effect of this is to :js:func:`~openerp.web.Widget.start` it, -which for us means going to query the user's times. - -We don't have any records to get in our test, and we don't want to -test the initialization yet! So let's cheat a bit: we can manually -:js:func:`set a widget's DOM `, let's -create a basic DOM matching what each method expects then call the -method: - -.. patch:: - -The next group of patches (in terms of setup/complexity) is RPC tests: -testing components/methods which perform network calls (RPC -requests). In our module, ``start`` and ``watch_stop`` are in that -case: ``start`` fetches the user's recorded times and ``watch_stop`` -creates a new record with the current watch. - -By default, tests don't allow RPC requests and will generate an error -when trying to perform one: - -.. image:: module/testing_1.png - :align: center - -To allow them, the test case (or the test suite) has to explicitly opt -into :js:attr:`rpc support ` by adding the ``rpc: -'mock'`` option to the test case, and providing its own "rpc -responses": - -.. patch:: - -.. note:: - - By default, tests cases don't load templates either. We had not - needed to perform any template rendering before here, so we must - now enable templates loading via :js:attr:`the corresponding - option `. - -Our final test requires altering the module's code: asynchronous tests -use :doc:`deferred ` to know when a test ends and the other -one can start (otherwise test content will execute non-linearly and -the assertions of a test will be executed during the next test or -worse), but although ``watch_stop`` performs an asynchronous -``create`` operation it doesn't return a deferred we can synchronize -on. We simply need to return its result: - -.. patch:: - -This makes no difference to the original code, but allows us to write -our test: - -.. patch:: - -.. [#DOM-building] they are not alternative solutions: they work very - well together. Templates are used to build "just - DOM", sub-widgets are used to build DOM subsections - *and* delegate part of the behavior (e.g. events - handling). - -.. _javascript module: - http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript diff --git a/addons/web/doc/module/0 b/addons/web/doc/module/0 deleted file mode 100644 index 17b70a86197..00000000000 --- a/addons/web/doc/module/0 +++ /dev/null @@ -1,17 +0,0 @@ -# HG changeset patch -# Parent 0000000000000000000000000000000000000000 - -diff --git a/__init__.py b/__init__.py -new file mode 100644 -diff --git a/__manifest__.py b/__manifest__.py -new file mode 100644 ---- /dev/null -+++ b/__manifest__.py -@@ -0,0 +1,7 @@ -+# __manifest__.py -+{ -+ 'name': "Web Example", -+ 'description': "Basic example of a (future) web module", -+ 'category': 'Hidden', -+ 'depends': ['base'], -+} diff --git a/addons/web/doc/module/10 b/addons/web/doc/module/10 deleted file mode 100644 index dc3b670c5a0..00000000000 --- a/addons/web/doc/module/10 +++ /dev/null @@ -1,13 +0,0 @@ -# HG changeset patch -# Parent 72d9d59a93fcee06ba28cf0b98a1075331dcc8f4 -diff --git a/static/src/css/web_example.css b/static/src/css/web_example.css -new file mode 100644 ---- /dev/null -+++ b/static/src/css/web_example.css -@@ -0,0 +1,6 @@ -+.openerp .oe_web_example { -+ color: white; -+ background-color: black; -+ height: 100%; -+ font-size: 400%; -+} diff --git a/addons/web/doc/module/11 b/addons/web/doc/module/11 deleted file mode 100644 index 889ee98e801..00000000000 --- a/addons/web/doc/module/11 +++ /dev/null @@ -1,11 +0,0 @@ -# HG changeset patch -# Parent 3ed382d9a8fe64fbb8e2bf4045e3fcd5c74c92bc -diff --git a/__manifest__.py b/__manifest__.py ---- a/__manifest__.py -+++ b/__manifest__.py -@@ -6,4 +6,5 @@ - 'depends': ['web'], - 'data': ['web_example.xml'], - 'js': ['static/src/js/first_module.js'], -+ 'css': ['static/src/css/web_example.css'], - } diff --git a/addons/web/doc/module/12 b/addons/web/doc/module/12 deleted file mode 100644 index 85c931c33b2..00000000000 --- a/addons/web/doc/module/12 +++ /dev/null @@ -1,28 +0,0 @@ -# HG changeset patch -# Parent 43f21611dacb7c2b2f3810baeeef359ad7c329f0 - -diff --git a/__manifest__.py b/__manifest__.py ---- a/__manifest__.py -+++ b/__manifest__.py -@@ -7,4 +7,5 @@ - 'data': ['web_example.xml'], - 'js': ['static/src/js/first_module.js'], - 'css': ['static/src/css/web_example.css'], -+ 'qweb': ['static/src/xml/web_example.xml'], - } -diff --git a/static/src/xml/web_example.xml b/static/src/xml/web_example.xml -new file mode 100644 ---- /dev/null -+++ b/static/src/xml/web_example.xml -@@ -0,0 +1,11 @@ -+ -+
-+

00:00:00

-+

-+ -+

-+

-+ -+

-+
-+
diff --git a/addons/web/doc/module/14 b/addons/web/doc/module/14 deleted file mode 100644 index a908cbc61e2..00000000000 --- a/addons/web/doc/module/14 +++ /dev/null @@ -1,17 +0,0 @@ -# HG changeset patch -# Parent ae3b427c96b532794a65357b3f075129cc991276 -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -2,10 +2,6 @@ - openerp.web_example = function (instance) { - instance.web.client_actions.add('example.action', 'instance.web_example.Action'); - instance.web_example.Action = instance.web.Widget.extend({ -- className: 'oe_web_example', -- start: function () { -- this.$el.text("Hello, world!"); -- return this._super(); -- } -+ template: 'web_example.action' - }); - }; diff --git a/addons/web/doc/module/15 b/addons/web/doc/module/15 deleted file mode 100644 index d82abee3284..00000000000 --- a/addons/web/doc/module/15 +++ /dev/null @@ -1,19 +0,0 @@ -# HG changeset patch -# Parent e2d2e1a4cc2d2496aebeb05d94768384427c9e8b -diff --git a/static/src/css/web_example.css b/static/src/css/web_example.css ---- a/static/src/css/web_example.css -+++ b/static/src/css/web_example.css -@@ -2,5 +2,12 @@ - color: white; - background-color: black; - height: 100%; -- font-size: 400%; - } -+.openerp .oe_web_example h4 { -+ margin: 0; -+ font-size: 200%; -+} -+.openerp .oe_web_example.oe_web_example_started .oe_web_example_start button, -+.openerp .oe_web_example.oe_web_example_stopped .oe_web_example_stop button { -+ display: none -+} diff --git a/addons/web/doc/module/16 b/addons/web/doc/module/16 deleted file mode 100644 index 816c23aa0b0..00000000000 --- a/addons/web/doc/module/16 +++ /dev/null @@ -1,25 +0,0 @@ -# HG changeset patch -# Parent 2645d7a09dcba7f6d6074a33252c16c03c56fdf3 -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -2,6 +2,18 @@ - openerp.web_example = function (instance) { - instance.web.client_actions.add('example.action', 'instance.web_example.Action'); - instance.web_example.Action = instance.web.Widget.extend({ -- template: 'web_example.action' -+ template: 'web_example.action', -+ events: { -+ 'click .oe_web_example_start button': 'watch_start', -+ 'click .oe_web_example_stop button': 'watch_stop' -+ }, -+ watch_start: function () { -+ this.$el.addClass('oe_web_example_started') -+ .removeClass('oe_web_example_stopped'); -+ }, -+ watch_stop: function () { -+ this.$el.removeClass('oe_web_example_started') -+ .addClass('oe_web_example_stopped'); -+ }, - }); - }; diff --git a/addons/web/doc/module/17 b/addons/web/doc/module/17 deleted file mode 100644 index d6d6ecc71e3..00000000000 --- a/addons/web/doc/module/17 +++ /dev/null @@ -1,52 +0,0 @@ -# HG changeset patch -# Parent 2921a545adc3406d3139be7951f3225e94493466 -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -7,13 +7,46 @@ openerp.web_example = function (instance - 'click .oe_web_example_start button': 'watch_start', - 'click .oe_web_example_stop button': 'watch_stop' - }, -+ init: function () { -+ this._super.apply(this, arguments); -+ this._start = null; -+ this._watch = null; -+ }, -+ update_counter: function () { -+ var h, m, s; -+ // Subtracting javascript dates returns the difference in milliseconds -+ var diff = new Date() - this._start; -+ s = diff / 1000; -+ m = Math.floor(s / 60); -+ s -= 60*m; -+ h = Math.floor(m / 60); -+ m -= 60*h; -+ this.$('.oe_web_example_timer').text( -+ _.str.sprintf("%02d:%02d:%02d", h, m, s)); -+ }, - watch_start: function () { - this.$el.addClass('oe_web_example_started') - .removeClass('oe_web_example_stopped'); -+ this._start = new Date(); -+ // Update the UI to the current time -+ this.update_counter(); -+ // Update the counter at 30 FPS (33ms/frame) -+ this._watch = setInterval( -+ this.proxy('update_counter'), -+ 33); - }, - watch_stop: function () { -+ clearInterval(this._watch); -+ this.update_counter(); -+ this._start = this._watch = null; - this.$el.removeClass('oe_web_example_started') - .addClass('oe_web_example_stopped'); - }, -+ destroy: function () { -+ if (this._watch) { -+ clearInterval(this._watch); -+ } -+ this._super(); -+ } - }); - }; diff --git a/addons/web/doc/module/18 b/addons/web/doc/module/18 deleted file mode 100644 index 6781c985239..00000000000 --- a/addons/web/doc/module/18 +++ /dev/null @@ -1,19 +0,0 @@ -# HG changeset patch -# Parent e0cc13c2b2ec4d6f6bfdb033b189a32e44106f2e -diff --git a/__init__.py b/__init__.py ---- a/__init__.py -+++ b/__init__.py -@@ -0,0 +1,13 @@ -+# __init__.py -+from openerp.osv import orm, fields -+ -+ -+class Times(orm.Model): -+ _name = 'web_example.stopwatch' -+ -+ _columns = { -+ 'time': fields.integer("Time", required=True, -+ help="Measured time in milliseconds"), -+ 'user_id': fields.many2one('res.users', "User", required=True, -+ help="User who registered the measurement") -+ } diff --git a/addons/web/doc/module/19 b/addons/web/doc/module/19 deleted file mode 100644 index d95a89a3441..00000000000 --- a/addons/web/doc/module/19 +++ /dev/null @@ -1,52 +0,0 @@ -# HG changeset patch -# Parent 05797cc75b49634e640f44b24347f2905b464022 -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -12,11 +12,13 @@ openerp.web_example = function (instance - this._start = null; - this._watch = null; - }, -- update_counter: function () { -+ current: function () { -+ // Subtracting javascript dates returns the difference in milliseconds -+ return new Date() - this._start; -+ }, -+ update_counter: function (time) { - var h, m, s; -- // Subtracting javascript dates returns the difference in milliseconds -- var diff = new Date() - this._start; -- s = diff / 1000; -+ s = time / 1000; - m = Math.floor(s / 60); - s -= 60*m; - h = Math.floor(m / 60); -@@ -29,18 +31,24 @@ openerp.web_example = function (instance - .removeClass('oe_web_example_stopped'); - this._start = new Date(); - // Update the UI to the current time -- this.update_counter(); -+ this.update_counter(this.current()); - // Update the counter at 30 FPS (33ms/frame) -- this._watch = setInterval( -- this.proxy('update_counter'), -+ this._watch = setInterval(function () { -+ this.update_counter(this.current()); -+ }.bind(this), - 33); - }, - watch_stop: function () { - clearInterval(this._watch); -- this.update_counter(); -+ var time = this.current(); -+ this.update_counter(time); - this._start = this._watch = null; - this.$el.removeClass('oe_web_example_started') - .addClass('oe_web_example_stopped'); -+ new instance.web.Model('web_example.stopwatch').call('create', [{ -+ user_id: instance.session.uid, -+ time: time, -+ }]); - }, - destroy: function () { - if (this._watch) { diff --git a/addons/web/doc/module/2 b/addons/web/doc/module/2 deleted file mode 100644 index 7d8e9f05597..00000000000 --- a/addons/web/doc/module/2 +++ /dev/null @@ -1,12 +0,0 @@ -# HG changeset patch -# Parent 8a986919a3e22cd7cca51210820c09d4545dc60d -diff --git a/__manifest__.py b/__manifest__.py ---- a/__manifest__.py -+++ b/__manifest__.py -@@ -3,5 +3,5 @@ - 'name': "Web Example", - 'description': "Basic example of a (future) web module", - 'category': 'Hidden', -- 'depends': ['base'], -+ 'depends': ['web'], - } diff --git a/addons/web/doc/module/20 b/addons/web/doc/module/20 deleted file mode 100644 index 042ff28067c..00000000000 --- a/addons/web/doc/module/20 +++ /dev/null @@ -1,64 +0,0 @@ -Index: web_example/static/src/js/first_module.js -=================================================================== ---- web_example.orig/static/src/js/first_module.js -+++ web_example/static/src/js/first_module.js -@@ -11,20 +11,36 @@ openerp.web_example = function (instance - this._super.apply(this, arguments); - this._start = null; - this._watch = null; -+ this.model = new instance.web.Model('web_example.stopwatch'); -+ }, -+ start: function () { -+ var display = this.display_record.bind(this); -+ return this.model.query() -+ .filter([['user_id', '=', instance.session.uid]]) -+ .all().done(function (records) { -+ _(records).each(display); -+ }); - }, - current: function () { - // Subtracting javascript dates returns the difference in milliseconds - return new Date() - this._start; - }, -- update_counter: function (time) { -+ display_record: function (record) { -+ $('
  • ') -+ .text(this.format_time(record.time)) -+ .appendTo(this.$('.oe_web_example_saved')); -+ }, -+ format_time: function (time) { - var h, m, s; - s = time / 1000; - m = Math.floor(s / 60); - s -= 60*m; - h = Math.floor(m / 60); - m -= 60*h; -- this.$('.oe_web_example_timer').text( -- _.str.sprintf("%02d:%02d:%02d", h, m, s)); -+ return _.str.sprintf("%02d:%02d:%02d", h, m, s); -+ }, -+ update_counter: function (time) { -+ this.$('.oe_web_example_timer').text(this.format_time(time)); - }, - watch_start: function () { - this.$el.addClass('oe_web_example_started') -@@ -45,7 +61,7 @@ openerp.web_example = function (instance - this._start = this._watch = null; - this.$el.removeClass('oe_web_example_started') - .addClass('oe_web_example_stopped'); -- new instance.web.Model('web_example.stopwatch').call('create', [{ -+ this.model.call('create', [{ - user_id: instance.session.uid, - time: time, - }]); -Index: web_example/static/src/xml/web_example.xml -=================================================================== ---- web_example.orig/static/src/xml/web_example.xml -+++ web_example/static/src/xml/web_example.xml -@@ -7,5 +7,6 @@ -

    - -

    -+
      - - diff --git a/addons/web/doc/module/21 b/addons/web/doc/module/21 deleted file mode 100644 index 0acfac9001d..00000000000 --- a/addons/web/doc/module/21 +++ /dev/null @@ -1,27 +0,0 @@ -Index: web_example/static/src/js/first_module.js -=================================================================== ---- web_example.orig/static/src/js/first_module.js -+++ web_example/static/src/js/first_module.js -@@ -55,16 +55,20 @@ openerp.web_example = function (instance - 33); - }, - watch_stop: function () { -+ var self = this; - clearInterval(this._watch); - var time = this.current(); - this.update_counter(time); - this._start = this._watch = null; - this.$el.removeClass('oe_web_example_started') - .addClass('oe_web_example_stopped'); -- this.model.call('create', [{ -+ var record = { - user_id: instance.session.uid, - time: time, -- }]); -+ }; -+ this.model.call('create', [record]).done(function () { -+ self.display_record(record); -+ }); - }, - destroy: function () { - if (this._watch) { diff --git a/addons/web/doc/module/22 b/addons/web/doc/module/22 deleted file mode 100644 index 5df76b303e4..00000000000 --- a/addons/web/doc/module/22 +++ /dev/null @@ -1,6 +0,0 @@ -Index: web_example/static/src/tests/timer.js -=================================================================== ---- /dev/null -+++ web_example/static/src/tests/timer.js -@@ -0,0 +1 @@ -+ diff --git a/addons/web/doc/module/23 b/addons/web/doc/module/23 deleted file mode 100644 index d08a026a976..00000000000 --- a/addons/web/doc/module/23 +++ /dev/null @@ -1,14 +0,0 @@ -Index: web_example/static/src/tests/timer.js -=================================================================== ---- web_example.orig/static/src/tests/timer.js -+++ web_example/static/src/tests/timer.js -@@ -1 +1,8 @@ -- -+openerp.testing.section('timer', function (test) { -+ test('successful test', function () { -+ ok(true, "should work"); -+ }); -+ test('unsuccessful test', function () { -+ ok(false, "shoud fail"); -+ }); -+}); diff --git a/addons/web/doc/module/24 b/addons/web/doc/module/24 deleted file mode 100644 index 0972e856042..00000000000 --- a/addons/web/doc/module/24 +++ /dev/null @@ -1,10 +0,0 @@ -Index: web_example/__manifest__.py -=================================================================== ---- web_example.orig/__manifest__.py -+++ web_example/__manifest__.py -@@ -8,4 +8,5 @@ - 'js': ['static/src/js/first_module.js'], - 'css': ['static/src/css/web_example.css'], - 'qweb': ['static/src/xml/web_example.xml'], -+ 'test': ['static/src/tests/timer.js'], - } diff --git a/addons/web/doc/module/25 b/addons/web/doc/module/25 deleted file mode 100644 index 1d63dc7f4a3..00000000000 --- a/addons/web/doc/module/25 +++ /dev/null @@ -1,55 +0,0 @@ -Index: web_example/static/src/tests/timer.js -=================================================================== ---- web_example.orig/static/src/tests/timer.js -+++ web_example/static/src/tests/timer.js -@@ -1,8 +1,45 @@ - openerp.testing.section('timer', function (test) { -- test('successful test', function () { -- ok(true, "should work"); -- }); -- test('unsuccessful test', function () { -- ok(false, "shoud fail"); -+ test('format_time', function (instance) { -+ var w = new instance.web_example.Action(); -+ -+ strictEqual( -+ w.format_time(0), -+ '00:00:00'); -+ strictEqual( -+ w.format_time(543), -+ '00:00:00', -+ "should round sub-second times down to zero"); -+ strictEqual( -+ w.format_time(5340), -+ '00:00:05', -+ "should floor sub-second extents to the previous second"); -+ strictEqual( -+ w.format_time(60000), -+ '00:01:00'); -+ strictEqual( -+ w.format_time(3600000), -+ '01:00:00'); -+ strictEqual( -+ w.format_time(86400000), -+ '24:00:00'); -+ strictEqual( -+ w.format_time(604800000), -+ '168:00:00'); -+ -+ strictEqual( -+ w.format_time(22733958), -+ '06:18:53'); -+ strictEqual( -+ w.format_time(41676639), -+ '11:34:36'); -+ strictEqual( -+ w.format_time(57802094), -+ '16:03:22'); -+ strictEqual( -+ w.format_time(73451828), -+ '20:24:11'); -+ strictEqual( -+ w.format_time(84092336), -+ '23:21:32'); - }); - }); diff --git a/addons/web/doc/module/26 b/addons/web/doc/module/26 deleted file mode 100644 index ec0b345a908..00000000000 --- a/addons/web/doc/module/26 +++ /dev/null @@ -1,38 +0,0 @@ -Index: web_example/static/src/tests/timer.js -=================================================================== ---- web_example.orig/static/src/tests/timer.js -+++ web_example/static/src/tests/timer.js -@@ -42,4 +42,33 @@ openerp.testing.section('timer', functio - w.format_time(84092336), - '23:21:32'); - }); -+ test('update_counter', function (instance, $fixture) { -+ var w = new instance.web_example.Action(); -+ // $fixture is a DOM tree whose content gets cleaned up before -+ // each test, so we can add whatever we need to it -+ $fixture.append('
      '); -+ // Then set it on the widget -+ w.setElement($fixture); -+ -+ // Update the counter with a known value -+ w.update_counter(22733958); -+ // And check the DOM matches -+ strictEqual($fixture.text(), '06:18:53'); -+ -+ w.update_counter(73451828) -+ strictEqual($fixture.text(), '20:24:11'); -+ }); -+ test('display_record', function (instance, $fixture) { -+ var w = new instance.web_example.Action(); -+ $fixture.append('
        ') -+ w.setElement($fixture); -+ -+ w.display_record({time: 41676639}); -+ w.display_record({time: 84092336}); -+ -+ var $lis = $fixture.find('li'); -+ strictEqual($lis.length, 2, "should have printed 2 records"); -+ strictEqual($lis[0].textContent, '11:34:36'); -+ strictEqual($lis[1].textContent, '23:21:32'); -+ }); - }); diff --git a/addons/web/doc/module/27 b/addons/web/doc/module/27 deleted file mode 100644 index 2061b7007e6..00000000000 --- a/addons/web/doc/module/27 +++ /dev/null @@ -1,28 +0,0 @@ -Index: web_example/static/src/tests/timer.js -=================================================================== ---- web_example.orig/static/src/tests/timer.js -+++ web_example/static/src/tests/timer.js -@@ -71,4 +71,23 @@ openerp.testing.section('timer', functio - strictEqual($lis[0].textContent, '11:34:36'); - strictEqual($lis[1].textContent, '23:21:32'); - }); -+ test('start', {templates: true, rpc: 'mock', asserts: 3}, function (instance, $fixture, mock) { -+ // Rather odd-looking shortcut for search+read in a single RPC call -+ mock('/web/dataset/search_read', function () { -+ // ignore parameters, just return a pair of records. -+ return {records: [ -+ {time: 22733958}, -+ {time: 84092336} -+ ]}; -+ }); -+ -+ var w = new instance.web_example.Action(); -+ return w.appendTo($fixture) -+ .then(function () { -+ var $lis = $fixture.find('li'); -+ strictEqual($lis.length, 2); -+ strictEqual($lis[0].textContent, '06:18:53'); -+ strictEqual($lis[1].textContent, '23:21:32'); -+ }); -+ }); - }); diff --git a/addons/web/doc/module/28 b/addons/web/doc/module/28 deleted file mode 100644 index 800e7a6f084..00000000000 --- a/addons/web/doc/module/28 +++ /dev/null @@ -1,13 +0,0 @@ -Index: web_example/static/src/js/first_module.js -=================================================================== ---- web_example.orig/static/src/js/first_module.js -+++ web_example/static/src/js/first_module.js -@@ -66,7 +66,7 @@ openerp.web_example = function (instance - user_id: instance.session.uid, - time: time, - }; -- this.model.call('create', [record]).done(function () { -+ return this.model.call('create', [record]).done(function () { - self.display_record(record); - }); - }, diff --git a/addons/web/doc/module/29 b/addons/web/doc/module/29 deleted file mode 100644 index 509d4b78662..00000000000 --- a/addons/web/doc/module/29 +++ /dev/null @@ -1,37 +0,0 @@ -Index: web_example/static/src/tests/timer.js -=================================================================== ---- web_example.orig/static/src/tests/timer.js -+++ web_example/static/src/tests/timer.js -@@ -90,4 +90,32 @@ openerp.testing.section('timer', functio - strictEqual($lis[1].textContent, '23:21:32'); - }); - }); -+ test('watch_stop', {templates: true, rpc: 'mock', asserts: 3}, function (instance, $fix, mock) { -+ var created = false; -+ mock('web_example.stopwatch:create', function (args, kwargs) { -+ created = true; -+ // return a fake id (unused) -+ return 42; -+ }); -+ mock('/web/dataset/search_read', function () { -+ return {records: []}; -+ }); -+ -+ var w = new instance.web_example.Action(); -+ return w.appendTo($fix) -+ .then(function () { -+ // Virtual start point 5s before 'now' -+ w._start = new Date() - 5000; -+ return w.watch_stop(); -+ }) -+ .done(function () { -+ ok(created, "should have called create()"); -+ strictEqual($fix.find('.oe_web_example_timer').text(), -+ '00:00:05', -+ "should have updated the timer"); -+ strictEqual($fix.find('li')[0].textContent, -+ '00:00:05', -+ "should have added the new time to the list"); -+ }); -+ }); - }); diff --git a/addons/web/doc/module/3 b/addons/web/doc/module/3 deleted file mode 100644 index c09925f93d4..00000000000 --- a/addons/web/doc/module/3 +++ /dev/null @@ -1,9 +0,0 @@ -# HG changeset patch -# Parent dcf661a5eef8f82503831bdb8e6c9d2f9beb285e -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js -new file mode 100644 ---- /dev/null -+++ b/static/src/js/first_module.js -@@ -0,0 +1,2 @@ -+// static/src/js/first_module.js -+console.log("Debug statement: file loaded"); diff --git a/addons/web/doc/module/4 b/addons/web/doc/module/4 deleted file mode 100644 index 99c073d672a..00000000000 --- a/addons/web/doc/module/4 +++ /dev/null @@ -1,11 +0,0 @@ -# HG changeset patch -# Parent 139dae60de67efa0017f5032f71ab774685c5507 -diff --git a/__manifest__.py b/__manifest__.py ---- a/__manifest__.py -+++ b/__manifest__.py -@@ -4,4 +4,5 @@ - 'description': "Basic example of a (future) web module", - 'category': 'Hidden', - 'depends': ['web'], -+ 'js': ['static/src/js/first_module.js'], - } diff --git a/addons/web/doc/module/5 b/addons/web/doc/module/5 deleted file mode 100644 index 49acad9cd52..00000000000 --- a/addons/web/doc/module/5 +++ /dev/null @@ -1,11 +0,0 @@ -# HG changeset patch -# Parent c8ae7646cce3f271698c844eb2d67f9a8719650d -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -1,2 +1,4 @@ - // static/src/js/first_module.js --console.log("Debug statement: file loaded"); -+openerp.web_example = function (instance) { -+ console.log("Module loaded"); -+}; diff --git a/addons/web/doc/module/6 b/addons/web/doc/module/6 deleted file mode 100644 index 3a1232fa51c..00000000000 --- a/addons/web/doc/module/6 +++ /dev/null @@ -1,29 +0,0 @@ -# HG changeset patch -# Parent 0026cb80097a724db8d36371bc00da993a51a06f - -diff --git a/__manifest__.py b/__manifest__.py ---- a/__manifest__.py -+++ b/__manifest__.py -@@ -4,5 +4,6 @@ - 'description': "Basic example of a (future) web module", - 'category': 'Hidden', - 'depends': ['web'], -+ 'data': ['web_example.xml'], - 'js': ['static/src/js/first_module.js'], - } -diff --git a/web_example.xml b/web_example.xml -new file mode 100644 ---- /dev/null -+++ b/web_example.xml -@@ -0,0 +1,11 @@ -+ -+ -+ -+ -+ Example Client Action -+ example.action -+ -+ -+ -+ diff --git a/addons/web/doc/module/8 b/addons/web/doc/module/8 deleted file mode 100644 index 83e6c371bb3..00000000000 --- a/addons/web/doc/module/8 +++ /dev/null @@ -1,14 +0,0 @@ -# HG changeset patch -# Parent d987c9edd884de1de30f2ceb70d2e554474b8dd1 -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -1,4 +1,7 @@ - // static/src/js/first_module.js - openerp.web_example = function (instance) { -- console.log("Module loaded"); -+ instance.web.client_actions.add('example.action', 'instance.web_example.action'); -+ instance.web_example.action = function (parent, action) { -+ console.log("Executed the action", action); -+ }; - }; diff --git a/addons/web/doc/module/9 b/addons/web/doc/module/9 deleted file mode 100644 index 9113f914e7c..00000000000 --- a/addons/web/doc/module/9 +++ /dev/null @@ -1,21 +0,0 @@ -# HG changeset patch -# Parent 6a1a7240ea0e63182f60abb1eb5c631089d56dbe -diff --git a/static/src/js/first_module.js b/static/src/js/first_module.js ---- a/static/src/js/first_module.js -+++ b/static/src/js/first_module.js -@@ -1,7 +1,11 @@ - // static/src/js/first_module.js - openerp.web_example = function (instance) { -- instance.web.client_actions.add('example.action', 'instance.web_example.action'); -- instance.web_example.action = function (parent, action) { -- console.log("Executed the action", action); -- }; -+ instance.web.client_actions.add('example.action', 'instance.web_example.Action'); -+ instance.web_example.Action = instance.web.Widget.extend({ -+ className: 'oe_web_example', -+ start: function () { -+ this.$el.text("Hello, world!"); -+ return this._super(); -+ } -+ }); - }; diff --git a/addons/web/doc/module/series b/addons/web/doc/module/series deleted file mode 100644 index ff1a909a6af..00000000000 --- a/addons/web/doc/module/series +++ /dev/null @@ -1,27 +0,0 @@ -0 -2 -3 -4 -5 -6 -8 -9 -10 -11 -12 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 diff --git a/addons/web/doc/module/testing_0.png b/addons/web/doc/module/testing_0.png deleted file mode 100644 index 62711799ff7..00000000000 Binary files a/addons/web/doc/module/testing_0.png and /dev/null differ diff --git a/addons/web/doc/module/testing_1.png b/addons/web/doc/module/testing_1.png deleted file mode 100644 index 40cf32497eb..00000000000 Binary files a/addons/web/doc/module/testing_1.png and /dev/null differ diff --git a/addons/web/doc/search_view.rst b/addons/web/doc/search_view.rst deleted file mode 100644 index 76692a0d775..00000000000 --- a/addons/web/doc/search_view.rst +++ /dev/null @@ -1,560 +0,0 @@ -Search View -=========== - -OpenERP Web 7.0 implements a unified facets-based search view instead -of the previous form-like search view (composed of buttons and -multiple fields). The goal for this change is twofold: - -* Avoid the common issue of users confusing the search view with a - form view and trying to create their records through it (or entering - all their data, hitting the ``Create`` button expecting their record - to be created and losing everything). - -* Improve the looks and behaviors of the view, and the fit within - OpenERP Web's new design. - -The internal structure of the faceted search is inspired by -`VisualSearch `_ -[#previous]_. - -As does VisualSearch, the new search view is based on `Backbone`_ and -makes significant use of Backbone's models and collections (OpenERP -Web's widgets make a good replacement for Backbone's own views). As a -result, understanding the implementation details of the OpenERP Web 7 -search view also requires a basic understanding of Backbone's models, -collections and events. - -.. note:: - - This document may mention *fetching* data. This is a shortcut for - "returning a :js:class:`Deferred` to [whatever is being - fetched]". Unless further noted, the function or method may opt to - return nothing by fetching ``null`` (which can easily be done by - returning ``$.when(null)``, which simply wraps the ``null`` in a - Deferred). - -Working with the search view: creating new inputs -------------------------------------------------- - -The primary component of search views, as with all other OpenERP -views, are inputs. The search view has two types of inputs — filters -and fields — but only one is easly customizable: fields. - -The mapping from OpenERP field types (and widgets) to search view -objects is stored in the ``openerp.web.search.fields`` -:js:class:`~openerp.web.Registry` where new field types and widgets -can be added. - -Search view inputs have four main roles: - -Loading defaults -++++++++++++++++ - -Once the search view has initialized all its inputs, it will call -:js:func:`~openerp.web.search.Input.facet_for_defaults` on each input, -passing it a mapping (a javascript object) of ``name:value`` extracted -from the action's context. - -This method should fetch a :js:class:`~openerp.web.search.Facet` (or -an equivalent object) for the field's default value if applicable (if -a default value for the field is found in the ``defaults`` mapping). - -A default implementation is provided which checks if ``defaults`` -contains a non-falsy value for the field's ``@name`` and calls -:js:func:`openerp.web.search.Input.facet_for` with that value. - -There is no default implementation of -:js:func:`openerp.web.search.Input.facet_for` [#no_impl]_, but -:js:class:`openerp.web.search.Field` provides one, which uses the -value as-is to fetch a :js:class:`~openerp.web.search.Facet`. - -Providing completions -+++++++++++++++++++++ - -An important component of the new search view is the auto-completion -pane, and the task of providing completion items is delegated to -inputs through the :js:func:`~openerp.web.search.Input.complete` -method. - -This method should take a single argument (the string being typed by -the user) and should fetch an ``Array`` of possible completions -[#completion]_. - -A default implementation is provided which fetches nothing. - -A completion item is a javascript object with two keys (technically it -can have any number of keys, but only these two will be used by the -search view): - -``label`` - - The string which will be displayed in the completion pane. It may - be formatted using HTML (inline only), as a result if ``value`` is - interpolated into it it *must* be escaped. ``_.escape`` can be - used for this. - -``facet`` - - Either a :js:class:`~openerp.web.search.Facet` object or (more - commonly) the corresponding attributes object. This is the facet - which will be inserted into the search query if the completion - item is selected by the user. - -If the ``facet`` is not provided (not present, ``null``, ``undefined`` -or any other falsy value), the completion item will not be selectable -and will act as a section title of sort (the ``label`` will be -formatted differently). If an input *may* fetch multiple completion -items, it *should* prefix those with a section title using its own -name. This has no technical consequence but is clearer for users. - -.. note:: - - If a field is :js:func:`invisible - `, its completion function will - *not* be called. - -Providing drawer/supplementary UI -+++++++++++++++++++++++++++++++++ - -For some inputs (fields or not), interaction via autocompletion may be -awkward or even impossible. - -These may opt to being rendered in a "drawer" as well or instead. In -that case, they will undergo the normal widget lifecycle and be -rendered inside the drawer. - -.. Found no good type-based way to handle this, since there is no MI - (so no type-tagging) and it's possible for both Field and non-Field - input to be put into the drawer, for whatever reason (e.g. some - sort of auto-detector completion item for date widgets, but a - second more usual calendar widget in the drawer for more - obvious/precise interactions) - -Any input can note its desire to be rendered in the drawer by -returning a truthy value from -:js:func:`~openerp.web.search.Input.in_drawer`. - -By default, :js:func:`~openerp.web.search.Input.in_drawer` returns the -value of :js:attr:`~openerp.web.search.Input._in_drawer`, which is -``false``. The behavior can be toggled either by redefining the -attribute to ``true`` (either on the class or on the input), or by -overriding :js:func:`~openerp.web.search.Input.in_drawer` itself. - -The input will be rendered in the full width of the drawer, it will be -started only once (per view). - -.. todo:: drawer API (if a widget wants to close the drawer in some - way), part of the low-level SearchView API/interactions? - - -.. todo:: handle filters and filter groups via a "driver" input which - dynamically collects, lays out and renders filters? => - exercises drawer thingies - -.. note:: - - An :js:func:`invisible ` input - will not be inserted into the drawer. - -Converting from facet objects -+++++++++++++++++++++++++++++ - -Ultimately, the point of the search view is to allow searching. In -OpenERP this is done via :ref:`domains `. On -the other hand, the OpenERP Web 7 search view's state is modelled -after a collection of :js:class:`~openerp.web.search.Facet`, and each -field of a search view may have special requirements when it comes to -the domains it produces [#special]_. - -So there needs to be some way of mapping -:js:class:`~openerp.web.search.Facet` objects to OpenERP search data. - -This is done via an input's -:js:func:`~openerp.web.search.Input.get_domain` and -:js:func:`~openerp.web.search.Input.get_context`. Each takes a -:js:class:`~openerp.web.search.Facet` and returns whatever it's -supposed to generate (a domain or a context, respectively). Either can -return ``null`` if the current value does not map to a domain or -context, and can throw an :js:class:`~openerp.web.search.Invalid` -exception if the value is not valid at all for the field. - -.. note:: - - The :js:class:`~openerp.web.search.Facet` object can have any - number of values (from 1 upwards) - -.. note:: - - There is a third conversion method, - :js:func:`~openerp.web.search.Input.get_groupby`, which returns an - ``Array`` of groupby domains rather than a single context. At this - point, it is only implemented on (and used by) filters. - -Programmatic interactions: internal model ------------------------------------------ - -This new searchview is built around an instance of -:js:class:`~openerp.web.search.SearchQuery` available as -:js:attr:`openerp.web.SearchView.query`. - -The query is a `backbone collection`_ of -:js:class:`~openerp.web.search.Facet` objects, which can be interacted -with directly by external objects or search view controls -(e.g. widgets displayed in the drawer). - -.. js:class:: openerp.web.search.SearchQuery - - The current search query of the search view, provides convenience - behaviors for manipulating :js:class:`~openerp.web.search.Facet` - on top of the usual `backbone collection`_ methods. - - The query ensures all of its facets contain at least one - :js:class:`~openerp.web.search.FacetValue` instance. Otherwise, - the facet is automatically removed from the query. - - .. js:function:: openerp.web.search.SearchQuery.add(values, options) - - Overridden from the base ``add`` method so that adding a facet - which is *already* in the collection will merge the value of - the new facet into the old one rather than add a second facet - with different values. - - :param values: facet, facet attributes or array thereof - :returns: the collection itself - - .. js:function:: openerp.web.search.SearchQuery.toggle(value, options) - - Convenience method for toggling facet values in a query: - removes the values (through the facet itself) if they are - present, adds them if they are not. If the facet itself is not - in the collection, adds it automatically. - - A toggling is atomic: only one change event will be triggered - on the facet regardless of the number of values added to or - removed from the facet (if the facet already exists), and the - facet is only removed from the query if it has no value *at - the end* of the toggling. - - :param value: facet or facet attributes - :returns: the collection - -.. js:class:: openerp.web.search.Facet - - A `backbone model`_ representing a single facet of the current - search. May map to a search field, or to a more complex or - fuzzier input (e.g. a custom filter or an advanced search). - - .. js:attribute:: category - - The displayed name of the facet, as a ``String``. This is a - backbone model attribute. - - .. js:attribute:: field - - The :js:class:`~openerp.web.search.Input` instance which - originally created the facet [#facet-field]_, used to delegate - some operations (such as serializing the facet's values to - domains and contexts). This is a backbone model attribute. - - .. js:attribute:: values - - :js:class:`~openerp.web.search.FacetValues` as a javascript - attribute, stores all the values for the facet and helps - propagate their events to the facet. Is also available as a - backbone attribute (via ``#get`` and ``#set``) in which cases - it serializes to and deserializes from javascript arrays (via - ``Collection#toJSON`` and ``Collection#reset``). - - .. js:attribute:: [icon] - - optional, a single ASCII letter (a-z or A-Z) mapping to the - bundled mnmliconsRegular icon font. - - When a facet with an ``icon`` attribute is rendered, the icon - is displayed (in the icon font) in the first section of the - facet instead of the ``category``. - - By default, only filters make use of this facility. - -.. js:class:: openerp.web.search.FacetValues - - `Backbone collection`_ of - :js:class:`~openerp.web.search.FacetValue` instances. - -.. js:class:: openerp.web.search.FacetValue - - `Backbone model`_ representing a single value within a facet, - represents a pair of (displayed name, logical value). - - .. js:attribute:: label - - Backbone model attribute storing the "displayable" - representation of the value, visually output to the - user. Must be a string. - - .. js:attribute:: value - - Backbone model attribute storing the logical/internal value - (of itself), will be used by - :js:class:`~openerp.web.search.Input` to serialize to domains - and contexts. - - Can be of any type. - -Field services --------------- - -:js:class:`~openerp.web.search.Field` provides a default -implementation of :js:func:`~openerp.web.search.Input.get_domain` and -:js:func:`~openerp.web.search.Input.get_context` taking care of most -of the peculiarities pertaining to OpenERP's handling of fields in -search views. It also provides finer hooks to let developers of new -fields and widgets customize the behavior they want without -necessarily having to reimplement all of -:js:func:`~openerp.web.search.Input.get_domain` or -:js:func:`~openerp.web.search.Input.get_context`: - -.. js:function:: openerp.web.search.Field.get_context(facet) - - If the field has no ``@context``, simply returns - ``null``. Otherwise, calls - :js:func:`~openerp.web.search.Field.value_from` once for each - :js:class:`~openerp.web.search.FacetValue` of the current - :js:class:`~openerp.web.search.Facet` (in order to extract the - basic javascript object from the - :js:class:`~openerp.web.search.FacetValue` then evaluates - ``@context`` with each of these values set as ``self``, and - returns the union of all these contexts. - - :param facet: - :type facet: openerp.web.search.Facet - :returns: a context (literal or compound) - -.. js:function:: openerp.web.search.Field.get_domain(facet) - - If the field has no ``@filter_domain``, calls - :js:func:`~openerp.web.search.Field.make_domain` once with each - :js:class:`~openerp.web.search.FacetValue` of the current - :js:class:`~openerp.web.search.Facet` as well as the field's - ``@name`` and either its ``@operator`` or - :js:attr:`~openerp.web.search.Field.default_operator`. - - If the field has an ``@filter_value``, calls - :js:func:`~openerp.web.search.Field.value_from` once per - :js:class:`~openerp.web.search.FacetValue` and evaluates - ``@filter_value`` with each of these values set as ``self``. - - In either case, "ors" all of the resulting domains (using ``|``) - if there is more than one - :js:class:`~openerp.web.search.FacetValue` and returns the union - of the result. - - :param facet: - :type facet: openerp.web.search.Facet - :returns: a domain (literal or compound) - -.. js:function:: openerp.web.search.Field.make_domain(name, operator, facetValue) - - Builds a literal domain from the provided data. Calls - :js:func:`~openerp.web.search.Field.value_from` on the - :js:class:`~openerp.web.search.FacetValue` and evaluates and sets - it as the domain's third value, uses the other two parameters as - the first two values. - - Can be overridden to build more complex default domains. - - :param String name: the field's name - :param String operator: the operator to use in the field's domain - :param facetValue: - :type facetValue: openerp.web.search.FacetValue - :returns: Array<(String, String, Object)> - -.. js:function:: openerp.web.search.Field.value_from(facetValue) - - Extracts a "bare" javascript value from the provided - :js:class:`~openerp.web.search.FacetValue`, and returns it. - - The default implementation will simply return the ``value`` - backbone property of the argument. - - :param facetValue: - :type facetValue: openerp.web.search.FacetValue - :returns: Object - -.. js:attribute:: openerp.web.search.Field.default_operator - - Operator used to build a domain when a field has no ``@operator`` - or ``@filter_domain``. ``"="`` for - :js:class:`~openerp.web.search.Field` - -Arbitrary data storage ----------------------- - -:js:class:`~openerp.web.search.Facet` and -:js:class:`~openerp.web.search.FacetValue` objects (and structures) -provided by your widgets should never be altered by the search view -(or an other widget). This means you are free to add arbitrary fields -in these structures if you need to (because you have more complex -needs than the attributes described in this document). - -Ideally this should be avoided, but the possibility remains. - -Changes -------- - -.. todo:: merge in changelog instead? - -The displaying of the search view was significantly altered from -OpenERP Web 6.1 to OpenERP Web 7. - -As a result, while the external API used to interact with the search -view does not change many internal details — including the interaction -between the search view and its widgets — were significantly altered: - -Internal operations -+++++++++++++++++++ - -* :js:func:`openerp.web.SearchView.do_clear` has been removed -* :js:func:`openerp.web.SearchView.do_toggle_filter` has been removed - -Widgets API -+++++++++++ - -* :js:func:`openerp.web.search.Widget.render` has been removed - -* :js:func:`openerp.web.search.Widget.make_id` has been removed - -* Search field objects are not openerp widgets anymore, their - ``start`` is not generally called - -* :js:func:`~openerp.web.search.Input.clear` has been removed since - clearing the search view now simply consists of removing all search - facets - -* :js:func:`~openerp.web.search.Input.get_domain` and - :js:func:`~openerp.web.search.Input.get_context` now take a - :js:class:`~openerp.web.search.Facet` as parameter, from which it's - their job to get whatever value they want - -* :js:func:`~openerp.web.search.Input.get_groupby` has been added. It returns - an :js:class:`Array` of context-like constructs. By default, it does not do - anything in :js:class:`~openerp.web.search.Field` and it returns the various - contexts of its enabled filters in - :js:class:`~openerp.web.search.FilterGroup`. - -Filters -+++++++ - -* :js:func:`openerp.web.search.Filter.is_enabled` has been removed - -* :js:class:`~openerp.web.search.FilterGroup` instances are still - rendered (and started) in the "advanced search" drawer. - -Fields -++++++ - -* ``get_value`` has been replaced by - :js:func:`~openerp.web.search.Field.value_from` as it now takes a - :js:class:`~openerp.web.search.FacetValue` argument (instead of no - argument). It provides a default implementation returning the - ``value`` property of its argument. - -* The third argument to - :js:func:`~openerp.web.search.Field.make_domain` is now a - :js:class:`~openerp.web.search.FacetValue` so child classes have all - the information they need to derive the "right" resulting domain. - -Custom filters -++++++++++++++ - -Instead of being an intrinsic part of the search view, custom filters -are now a special case of filter groups. They are treated specially -still, but much less so than they used to be. - -Many To One -+++++++++++ - -* Because the autocompletion service is now provided by the search - view itself, - :js:func:`openerp.web.search.ManyToOneField.setup_autocomplete` has - been removed. - -Advanced Search -+++++++++++++++ - -* The advanced search is now a more standard - :js:class:`~openerp.web.search.Input` configured to be rendered in - the drawer. - -* :js:class:`~openerp.web.search.ExtendedSearchProposition.Field` are - now standard widgets, with the "right" behaviors (they don't rebind - their ``$element`` in ``start()``) - -* The ad-hoc optional setting of the openerp field descriptor on a - :js:class:`~openerp.web.search.ExtendedSearchProposition.Field` has - been removed, the field descriptor is now passed as second argument - to the - :js:class:`~openerp.web.search.ExtendedSearchProposition.Field`'s - constructor, and bound to its - :js:attr:`~openerp.web.search.ExtendedSearchProposition.Field.field`. - -* Instead of its former domain triplet ``(field, operator, value)``, - :js:func:`~openerp.web.search.ExtendedSearchProposition.get_proposition` - now returns an object with two fields ``label`` and ``value``, - respectively a human-readable version of the proposition and the - corresponding domain triplet for the proposition. - -.. [#previous] - - the original view was implemented on top of a monkey-patched - VisualSearch, but as our needs diverged from VisualSearch's goal - this made less and less sense ultimately leading to a clean-room - reimplementation - -.. [#no_impl] - - In case you are extending the search view with a brand new type of - input - -.. [#completion] - - Ideally this array should not hold more than about 10 items, but - the search view does not put any constraint on this at the - moment. Note that this may change. - -.. [#facet-field] - - ``field`` does not actually need to be an instance of - :js:class:`~openerp.web.search.Input`, nor does it need to be what - created the facet, it just needs to provide the three - facet-serialization methods - :js:func:`~openerp.web.search.Input.get_domain`, - :js:func:`~openerp.web.search.Input.get_context` and - :js:func:`~openerp.web.search.Input.get_gropuby`, existing - :js:class:`~openerp.web.search.Input` subtypes merely provide - convenient base implementation for those methods. - - Complex search view inputs (especially those living in the drawer) - may prefer using object literals with the right slots returning - closed-over values or some other scheme un-bound to an actual - :js:class:`~openerp.web.search.Input`, as - :js:class:`~openerp.web.search.CustomFilters` and - :js:class:`~openerp.web.search.Advanced` do. - -.. [#special] - - search view fields may also bundle context data to add to the - search context - -.. _Backbone: - http://documentcloud.github.com/backbone/ - -.. _Backbone.Collection: -.. _Backbone collection: - http://documentcloud.github.com/backbone/#Collection - -.. _Backbone model: - http://documentcloud.github.com/backbone/#Model - -.. _commit 3fca87101d: - https://github.com/documentcloud/visualsearch/commit/3fca87101d