diff --git a/LICENSE.web b/LICENSE.web
new file mode 100644
index 00000000000..dba13ed2ddf
--- /dev/null
+++ b/LICENSE.web
@@ -0,0 +1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
diff --git a/README.web b/README.web
new file mode 100644
index 00000000000..7aff74c76c4
--- /dev/null
+++ b/README.web
@@ -0,0 +1,11 @@
+OpenERP Web
+-----------
+
+The OpenERP Web Client supports the following web browsers:
+
+* Internet Explorer 9+
+* Google Chrome 22+
+* Firefox 13+
+* Any browser using the latest version of Chrome Frame
+
+
diff --git a/addons/web/doc/async.rst b/addons/web/doc/async.rst
index 23b3409bd8f..bd23d5a31d3 100644
--- a/addons/web/doc/async.rst
+++ b/addons/web/doc/async.rst
@@ -1,5 +1,5 @@
-Don't stop the world now: asynchronous development and Javascript
-=================================================================
+Asynchronous Operations
+=======================
As a language (and runtime), javascript is fundamentally
single-threaded. This means any blocking request or computation will
diff --git a/addons/web/doc/changelog-7.0.rst b/addons/web/doc/changelog-7.0.rst
index dd08f1bcde7..b801c11b945 100644
--- a/addons/web/doc/changelog-7.0.rst
+++ b/addons/web/doc/changelog-7.0.rst
@@ -95,8 +95,8 @@ DataGroup -> also Model
-----------------------
Alongside the deprecation of ``DataSet`` for
-:js:class:`~openerp.web.Model`, OpenERP Web 7.0 also deprecates
-``DataGroup`` and its subtypes in favor of a single method on
+:js:class:`~openerp.web.Model`, OpenERP Web 7.0 removes
+``DataGroup`` and its subtypes as public objects in favor of a single method on
:js:class:`~openerp.web.Query`:
:js:func:`~openerp.web.Query.group_by`.
@@ -116,3 +116,8 @@ Because it is heavily related to ``DataSet`` (as it *yields*
``DataGroup`` (if we want to stay consistent), which is a good time to
make the API more imperative and look more like what most developers
are used to.
+
+But as ``DataGroup`` users in 6.1 were rare (and there really was little reason
+to use it), it has been removed as a public API.
+
+
diff --git a/addons/web/doc/rpc.rst b/addons/web/doc/rpc.rst
index 4787978e187..db6fcb4fa4b 100644
--- a/addons/web/doc/rpc.rst
+++ b/addons/web/doc/rpc.rst
@@ -1,5 +1,5 @@
-Outside the box: network interactions
-=====================================
+RPC Calls
+=========
Building static displays is all nice and good and allows for neat
effects (and sometimes you're given data to display from third parties
diff --git a/addons/web/i18n/ar.po b/addons/web/i18n/ar.po
index 008f1d300d6..40756b45f6b 100644
--- a/addons/web/i18n/ar.po
+++ b/addons/web/i18n/ar.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/bg.po b/addons/web/i18n/bg.po
index e8b2d251e5d..d1ab853401a 100644
--- a/addons/web/i18n/bg.po
+++ b/addons/web/i18n/bg.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/bn.po b/addons/web/i18n/bn.po
index be55c854683..8b6accef4ac 100644
--- a/addons/web/i18n/bn.po
+++ b/addons/web/i18n/bn.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/bs.po b/addons/web/i18n/bs.po
index 9c4c8e1efea..e784c56a4fb 100644
--- a/addons/web/i18n/bs.po
+++ b/addons/web/i18n/bs.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ca.po b/addons/web/i18n/ca.po
index d5377f66780..be31ecde6e8 100644
--- a/addons/web/i18n/ca.po
+++ b/addons/web/i18n/ca.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/cs.po b/addons/web/i18n/cs.po
index 1bc447a369e..2a580dfb6f1 100644
--- a/addons/web/i18n/cs.po
+++ b/addons/web/i18n/cs.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
"X-Poedit-Language: Czech\n"
#. openerp-web
diff --git a/addons/web/i18n/da.po b/addons/web/i18n/da.po
index 8799ce9472e..9ed2c394c67 100644
--- a/addons/web/i18n/da.po
+++ b/addons/web/i18n/da.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/de.po b/addons/web/i18n/de.po
index 3d1ff84113d..efffdaae086 100644
--- a/addons/web/i18n/de.po
+++ b/addons/web/i18n/de.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/en_AU.po b/addons/web/i18n/en_AU.po
index 833184dc94f..523091548a1 100644
--- a/addons/web/i18n/en_AU.po
+++ b/addons/web/i18n/en_AU.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/en_GB.po b/addons/web/i18n/en_GB.po
index d68113dbbac..eed11630b31 100644
--- a/addons/web/i18n/en_GB.po
+++ b/addons/web/i18n/en_GB.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/es.po b/addons/web/i18n/es.po
index e11bb829ba0..eb8d94b563c 100644
--- a/addons/web/i18n/es.po
+++ b/addons/web/i18n/es.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/es_CL.po b/addons/web/i18n/es_CL.po
index ef34d06b874..3888b799e52 100644
--- a/addons/web/i18n/es_CL.po
+++ b/addons/web/i18n/es_CL.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/es_CR.po b/addons/web/i18n/es_CR.po
index cb0bb1202e2..a3c9e0ea3f5 100644
--- a/addons/web/i18n/es_CR.po
+++ b/addons/web/i18n/es_CR.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
"Language: es\n"
#. openerp-web
diff --git a/addons/web/i18n/es_EC.po b/addons/web/i18n/es_EC.po
index d4ff6f80109..89aa15aa3f5 100644
--- a/addons/web/i18n/es_EC.po
+++ b/addons/web/i18n/es_EC.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/et.po b/addons/web/i18n/et.po
index 2422f46fc89..a664a0eba71 100644
--- a/addons/web/i18n/et.po
+++ b/addons/web/i18n/et.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/eu.po b/addons/web/i18n/eu.po
index 99debdd072d..ae886ab0b86 100644
--- a/addons/web/i18n/eu.po
+++ b/addons/web/i18n/eu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/fi.po b/addons/web/i18n/fi.po
index 43dbcdd8e18..e97a9cedfac 100644
--- a/addons/web/i18n/fi.po
+++ b/addons/web/i18n/fi.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/fr.po b/addons/web/i18n/fr.po
index 619b8465dc5..036d1695bc4 100644
--- a/addons/web/i18n/fr.po
+++ b/addons/web/i18n/fr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/fr_CA.po b/addons/web/i18n/fr_CA.po
index 0f2cd756705..070e109a1ac 100644
--- a/addons/web/i18n/fr_CA.po
+++ b/addons/web/i18n/fr_CA.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/gl.po b/addons/web/i18n/gl.po
index 42d4e312372..6d3c4af4df7 100644
--- a/addons/web/i18n/gl.po
+++ b/addons/web/i18n/gl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/gu.po b/addons/web/i18n/gu.po
index 1d2f403e0db..851593765c3 100644
--- a/addons/web/i18n/gu.po
+++ b/addons/web/i18n/gu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/hi.po b/addons/web/i18n/hi.po
index 61b77e546c8..5e95732337f 100644
--- a/addons/web/i18n/hi.po
+++ b/addons/web/i18n/hi.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/hr.po b/addons/web/i18n/hr.po
index 3aadcd86171..47f2a6cb7ef 100644
--- a/addons/web/i18n/hr.po
+++ b/addons/web/i18n/hr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/hu.po b/addons/web/i18n/hu.po
index 691445417da..35722b9be95 100644
--- a/addons/web/i18n/hu.po
+++ b/addons/web/i18n/hu.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/id.po b/addons/web/i18n/id.po
index cf59fe32dba..4f5ff9a5b44 100644
--- a/addons/web/i18n/id.po
+++ b/addons/web/i18n/id.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/it.po b/addons/web/i18n/it.po
index 0ef8452b271..402ddad3365 100644
--- a/addons/web/i18n/it.po
+++ b/addons/web/i18n/it.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ja.po b/addons/web/i18n/ja.po
index 699f55c1311..6fd63587a64 100644
--- a/addons/web/i18n/ja.po
+++ b/addons/web/i18n/ja.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ka.po b/addons/web/i18n/ka.po
index 6798dca15c9..09c4ffd9f8b 100644
--- a/addons/web/i18n/ka.po
+++ b/addons/web/i18n/ka.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/mk.po b/addons/web/i18n/mk.po
index 613176f1c3c..9003b875eac 100644
--- a/addons/web/i18n/mk.po
+++ b/addons/web/i18n/mk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/mn.po b/addons/web/i18n/mn.po
index 58e8f985aec..072448c126d 100644
--- a/addons/web/i18n/mn.po
+++ b/addons/web/i18n/mn.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/nb.po b/addons/web/i18n/nb.po
index 0a82c8e5e39..275a678b617 100644
--- a/addons/web/i18n/nb.po
+++ b/addons/web/i18n/nb.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/nl.po b/addons/web/i18n/nl.po
index a99e02aeb7a..e23fe40a79b 100644
--- a/addons/web/i18n/nl.po
+++ b/addons/web/i18n/nl.po
@@ -9,13 +9,13 @@ msgstr ""
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
"PO-Revision-Date: 2012-07-02 14:46+0000\n"
-"Last-Translator: Erwin \n"
+"Last-Translator: Erwin van der Ploeg (Endian Solutions) \n"
"Language-Team: Dutch \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/nl_BE.po b/addons/web/i18n/nl_BE.po
index cdf0bbdcee2..d7006b509a2 100644
--- a/addons/web/i18n/nl_BE.po
+++ b/addons/web/i18n/nl_BE.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/pl.po b/addons/web/i18n/pl.po
index 8881a0bc239..7a90d6d5432 100644
--- a/addons/web/i18n/pl.po
+++ b/addons/web/i18n/pl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/pt.po b/addons/web/i18n/pt.po
index 43b6d330612..d4fd51fa982 100644
--- a/addons/web/i18n/pt.po
+++ b/addons/web/i18n/pt.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/pt_BR.po b/addons/web/i18n/pt_BR.po
index 041c1d859d0..735c8f9feef 100644
--- a/addons/web/i18n/pt_BR.po
+++ b/addons/web/i18n/pt_BR.po
@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ro.po b/addons/web/i18n/ro.po
index ec52b3807e8..71c7cb15c58 100644
--- a/addons/web/i18n/ro.po
+++ b/addons/web/i18n/ro.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/ru.po b/addons/web/i18n/ru.po
index 6ed05f29c2a..a83821b5e5f 100644
--- a/addons/web/i18n/ru.po
+++ b/addons/web/i18n/ru.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sk.po b/addons/web/i18n/sk.po
index 5656d604668..6a2165efaf9 100644
--- a/addons/web/i18n/sk.po
+++ b/addons/web/i18n/sk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sl.po b/addons/web/i18n/sl.po
index d228cd9651e..a869b97eab4 100644
--- a/addons/web/i18n/sl.po
+++ b/addons/web/i18n/sl.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sq.po b/addons/web/i18n/sq.po
index c77bd50961a..3b5e2ca41ea 100644
--- a/addons/web/i18n/sq.po
+++ b/addons/web/i18n/sq.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:48+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sr@latin.po b/addons/web/i18n/sr@latin.po
index c0e6c7f6207..2c35afc3bde 100644
--- a/addons/web/i18n/sr@latin.po
+++ b/addons/web/i18n/sr@latin.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/sv.po b/addons/web/i18n/sv.po
index 1c5823e8041..978e4fb1fb3 100644
--- a/addons/web/i18n/sv.po
+++ b/addons/web/i18n/sv.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/tr.po b/addons/web/i18n/tr.po
index 2322b869344..7a74eba5dd0 100644
--- a/addons/web/i18n/tr.po
+++ b/addons/web/i18n/tr.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/uk.po b/addons/web/i18n/uk.po
index e45cf1dca3a..daed408aaaf 100644
--- a/addons/web/i18n/uk.po
+++ b/addons/web/i18n/uk.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:27+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/zh_CN.po b/addons/web/i18n/zh_CN.po
index 550ec9dc897..7539b136e03 100644
--- a/addons/web/i18n/zh_CN.po
+++ b/addons/web/i18n/zh_CN.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/i18n/zh_TW.po b/addons/web/i18n/zh_TW.po
index 0bdd2804510..f29b9002d8c 100644
--- a/addons/web/i18n/zh_TW.po
+++ b/addons/web/i18n/zh_TW.po
@@ -14,8 +14,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-10-03 05:28+0000\n"
-"X-Generator: Launchpad (build 16061)\n"
+"X-Launchpad-Export-Date: 2012-10-13 04:49+0000\n"
+"X-Generator: Launchpad (build 16137)\n"
#. openerp-web
#: addons/web/static/src/js/chrome.js:176
diff --git a/addons/web/static/lib/datejs/globalization/ab-RU.js b/addons/web/static/lib/datejs/globalization/ab-RU.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/ar-AR.js b/addons/web/static/lib/datejs/globalization/ar-AR.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/bs-BS.js b/addons/web/static/lib/datejs/globalization/bs-BS.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/iu-CA.js b/addons/web/static/lib/datejs/globalization/iu-CA.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/ko-KP.js b/addons/web/static/lib/datejs/globalization/ko-KP.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/ml-IN.js b/addons/web/static/lib/datejs/globalization/ml-IN.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/oc-FR.js b/addons/web/static/lib/datejs/globalization/oc-FR.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/si-LK.js b/addons/web/static/lib/datejs/globalization/si-LK.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/sr-RS.js b/addons/web/static/lib/datejs/globalization/sr-RS.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/sr@latin.js b/addons/web/static/lib/datejs/globalization/sr@latin.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/lib/datejs/globalization/tlh-TLH.js b/addons/web/static/lib/datejs/globalization/tlh-TLH.js
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css
index c8f1567bee9..8925c3a0964 100644
--- a/addons/web/static/src/css/base.css
+++ b/addons/web/static/src/css/base.css
@@ -25,6 +25,7 @@
display: none !important;
}
}
+
.openerp.openerp_webclient_container {
height: 100%;
position: relative;
@@ -1184,7 +1185,7 @@
color: white;
padding: 2px 4px;
margin: 1px 6px 0 0;
- border: 1px solid lightgrey;
+ border: 1px solid lightGray;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
@@ -1209,7 +1210,7 @@
transform: scale(1.1);
}
.openerp .oe_secondary_submenu .oe_active {
- border-top: 1px solid lightgrey;
+ border-top: 1px solid lightGray;
border-bottom: 1px solid #dedede;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 -1px 3px rgba(40, 40, 40, 0.2);
@@ -2054,36 +2055,36 @@
width: 400px;
padding-bottom: 0;
}
-.openerp .oe_form header .oe_tags div.oe_chatter {
+.openerp .oe_form div.oe_chatter {
min-width: 650px;
max-width: 860px;
margin: 0 auto;
padding: 16px 0 48px;
}
-.openerp .oe_form header .oe_tags div.oe_form_configuration p, .openerp .oe_form header .oe_tags div.oe_form_configuration ul, .openerp .oe_form header .oe_tags div.oe_form_configuration ol {
+.openerp .oe_form div.oe_form_configuration p, .openerp .oe_form div.oe_form_configuration ul, .openerp .oe_form div.oe_form_configuration ol {
color: #aaaaaa;
max-width: 650px;
}
-.openerp .oe_form header .oe_tags div.oe_form_configuration label {
+.openerp .oe_form div.oe_form_configuration label {
min-width: 150px;
}
-.openerp .oe_form header .oe_tags div.oe_form_configuration .oe_form_group_cell_label {
+.openerp .oe_form div.oe_form_configuration .oe_form_group_cell_label {
padding: 1px 0;
}
-.openerp .oe_form header .oe_tags div.oe_form_configuration .oe_form_group_cell div div {
+.openerp .oe_form div.oe_form_configuration .oe_form_group_cell div div {
padding: 1px 0;
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer {
+.openerp .oe_form .oe_subtotal_footer {
width: 1% !important;
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer td.oe_form_group_cell {
+.openerp .oe_form .oe_subtotal_footer td.oe_form_group_cell {
text-align: right;
padding: 0 !important;
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer td.oe_form_group_cell_label {
+.openerp .oe_form .oe_subtotal_footer td.oe_form_group_cell_label {
border-right: none;
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer .oe_subtotal_footer_separator {
+.openerp .oe_form .oe_subtotal_footer .oe_subtotal_footer_separator {
width: 108px;
border-top: 1px solid #cacaca;
margin-top: 4px;
@@ -2091,14 +2092,14 @@
font-weight: bold;
font-size: 18px;
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer label:after {
+.openerp .oe_form .oe_subtotal_footer label:after {
content: ":";
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer label.oe_subtotal_footer_separator {
+.openerp .oe_form .oe_subtotal_footer label.oe_subtotal_footer_separator {
font-weight: bold !important;
padding: 2px 11px 2px 0px !important;
}
-.openerp .oe_form header .oe_tags .oe_subtotal_footer label.oe_form_label_help {
+.openerp .oe_form .oe_subtotal_footer label.oe_form_label_help {
font-weight: normal;
}
.openerp .oe_form .oe_form_button {
@@ -2130,7 +2131,7 @@
}
.openerp .oe_form .oe_form_label_help[for] span, .openerp .oe_form .oe_form_label[for] span {
font-size: 80%;
- color: darkgreen;
+ color: darkGreen;
vertical-align: top;
position: relative;
top: -4px;
diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass
index 823ced4e24f..a1adfe67e75 100644
--- a/addons/web/static/src/css/base.sass
+++ b/addons/web/static/src/css/base.sass
@@ -1616,16 +1616,18 @@ $sheet-max-width: 860px
ul
display: inline-block
float: right
- .oe_button,
+ .oe_button
margin: 3px 2px 1px
&:first-child
margin-left: 6px
// }}}
// FormView.custom tags and classes {{{
- .oe_form header .oe_tags
- margin: 5px 0 0 5px
- width: 400px
- padding-bottom: 0
+ .oe_form
+ header
+ .oe_tags
+ margin: 5px 0 0 5px
+ width: 400px
+ padding-bottom: 0
div.oe_chatter
min-width: 650px
max-width: $sheet-max-width
diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js
index b605f4ad4e1..a298ac67159 100644
--- a/addons/web/static/src/js/chrome.js
+++ b/addons/web/static/src/js/chrome.js
@@ -70,7 +70,9 @@ instance.web.Dialog = instance.web.Widget.extend({
autoOpen: false,
position: [false, 40],
buttons: {},
- beforeClose: function () { self.on_close(); },
+ beforeClose: function () {
+ self.trigger("closing");
+ },
resizeStop: this.on_resized
};
for (var f in this) {
@@ -84,6 +86,7 @@ instance.web.Dialog = instance.web.Widget.extend({
}
_.extend(this.dialog_options, options);
}
+ this.on("closing", this, this._closing);
},
get_options: function(options) {
var self = this,
@@ -126,13 +129,10 @@ instance.web.Dialog = instance.web.Widget.extend({
if (! this.dialog_inited)
this.init_dialog();
var o = this.get_options(options);
- if (! this.params_buttons) {
- this.$buttons.appendTo($("body"));
- }
+ this.$buttons.appendTo($("body"));
instance.web.dialog(this.$el, o).dialog('open');
- if (! this.params_buttons) {
- this.$buttons.appendTo(this.$el.dialog("widget"));
- }
+ this.$el.dialog("widget").find(".ui-dialog-buttonpane").remove();
+ this.$buttons.appendTo(this.$el.dialog("widget"));
if (o.height === 'auto' && o.max_height) {
this.$el.css({ 'max-height': o.max_height, 'overflow-y': 'auto' });
}
@@ -145,6 +145,8 @@ instance.web.Dialog = instance.web.Widget.extend({
if (! this.params_buttons) {
this.$buttons = $('');
this.$el.dialog("widget").append(this.$buttons);
+ } else {
+ this.$buttons = this.$el.dialog("widget").find(".ui-dialog-buttonpane");
}
this.dialog_inited = true;
var res = this.start();
@@ -153,7 +155,7 @@ instance.web.Dialog = instance.web.Widget.extend({
close: function() {
this.$el.dialog('close');
},
- on_close: function() {
+ _closing: function() {
if (this.__tmp_dialog_destroying)
return;
if (this.dialog_options.destroy_on_close) {
@@ -627,6 +629,7 @@ instance.web.Reload = function(parent, params) {
hash = "#menu_id=" + menu_id;
}
var url = l.protocol + "//" + l.host + l.pathname + search + hash;
+ window.onerror = function() {};
window.location = url;
};
instance.web.client_actions.add("reload", "instance.web.Reload");
@@ -878,9 +881,8 @@ instance.web.UserMenu = instance.web.Widget.extend({
};
this.update_promise = this.update_promise.pipe(fct, fct);
},
- on_action: function() {
- },
on_menu_logout: function() {
+ this.trigger('user_logout');
},
on_menu_settings: function() {
var self = this;
@@ -897,8 +899,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
var $help = $(QWeb.render("UserMenu.about", {version_info: res}));
$help.find('a.oe_activate_debug_mode').click(function (e) {
e.preventDefault();
- window.location = $.param.querystring(
- window.location.href, 'debug');
+ window.location = $.param.querystring( window.location.href, 'debug');
});
instance.web.dialog($help, {autoOpen: true,
modal: true, width: 507, height: 290, resizable: false, title: _t("About")});
@@ -1019,15 +1020,13 @@ instance.web.WebClient = instance.web.Client.extend({
var state = $.bbq.getState(true);
var action = {
- 'type': 'ir.actions.client',
- 'tag': 'login',
- 'params': state
+ type: 'ir.actions.client',
+ tag: 'login',
+ _push_me: false,
};
this.action_manager.do_action(action);
this.action_manager.inner_widget.on('login_successful', this, function() {
- this.do_push_state(state);
- this._current_state = null; // ensure the state will be loaded
this.show_application(); // will load the state we just pushed
});
},
@@ -1039,8 +1038,7 @@ instance.web.WebClient = instance.web.Client.extend({
self.menu.on('menu_click', this, this.on_menu_action);
self.user_menu = new instance.web.UserMenu(self);
self.user_menu.replace(this.$el.find('.oe_user_menu_placeholder'));
- self.user_menu.on_menu_logout.add(this.proxy('on_logout'));
- self.user_menu.on_action.add(this.proxy('on_menu_action'));
+ self.user_menu.on('user_logout', self, self.on_logout);
self.user_menu.do_update();
self.bind_hashchange();
self.set_title();
@@ -1103,6 +1101,7 @@ instance.web.WebClient = instance.web.Client.extend({
});
});
} else {
+ state._push_me = false; // no need to push state back...
this.action_manager.do_load_state(state, !!this._current_state);
}
}
@@ -1121,9 +1120,11 @@ instance.web.WebClient = instance.web.Client.extend({
.pipe(function (result) {
var action = result;
if (options.needaction) {
- action.context.search_default_needaction_pending = true;
+ action.context.search_default_message_unread = true;
}
- return $.when(self.action_manager.do_action(action, null, true)).fail(function() {
+ return $.when(self.action_manager.do_action(action, {
+ clear_breadcrumbs: true,
+ })).fail(function() {
self.menu.open_menu(options.previous_menu_id);
});
});
diff --git a/addons/web/static/src/js/corelib.js b/addons/web/static/src/js/corelib.js
index b5fbacc7927..7f4f8c0d6ca 100644
--- a/addons/web/static/src/js/corelib.js
+++ b/addons/web/static/src/js/corelib.js
@@ -291,6 +291,17 @@ var Events = instance.web.Class.extend({
return this;
},
+ callbackList: function() {
+ var lst = [];
+ _.each(this._callbacks || {}, function(el, eventName) {
+ var node = el;
+ while ((node = node.next) && node.next) {
+ lst.push([eventName, node.callback, node.context]);
+ }
+ });
+ return lst;
+ },
+
trigger : function(events) {
var event, node, calls, tail, args, all, rest;
if (!(calls = this._callbacks))
@@ -369,9 +380,9 @@ instance.web.EventDispatcherMixin = _.extend({}, instance.web.ParentedMixin, {
event.source.__edispatcherEvents.off(event.name, event.func, self);
});
this.__edispatcherRegisteredEvents = [];
- if(!this.__edispatcherEvents) {
- debugger;
- }
+ _.each(this.__edispatcherEvents.callbackList(), function(cal) {
+ this.off(cal[0], cal[2], cal[1]);
+ }, this);
this.__edispatcherEvents.off();
instance.web.ParentedMixin.destroy.call(this);
}
@@ -1440,6 +1451,10 @@ instance.web.JsonRPC = instance.web.CallbackEnabled.extend({
},
});
+instance.web.py_eval = function(expr, context) {
+ return py.eval(expr, _.extend({}, context || {}, {"true": true, "false": false, "null": null}));
+};
+
}
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/web/static/src/js/data.js b/addons/web/static/src/js/data.js
index ce85e0ac43f..77583899bf1 100644
--- a/addons/web/static/src/js/data.js
+++ b/addons/web/static/src/js/data.js
@@ -280,7 +280,8 @@ instance.web.Model = instance.web.Class.extend({
kwargs = args;
args = [];
}
- return instance.session.rpc('/web/dataset/call_kw', {
+ var debug = instance.session.debug ? '/'+this.name+':'+method : '';
+ return instance.session.rpc('/web/dataset/call_kw' + debug, {
model: this.name,
method: method,
args: args,
@@ -349,89 +350,6 @@ instance.web.Model = instance.web.Class.extend({
},
});
-instance.web.DataGroup = instance.web.CallbackEnabled.extend({
- /**
- * Management interface between views and grouped collections of OpenERP
- * records.
- *
- * The root DataGroup is instantiated with the relevant information
- * (a session, a model, a domain, a context and a group_by sequence), the
- * domain and context may be empty. It is then interacted with via
- * :js:func:`~instance.web.DataGroup.list`, which is used to read the
- * content of the current grouping level.
- *
- * @constructs instance.web.DataGroup
- * @extends instance.web.CallbackEnabled
- *
- * @param {instance.web.CallbackEnabled} parent widget
- * @param {String} model name of the model managed by this DataGroup
- * @param {Array} domain search domain for this DataGroup
- * @param {Object} context context of the DataGroup's searches
- * @param {Array} group_by sequence of fields by which to group
- * @param {Number} [level=0] nesting level of the group
- */
- init: function(parent, model, domain, context, group_by, level) {
- this._super(parent, null);
- this.model = new instance.web.Model(model, context, domain);
- this.group_by = group_by;
- this.context = context;
- this.domain = domain;
-
- this.level = level || 0;
- },
- list: function (fields, ifGroups, ifRecords) {
- var self = this;
- var query = this.model.query(fields).order_by(this.sort).group_by(this.group_by);
- $.when(query).then(function (querygroups) {
- // leaf node
- if (!querygroups) {
- var ds = new instance.web.DataSetSearch(self, self.model.name, self.model.context(), self.model.domain());
- ds._sort = self.sort;
- ifRecords(ds);
- return;
- }
- // internal node
- var child_datagroups = _(querygroups).map(function (group) {
- var child_context = _.extend(
- {}, self.model.context(), group.model.context());
- var child_dg = new instance.web.DataGroup(
- self, self.model.name, group.model.domain(),
- child_context, group.model._context.group_by,
- self.level + 1);
- child_dg.sort = self.sort;
- // copy querygroup properties
- child_dg.__context = child_context;
- child_dg.__domain = group.model.domain();
- child_dg.folded = group.get('folded');
- child_dg.grouped_on = group.get('grouped_on');
- child_dg.length = group.get('length');
- child_dg.value = group.get('value');
- child_dg.openable = group.get('has_children');
- child_dg.aggregates = group.get('aggregates');
- return child_dg;
- });
- ifGroups(child_datagroups);
- });
- }
-});
-
-instance.web.StaticDataGroup = instance.web.DataGroup.extend({
- /**
- * A specialization of data groups, relying on a single static
- * dataset as its records provider.
- *
- * @constructs instance.web.StaticDataGroup
- * @extends instance.web.DataGroup
- * @param {openep.web.DataSetStatic} dataset a static dataset backing the groups
- */
- init: function (dataset) {
- this.dataset = dataset;
- },
- list: function (fields, ifGroups, ifRecords) {
- ifRecords(this.dataset);
- }
-});
-
instance.web.DataSet = instance.web.CallbackEnabled.extend({
/**
* Collection of OpenERP records, used to share records and the current selection between views.
@@ -567,7 +485,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
*/
write: function (id, data, options) {
options = options || {};
- return this._model.call('write', [[id], data], {context: this._model.context(options.context)});
+ return this._model.call('write', [[id], data], {context: this._model.context(options.context)}).then(this.trigger('dataset_changed', id, data, options));
},
/**
* Deletes an existing record from the database
@@ -575,8 +493,7 @@ instance.web.DataSet = instance.web.CallbackEnabled.extend({
* @param {Number|String} ids identifier of the record to delete
*/
unlink: function(ids) {
- this.trigger('unlink', ids);
- return this._model.call('unlink', [ids], {context: this._model.context()});
+ return this._model.call('unlink', [ids], {context: this._model.context()}).then(this.trigger('dataset_changed', ids));
},
/**
* Calls an arbitrary RPC method
@@ -774,10 +691,11 @@ instance.web.DataSetSearch = instance.web.DataSet.extend({
if (self._length) {
self._length -= 1;
}
- if (this.index !== null) {
+ if (self.index !== null) {
self.index = self.index <= self.ids.length - 1 ?
self.index : (self.ids.length > 0 ? self.ids.length -1 : 0);
}
+ self.trigger("dataset_changed", ids, callback, error_callback);
});
},
size: function () {
@@ -834,7 +752,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
}
$.extend(cached.values, record.values);
if (dirty)
- this.on_change();
+ this.trigger("dataset_changed", id, data, options);
return $.Deferred().resolve(true).promise();
},
unlink: function(ids, callback, error_callback) {
@@ -848,7 +766,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
this.to_write = _.reject(this.to_write, function(x) { return _.include(ids, x.id);});
this.cache = _.reject(this.cache, function(x) { return _.include(ids, x.id);});
this.set_ids(_.without.apply(_, [this.ids].concat(ids)));
- this.on_change();
+ this.trigger("dataset_changed", ids, callback, error_callback);
return $.async_when({result: true}).then(callback);
},
reset_ids: function(ids) {
@@ -859,8 +777,6 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
this.cache = [];
this.delete_all = false;
},
- on_change: function() {
- },
read_ids: function (ids, fields, options) {
var self = this;
var to_get = [];
@@ -947,7 +863,7 @@ instance.web.BufferedDataSet = instance.web.DataSetStatic.extend({
},
alter_ids: function(n_ids) {
this._super(n_ids);
- this.on_change();
+ this.trigger("dataset_changed", n_ids);
},
});
instance.web.BufferedDataSet.virtual_id_regex = /^one2many_v_id_.*$/;
diff --git a/addons/web/static/src/js/formats.js b/addons/web/static/src/js/formats.js
index 3e5e6fecd5e..03b2c5b775d 100644
--- a/addons/web/static/src/js/formats.js
+++ b/addons/web/static/src/js/formats.js
@@ -135,7 +135,7 @@ instance.web.format_value = function (value, descriptor, value_if_empty) {
Math.round((value % 1) * 60));
case 'many2one':
// name_get value format
- return value[1];
+ return value[1] ? value[1].split("\n")[0] : value[1];
case 'one2many':
case 'many2many':
if (typeof value === 'string') {
diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js
index d9254d2d724..606d966da3f 100644
--- a/addons/web/static/src/js/view_form.js
+++ b/addons/web/static/src/js/view_form.js
@@ -110,6 +110,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
"not_interactible_on_create": false,
"initial_mode": "view",
"disable_autofocus": false,
+ "footer_to_buttons": false,
});
this.is_initialized = $.Deferred();
this.mutating_mutex = new $.Mutex();
@@ -118,7 +119,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.__clicked_inside = false;
this.__blur_timeout = null;
this.rendering_engine = new instance.web.form.FormRenderingEngine(this);
- this.qweb = null; // A QWeb instance will be created if the view is a QWeb template
self.set({actual_mode: self.options.initial_mode});
this.has_been_loaded.then(function() {
self.on("change:actual_mode", self, self.check_actual_mode);
@@ -157,11 +157,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.rendering_engine.set_fields_registry(this.fields_registry);
this.rendering_engine.set_tags_registry(this.tags_registry);
this.rendering_engine.set_widgets_registry(this.widgets_registry);
- if (!this.extract_qweb_template(data)) {
- this.rendering_engine.set_fields_view(data);
- var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container');
- this.rendering_engine.render_to($dest);
- }
+ this.rendering_engine.set_fields_view(data);
+ var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container');
+ this.rendering_engine.render_to($dest);
this.$el.on('mousedown.formBlur', function () {
self.__clicked_inside = true;
@@ -169,6 +167,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.$buttons = $(QWeb.render("FormView.buttons", {'widget':self}));
if (this.options.$buttons) {
+ this.options.$buttons.children().remove();
this.$buttons.appendTo(this.options.$buttons);
} else {
this.$el.find('.oe_form_buttons').replaceWith(this.$buttons);
@@ -177,6 +176,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this.$buttons.on('click', '.oe_form_button_edit', this.on_button_edit);
this.$buttons.on('click', '.oe_form_button_save', this.on_button_save);
this.$buttons.on('click', '.oe_form_button_cancel', this.on_button_cancel);
+ if (this.options.footer_to_buttons) {
+ this.$el.find('footer').appendTo(this.$buttons);
+ }
this.$sidebar = this.options.$sidebar || this.$el.find('.oe_form_sidebar');
if (!this.sidebar && this.options.$sidebar) {
@@ -214,57 +216,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return $.when();
},
- extract_qweb_template: function(fvg) {
- for (var i=0, ii=fvg.arch.children.length; i < ii; i++) {
- var child = fvg.arch.children[i];
- if (child.tag === "templates") {
- this.qweb = new QWeb2.Engine();
- this.qweb.add_template(instance.web.json_node_to_xml(child));
- if (!this.qweb.has_template('form')) {
- throw new Error("No QWeb template found for form view");
- }
- return true;
- }
- }
- this.qweb = null;
- return false;
- },
- get_fvg_from_qweb: function(record) {
- var view = this.qweb.render('form', this.get_qweb_context(record));
- var fvg = _.clone(this.fields_view);
- fvg.arch = instance.web.xml_to_json(instance.web.str_to_xml(view).firstChild);
- return fvg;
- },
- get_qweb_context: function(record) {
- var self = this,
- new_record = {};
- _.each(record, function(value_, name) {
- var r = _.clone(self.fields_view.fields[name] || {});
- if ((r.type === 'date' || r.type === 'datetime') && value_) {
- r.raw_value = instance.web.auto_str_to_date(value_);
- } else {
- r.raw_value = value_;
- }
- r.value = instance.web.format_value(value_, r);
- new_record[name] = r;
- });
- return {
- record : new_record,
- new_record : !record.id
- };
- },
- kill_current_form: function() {
- _.each(this.getChildren(), function(el) {
- el.destroy();
- });
- this.fields = {};
- this.fields_order = [];
- this.default_focus_field = null;
- this.default_focus_button = null;
- this.translatable_fields = [];
- this.$el.find('.oe_form_container').empty();
- },
-
widgetFocused: function() {
// Clear click flag if used to focus a widget
this.__clicked_inside = false;
@@ -368,13 +319,6 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
this._actualize_mode();
this.set({ 'title' : record.id ? record.display_name : "New" });
- if (this.qweb) {
- this.kill_current_form();
- this.rendering_engine.set_fields_view(this.get_fvg_from_qweb(record));
- var $dest = this.$el.hasClass("oe_form_container") ? this.$el : this.$el.find('.oe_form_container');
- this.rendering_engine.render_to($dest);
- }
-
_(this.fields).each(function (field, f) {
field._dirty_flag = false;
field._inhibit_on_change_flag = true;
@@ -395,6 +339,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
});
}
self.on_form_changed();
+ self.rendering_engine.init_fields();
self.is_initialized.resolve();
self.do_update_pager(record.id == null);
if (self.sidebar) {
@@ -431,7 +376,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
do_notify_change: function() {
this.$el.add(this.$buttons).addClass('oe_form_dirty');
},
- on_pager_action: function(action) {
+ execute_pager_action: function(action) {
if (this.can_be_discarded()) {
switch (action) {
case 'first':
@@ -448,6 +393,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
break;
}
this.reload();
+ this.trigger('pager_action_executed');
}
},
init_pager: function() {
@@ -464,7 +410,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
}
this.$pager.on('click','a[data-pager-action]',function() {
var action = $(this).data('pager-action');
- self.on_pager_action(action);
+ self.execute_pager_action(action);
});
this.do_update_pager();
},
@@ -737,7 +683,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
}
for (var i = 0; i < fields_order.length; i += 1) {
var field = this.fields[fields_order[i]];
- if (!field.get('effective_invisible') && !field.get('effective_readonly')) {
+ if (!field.get('effective_invisible') && !field.get('effective_readonly') && field.$label) {
if (field.focus() !== false) {
break;
}
@@ -747,7 +693,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
on_button_save: function() {
var self = this;
- return this.do_save().then(function(result) {
+ return this.save().then(function(result) {
+ self.trigger("save", result);
self.to_view_mode();
});
},
@@ -784,7 +731,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var def = $.Deferred();
$.when(this.has_been_loaded).then(function() {
self.dataset.call('copy', [self.datarecord.id, {}, self.dataset.context]).then(function(new_id) {
- return self.record_created({ result : new_id });
+ return self.record_created(new_id);
}).then(function() {
return self.to_edit_mode();
}).then(function() {
@@ -799,7 +746,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
$.when(this.has_been_loaded).then(function() {
if (self.datarecord.id && confirm(_t("Do you really want to delete this record?"))) {
self.dataset.unlink([self.datarecord.id]).then(function() {
- self.on_pager_action('next');
+ self.execute_pager_action('next');
def.resolve();
});
} else {
@@ -824,11 +771,11 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
* record or saving an existing one depending on whether the record
* already has an id property.
*
- * @param {Boolean} [prepend_on_create=false] if ``do_save`` creates a new
+ * @param {Boolean} [prepend_on_create=false] if ``save`` creates a new
* record, should that record be inserted at the start of the dataset (by
* default, records are added at the end)
*/
- do_save: function(prepend_on_create) {
+ save: function(prepend_on_create) {
var self = this;
return this.mutating_mutex.exec(function() { return self.is_initialized.pipe(function() {
try {
@@ -843,7 +790,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
if (!first_invalid_field) {
first_invalid_field = f;
}
- } else if (f.name !== 'id' && (!self.datarecord.id || (!f.get("readonly") && f._dirty_flag))) {
+ } else if (f.name !== 'id' && !f.get("readonly") && (!self.datarecord.id || f._dirty_flag)) {
// Special case 'id' field, do not save this field
// on 'create' : save all non readonly fields
// on 'edit' : save non readonly modified fields
@@ -956,7 +903,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
var self = this;
return this.reload_mutex.exec(function() {
if (self.dataset.index == null) {
- self.do_prev_view();
+ self.trigger("previous_view");
return $.Deferred().reject().promise();
}
if (self.dataset.index == null || self.dataset.index < 0) {
@@ -1000,7 +947,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
},
recursive_save: function() {
var self = this;
- return $.when(this.do_save()).pipe(function(res) {
+ return $.when(this.save()).pipe(function(res) {
if (self.dataset.parent_view)
return self.dataset.parent_view.recursive_save();
});
@@ -1031,10 +978,20 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
return true;
},
sidebar_context: function () {
- return this.do_save().pipe(_.bind(function() {return this.get_fields_values();}, this));
+ return this.save().pipe(_.bind(function() {return this.get_fields_values();}, this));
},
open_defaults_dialog: function () {
var self = this;
+ var display = function (field, value) {
+ if (field instanceof instance.web.form.FieldSelection) {
+ return _(field.values).find(function (option) {
+ return option[0] === value;
+ })[1];
+ } else if (field instanceof instance.web.form.FieldMany2One) {
+ return field.get_displayed();
+ }
+ return value;
+ }
var fields = _.chain(this.fields)
.map(function (field, name) {
var value = field.get_value();
@@ -1048,29 +1005,28 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|| field.field.type === 'binary') {
return false;
}
- var displayed = value;
- if (field instanceof instance.web.form.FieldSelection) {
- displayed = _(field.values).find(function (option) {
- return option[0] === value;
- })[1];
- } else if (field instanceof instance.web.form.FieldMany2One) {
- displayed = field.get_displayed();
- }
return {
name: name,
string: field.string,
value: value,
- displayed: displayed,
- // convert undefined to false
- change_default: !!field.field.change_default
+ displayed: display(field, value),
}
})
.compact()
.sortBy(function (field) { return field.string; })
.value();
- var conditions = _.chain(fields)
- .filter(function (field) { return field.change_default; })
+ var conditions = _.chain(self.fields)
+ .filter(function (field) { return field.field.change_default; })
+ .map(function (field, name) {
+ var value = field.get_value();
+ return {
+ name: name,
+ string: field.string,
+ value: value,
+ displayed: display(field, value),
+ }
+ })
.value();
var d = new instance.web.Dialog(this, {
@@ -1096,7 +1052,7 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
field_to_set,
self.fields[field_to_set].get_value(),
all_users,
- false,
+ true,
condition || false
]).then(function () { d.close(); });
}}
@@ -1226,7 +1182,9 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
this.$form.appendTo(this.$target);
- var ws = _.map(this.fields_to_init, function($elem) {
+ this.to_replace = [];
+
+ _.each(this.fields_to_init, function($elem) {
var name = $elem.attr("name");
if (!self.fvg.fields[name]) {
throw new Error("Field '" + name + "' specified in view could not be found.");
@@ -1242,24 +1200,28 @@ instance.web.form.FormRenderingEngine = instance.web.form.FormRenderingEngineInt
}
self.alter_field(w);
self.view.register_field(w, $elem.attr("name"));
- return [w, $elem];
- });
- _.each(ws, function(w) {
- w[0].replace(w[1]);
+ self.to_replace.push([w, $elem]);
});
_.each(this.tags_to_init, function($elem) {
var tag_name = $elem[0].tagName.toLowerCase();
var obj = self.tags_registry.get_object(tag_name);
var w = new (obj)(self.view, instance.web.xml_to_json($elem[0]));
- w.replace($elem);
+ self.to_replace.push([w, $elem]);
});
_.each(this.widgets_to_init, function($elem) {
var widget_type = $elem.attr("type");
var obj = self.widgets_registry.get_object(widget_type);
var w = new (obj)(self.view, instance.web.xml_to_json($elem[0]));
- w.replace($elem);
+ self.to_replace.push([w, $elem]);
});
- // TODO: return a deferred
+ },
+ init_fields: function() {
+ var defs = [];
+ _.each(this.to_replace, function(el) {
+ defs.push(el[0].replace(el[1]));
+ });
+ this.to_replace = [];
+ return $.when.apply($, defs);
},
render_element: function(template /* dictionaries */) {
var dicts = [].slice.call(arguments).slice(1);
@@ -1660,6 +1622,8 @@ instance.web.form.FormDialog = instance.web.Dialog.extend({
});
instance.web.form.compute_domain = function(expr, fields) {
+ if (! (expr instanceof Array))
+ return !! expr;
var stack = [];
for (var i = expr.length - 1; i >= 0; i--) {
var ex = expr[i];
@@ -2006,12 +1970,9 @@ instance.web.form.FieldInterface = {
/**
* Called by the form view to indicate the value of the field.
*
- * set_value() may return an object that can be passed to $.when() that represents the moment when
- * the field has finished all operations necessary before the user can effectively use the widget.
- *
* Multiple calls to set_value() can occur at any time and must be handled correctly by the implementation,
- * regardless of any asynchronous operation currently running and the status of any promise that a
- * previous call to set_value() could have returned.
+ * regardless of any asynchronous operation currently running. Calls to set_value() can and will also occur
+ * before the widget is inserted into the DOM.
*
* set_value() must be able, at any moment, to handle the syntax returned by the "read" method of the
* osv class in the OpenERP server as well as the syntax used by the set_value() (see below). It must
@@ -2087,11 +2048,7 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
this.field = this.field_manager.get_field_desc(this.name);
this.widget = this.node.attrs.widget;
this.string = this.node.attrs.string || this.field.string || this.name;
- try {
- this.options = JSON.parse(this.node.attrs.options || '{}');
- } catch (e) {
- throw new Error(_.str.sprintf(_t("Widget options for field '%s' are not valid JSON."), this.name));
- }
+ this.options = instance.web.py_eval(this.node.attrs.options || '{}');
this.set({'value': false});
this.on("change:value", this, function() {
@@ -2125,6 +2082,14 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
this.field_manager.on("change:display_invalid_fields", this, this._check_css_flags);
this._check_css_flags();
},
+ start: function() {
+ var tmp = this._super();
+ this.on("change:value", this, function() {
+ if (! this.no_rerender)
+ this.render_value();
+ });
+ this.render_value();
+ },
/**
* Private. Do not use.
*/
@@ -2137,6 +2102,20 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
get_value: function() {
return this.get('value');
},
+ /**
+ Utility method that all implementations should use to change the
+ value without triggering a re-rendering.
+ */
+ internal_set_value: function(value_) {
+ var tmp = this.no_render;
+ this.no_rerender = true;
+ this.set({'value': value_});
+ this.no_rerender = tmp;
+ },
+ /**
+ This method is called each time the value is modified.
+ */
+ render_value: function() {},
is_valid: function() {
return this.is_syntax_valid() && !(this.get('required') && this.is_false());
},
@@ -2181,11 +2160,11 @@ instance.web.form.AbstractField = instance.web.form.FormWidget.extend(instance.w
*/
instance.web.form.ReinitializeWidgetMixin = {
/**
- * Default implementation of start(), use it or call explicitly initialize_field().
+ * Default implementation of, you should not override it, use initialize_field() instead.
*/
start: function() {
- this._super();
this.initialize_field();
+ this._super();
},
initialize_field: function() {
this.on("change:effective_readonly", this, this.reinitialize);
@@ -2212,18 +2191,10 @@ instance.web.form.ReinitializeWidgetMixin = {
* switch.
*/
instance.web.form.ReinitializeFieldMixin = _.extend({}, instance.web.form.ReinitializeWidgetMixin, {
- initialize_field: function() {
- instance.web.form.ReinitializeWidgetMixin.initialize_field.call(this);
- this.render_value();
- },
reinitialize: function() {
instance.web.form.ReinitializeWidgetMixin.reinitialize.call(this);
this.render_value();
},
- /**
- * Called to render the value. Should also be explicitly called at the end of a set_value().
- */
- render_value: function() {},
});
instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
@@ -2237,14 +2208,10 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we
var self = this;
var $input = this.$el.find('input');
$input.change(function() {
- self.set({'value': self.parse_value($input.val())});
+ self.internal_set_value(self.parse_value($input.val()));
});
this.setupFocus($input);
},
- set_value: function(value_) {
- this._super(value_);
- this.render_value();
- },
render_value: function() {
var show_value = this.format_value(this.get('value'), '');
if (!this.get("effective_readonly")) {
@@ -2257,7 +2224,7 @@ instance.web.form.FieldChar = instance.web.form.AbstractField.extend(instance.we
}
},
is_syntax_valid: function() {
- if (!this.get("effective_readonly")) {
+ if (!this.get("effective_readonly") && this.$("input").size() > 0) {
try {
var value_ = this.parse_value(this.$el.find('input').val(), '');
return true;
@@ -2348,7 +2315,7 @@ instance.web.form.FieldFloat = instance.web.form.FieldChar.extend({
widget_class: 'oe_form_field_float',
init: function (field_manager, node) {
this._super(field_manager, node);
- this.set({'value': 0});
+ this.internal_set_value(0);
if (this.node.attrs.digits) {
this.digits = this.node.attrs.digits;
} else {
@@ -2379,7 +2346,10 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
var self = this;
this.$input = this.$el.find('input.oe_datepicker_master');
this.$input_picker = this.$el.find('input.oe_datepicker_container');
- this.$input.change(this.on_change);
+ this.$input.change(function(){
+ self.change_datetime();
+ });
+
this.picker({
onClose: this.on_picker_select,
onSelect: this.on_picker_select,
@@ -2447,9 +2417,10 @@ instance.web.DateTimeWidget = instance.web.Widget.extend({
format_client: function(v) {
return instance.web.format_value(v, {"widget": this.type_of_date});
},
- on_change: function() {
+ change_datetime: function() {
if (this.is_valid_()) {
this.set_value_from_ui_();
+ this.trigger("datetime_changed");
}
}
});
@@ -2473,17 +2444,13 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc
initialize_content: function() {
if (!this.get("effective_readonly")) {
this.datewidget = this.build_widget();
- this.datewidget.on_change.add_last(_.bind(function() {
- this.set({'value': this.datewidget.get_value()});
+ this.datewidget.on('datetime_changed', this, _.bind(function() {
+ this.internal_set_value(this.datewidget.get_value());
}, this));
this.datewidget.appendTo(this.$el);
this.setupFocus(this.datewidget.$input);
}
},
- set_value: function(value_) {
- this._super(value_);
- this.render_value();
- },
render_value: function() {
if (!this.get("effective_readonly")) {
this.datewidget.set_value(this.get('value'));
@@ -2492,7 +2459,7 @@ instance.web.form.FieldDatetime = instance.web.form.AbstractField.extend(instanc
}
},
is_syntax_valid: function() {
- if (!this.get("effective_readonly")) {
+ if (!this.get("effective_readonly") && this.datewidget) {
return this.datewidget.is_valid_();
}
return true;
@@ -2525,7 +2492,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we
this.default_height = this.$textarea.css('height');
if (!this.get("effective_readonly")) {
this.$textarea.change(_.bind(function() {
- self.set({'value': instance.web.parse_value(self.$textarea.val(), self)});
+ self.internal_set_value(instance.web.parse_value(self.$textarea.val(), self));
}, this));
} else {
this.$textarea.attr('disabled', 'disabled');
@@ -2537,12 +2504,8 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we
});
this.setupFocus(this.$textarea);
},
- set_value: function(value_) {
- this._super(value_);
- this.render_value();
- $(window).resize();
- },
render_value: function() {
+ $(window).resize();
var show_value = instance.web.format_value(this.get('value'), this, '');
if (show_value === '') {
this.$textarea.css('height', parseInt(this.default_height)+"px");
@@ -2551,7 +2514,7 @@ instance.web.form.FieldText = instance.web.form.AbstractField.extend(instance.we
this.$textarea.autosize();
},
is_syntax_valid: function() {
- if (!this.get("effective_readonly")) {
+ if (!this.get("effective_readonly") && this.$textarea) {
try {
var value_ = instance.web.parse_value(this.$textarea.val(), this, '');
return true;
@@ -2602,15 +2565,11 @@ instance.web.form.FieldTextHtml = instance.web.form.AbstractField.extend(instanc
this.$cleditor.change(function() {
if (! self._updating_editor) {
self.$cleditor.updateTextArea();
- self.set({'value': self.$textarea.val()});
+ self.internal_set_value(self.$textarea.val());
}
});
}
},
- set_value: function(value_) {
- this._super.apply(this, arguments);
- this.render_value();
- },
render_value: function() {
if (! this.get("effective_readonly")) {
this.$textarea.val(this.get('value') || '');
@@ -2627,21 +2586,20 @@ instance.web.form.FieldBoolean = instance.web.form.AbstractField.extend({
template: 'FieldBoolean',
start: function() {
var self = this;
- this._super.apply(this, arguments);
this.$checkbox = $("input", this.$el);
this.setupFocus(this.$checkbox);
this.$el.click(_.bind(function() {
- this.set({'value': this.$checkbox.is(':checked')});
+ this.internal_set_value(this.$checkbox.is(':checked'));
}, this));
var check_readonly = function() {
self.$checkbox.prop('disabled', self.get("effective_readonly"));
};
this.on("change:effective_readonly", this, check_readonly);
check_readonly.call(this);
- },
- set_value: function(value_) {
this._super.apply(this, arguments);
- this.$checkbox[0].checked = value_;
+ },
+ render_value: function() {
+ this.$checkbox[0].checked = this.get('value');
},
focus: function() {
this.$checkbox.focus();
@@ -2657,9 +2615,8 @@ instance.web.form.FieldProgressBar = instance.web.form.AbstractField.extend({
disabled: this.get("effective_readonly")
});
},
- set_value: function(value_) {
- this._super.apply(this, arguments);
- var show_value = Number(value_);
+ render_value: function() {
+ var show_value = Number(this.get('value'));
if (isNaN(show_value)) {
show_value = 0;
}
@@ -2697,7 +2654,7 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan
var ischanging = false;
var $select = this.$el.find('select')
.change(_.bind(function() {
- this.set({'value': this.values[this.$el.find('select')[0].selectedIndex][0]});
+ this.internal_set_value(this.values[this.$el.find('select')[0].selectedIndex][0]);
}, this))
.change(function () { ischanging = true; })
.click(function () { ischanging = false; })
@@ -2712,7 +2669,6 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan
value_ = value_ === null ? false : value_;
value_ = value_ instanceof Array ? value_[0] : value_;
this._super(value_);
- this.render_value();
},
render_value: function() {
if (!this.get("effective_readonly")) {
@@ -2728,13 +2684,6 @@ instance.web.form.FieldSelection = instance.web.form.AbstractField.extend(instan
this.$el.text(option ? option[1] : this.values[0][1]);
}
},
- is_syntax_valid: function() {
- if (this.get("effective_readonly")) {
- return true;
- }
- var value_ = this.values[this.$el.find('select')[0].selectedIndex];
- return !! value_;
- },
focus: function() {
this.$el.find('select:first').focus();
}
@@ -2877,7 +2826,7 @@ instance.web.form.CompletionFieldMixin = {
self.build_domain(),
new instance.web.CompoundContext(self.build_context(), context || {})
);
- pop.on_select_elements.add(function(element_ids) {
+ pop.on("elements_selected", self, function(element_ids) {
self.add_id(element_ids[0]);
self.focus();
});
@@ -2932,26 +2881,27 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
this.display_value = {};
this.last_search = [];
this.floating = false;
- this.inhibit_on_change = false;
this.current_display = null;
+ this.is_started = false;
},
- start: function() {
- this._super();
- instance.web.form.ReinitializeFieldMixin.start.call(this);
- this.on("change:value", this, function() {
- this.floating = false;
+ reinit_value: function(val) {
+ this.internal_set_value(val);
+ this.floating = false;
+ if (this.is_started)
this.render_value();
- });
+ },
+ initialize_field: function() {
+ this.is_started = true;
instance.web.bus.on('click', this, function() {
if (!this.get("effective_readonly") && this.$input && this.$input.autocomplete('widget').is(':visible')) {
this.$input.autocomplete("close");
}
});
+ instance.web.form.ReinitializeFieldMixin.initialize_field.call(this);
},
initialize_content: function() {
if (!this.get("effective_readonly"))
this.render_editable();
- this.render_value();
},
init_error_displayer: function() {
// nothing
@@ -3002,7 +2952,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
if (self.current_display !== self.$input.val()) {
self.current_display = self.$input.val();
if (self.$input.val() === "") {
- self.set({value: false});
+ self.internal_set_value(false);
self.floating = false;
} else {
self.floating = true;
@@ -3034,15 +2984,14 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
if (self.last_search[0][0] != self.get("value")) {
self.display_value = {};
self.display_value["" + self.last_search[0][0]] = self.last_search[0][1];
- self.set({value: self.last_search[0][0]});
+ self.reinit_value(self.last_search[0][0]);
} else {
used = true;
self.render_value();
}
} else {
used = true;
- self.set({value: false});
- self.render_value();
+ self.reinit_value(false);
}
self.floating = false;
}
@@ -3097,7 +3046,7 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
if (item.id) {
self.display_value = {};
self.display_value["" + item.id] = item.name;
- self.set({value: item.id});
+ self.reinit_value(item.id);
} else if (item.action) {
item.action();
// Cancel widget blurring, to avoid form blur event
@@ -3188,16 +3137,14 @@ instance.web.form.FieldMany2One = instance.web.form.AbstractField.extend(instanc
value_ = value_[0];
}
value_ = value_ || false;
- this.inhibit_on_change = true;
- this._super(value_);
- this.inhibit_on_change = false;
+ this.reinit_value(value_);
},
get_displayed: function() {
return this.display_value["" + this.get("value")];
},
add_id: function(id) {
this.display_value = {};
- this.set({value: id});
+ this.reinit_value(id);
},
is_false: function() {
return ! this.get("value");
@@ -3270,9 +3217,18 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
lazy_build_o2m_kanban_view();
this.is_loaded = $.Deferred();
this.initial_is_loaded = this.is_loaded;
- this.is_setted = $.Deferred();
this.form_last_update = $.Deferred();
this.init_form_last_update = this.form_last_update;
+ this.is_started = false;
+ this.dataset = new instance.web.form.One2ManyDataSet(this, this.field.relation);
+ this.dataset.o2m = this;
+ this.dataset.parent_view = this.view;
+ this.dataset.child_name = this.name;
+ var self = this;
+ this.dataset.on('dataset_changed', this, function() {
+ self.trigger_on_change();
+ });
+ this.set_value([]);
},
start: function() {
this._super.apply(this, arguments);
@@ -3280,17 +3236,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
var self = this;
- this.dataset = new instance.web.form.One2ManyDataSet(this, this.field.relation);
- this.dataset.o2m = this;
- this.dataset.parent_view = this.view;
- this.dataset.child_name = this.name;
- this.dataset.on_change.add_last(function() {
- self.trigger_on_change();
- });
-
- this.is_setted.then(function() {
- self.load_views();
- });
+ self.load_views();
this.is_loaded.then(function() {
self.on("change:effective_readonly", self, function() {
self.is_loaded = self.is_loaded.pipe(function() {
@@ -3301,6 +3247,8 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
});
});
});
+ this.is_started = true;
+ this.reload_current_view();
},
trigger_on_change: function() {
var tmp = this.doing_on_change;
@@ -3372,7 +3320,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
var def = $.Deferred().then(function() {
self.initial_is_loaded.resolve();
});
- this.viewmanager.on_controller_inited.add_last(function(view_type, controller) {
+ this.viewmanager.on("controller_inited", self, function(view_type, controller) {
controller.o2m = self;
if (view_type == "list") {
if (self.get("effective_readonly")) {
@@ -3387,9 +3335,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
controller.on("load_record", self, function(){
once.resolve();
});
- controller.on_pager_action.add_first(function() {
- self.save_any_view();
- });
+ controller.on('pager_action_executed',self,self.save_any_view);
} else if (view_type == "graph") {
self.reload_current_view()
}
@@ -3404,10 +3350,8 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
}
});
});
- this.is_setted.then(function() {
- $.async_when().then(function () {
- self.viewmanager.appendTo(self.$el);
- });
+ $.async_when().then(function () {
+ self.viewmanager.appendTo(self.$el);
});
return def;
},
@@ -3487,9 +3431,12 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
if (this.dataset.index === null && this.dataset.ids.length > 0) {
this.dataset.index = 0;
}
- self.is_setted.resolve();
this.trigger_on_change();
- return self.reload_current_view();
+ if (this.is_started) {
+ return self.reload_current_view();
+ } else {
+ return $.when();
+ }
},
get_value: function() {
var self = this;
@@ -3524,7 +3471,7 @@ instance.web.form.FieldOne2Many = instance.web.form.AbstractField.extend({
if (!view.is_initialized.isResolved()) {
return false;
}
- var res = $.when(view.do_save());
+ var res = $.when(view.save());
if (!res.isResolved() && !res.isRejected()) {
console.warn("Asynchronous get_value() is not supported in form view.");
}
@@ -3581,7 +3528,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
create_function: function(data) {
return self.o2m.dataset.create(data).then(function(r) {
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
- self.o2m.dataset.on_change();
+ self.o2m.dataset.trigger("dataset_changed", r);
});
},
write_function: function(id, data, options) {
@@ -3598,7 +3545,7 @@ instance.web.form.One2ManyViewManager = instance.web.ViewManager.extend({
form_view_options: {'not_interactible_on_create':true},
readonly: self.o2m.get("effective_readonly")
});
- pop.on_select_elements.add_last(function() {
+ pop.on("elements_selected", self, function() {
self.o2m.reload_current_view();
});
},
@@ -3676,7 +3623,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
create_function: function(data, callback, error_callback) {
return self.o2m.dataset.create(data).then(function(r) {
self.o2m.dataset.set_ids(self.o2m.dataset.ids.concat([r]));
- self.o2m.dataset.on_change();
+ self.o2m.dataset.trigger("dataset_changed", r);
}).then(callback, error_callback);
},
read_function: function() {
@@ -3689,7 +3636,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
self.o2m.build_domain(),
self.o2m.build_context()
);
- pop.on_select_elements.add_last(function() {
+ pop.on("elements_selected", self, function() {
self.o2m.reload_current_view();
});
}
@@ -3725,7 +3672,7 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
var self = this;
this.ensure_saved().pipe(function () {
if (parent_form)
- return parent_form.do_save();
+ return parent_form.save();
else
return $.when();
}).then(function () {
@@ -3864,7 +3811,7 @@ instance.web.form.One2ManyFormView = instance.web.FormView.extend({
this._super(data);
var self = this;
this.$buttons.find('button.oe_form_button_create').click(function() {
- self.do_save().then(self.on_button_new);
+ self.save().then(self.on_button_new);
});
},
do_notify_change: function() {
@@ -3892,11 +3839,6 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in
this._display_orderer = new instance.web.DropMisordered();
this._drop_shown = false;
},
- start: function() {
- this._super();
- instance.web.form.ReinitializeFieldMixin.start.call(this);
- this.on("change:value", this, this.render_value);
- },
initialize_content: function() {
if (this.get("effective_readonly"))
return;
@@ -4018,36 +3960,33 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
disable_utility_classes: true,
init: function(field_manager, node) {
this._super(field_manager, node);
- this.set({"value": []});
this.is_loaded = $.Deferred();
this.initial_is_loaded = this.is_loaded;
- this.is_setted = $.Deferred();
+ this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
+ this.dataset.m2m = this;
+ var self = this;
+ this.dataset.on('unlink', self, function(ids) {
+ self.dataset_changed();
+ });
+ this.set_value([]);
},
start: function() {
- this._super.apply(this, arguments);
this.$el.addClass('oe_form_field oe_form_field_many2many');
var self = this;
- this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
- this.dataset.m2m = this;
- this.dataset.on('unlink', self, function(ids) {
- self.dataset_changed();
- });
-
- this.is_setted.then(function() {
- self.load_view();
- });
+ self.load_view();
this.is_loaded.then(function() {
self.on("change:effective_readonly", self, function() {
self.is_loaded = self.is_loaded.pipe(function() {
self.list_view.destroy();
return $.when(self.load_view()).then(function() {
- self.reload_content();
+ self.render_value();
});
});
});
});
+ this._super.apply(this, arguments);
},
set_value: function(value_) {
value_ = value_ || [];
@@ -4055,17 +3994,12 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
value_ = value_[0][2];
}
this._super(value_);
- this.dataset.set_ids(value_);
- var self = this;
- self.reload_content();
- this.is_setted.resolve();
},
get_value: function() {
return [commands.replace_with(this.get('value'))];
},
-
is_false: function () {
- return _(this.dataset.ids).isEmpty();
+ return _(this.get("value")).isEmpty();
},
load_view: function() {
var self = this;
@@ -4092,14 +4026,15 @@ instance.web.form.FieldMany2Many = instance.web.form.AbstractField.extend({
});
return loaded;
},
- reload_content: function() {
+ render_value: function() {
var self = this;
+ this.dataset.set_ids(this.get("value"));
this.is_loaded = this.is_loaded.pipe(function() {
return self.list_view.reload_content();
});
},
dataset_changed: function() {
- this.set({'value': this.dataset.ids});
+ this.internal_set_value(this.dataset.ids);
},
});
@@ -4126,7 +4061,7 @@ instance.web.form.Many2ManyListView = instance.web.ListView.extend(/** @lends in
this.m2m_field.build_context()
);
var self = this;
- pop.on_select_elements.add(function(element_ids) {
+ pop.on("elements_selected", self, function(element_ids) {
_.each(element_ids, function(one_id) {
if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) {
self.dataset.set_ids([].concat(self.dataset.ids, [one_id]));
@@ -4155,28 +4090,26 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
m2m_kanban_lazy_init();
this.is_loaded = $.Deferred();
this.initial_is_loaded = this.is_loaded;
- this.is_setted = $.Deferred();
+
+ var self = this;
+ this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
+ this.dataset.m2m = this;
+ this.dataset.on('unlink', self, function(ids) {
+ self.dataset_changed();
+ });
},
start: function() {
this._super.apply(this, arguments);
var self = this;
- this.dataset = new instance.web.form.Many2ManyDataSet(this, this.field.relation);
- this.dataset.m2m = this;
- this.dataset.on('unlink', self, function(ids) {
- self.dataset_changed();
- });
-
- this.is_setted.then(function() {
- self.load_view();
- });
+ self.load_view();
this.is_loaded.then(function() {
self.on("change:effective_readonly", self, function() {
self.is_loaded = self.is_loaded.pipe(function() {
self.kanban_view.destroy();
return $.when(self.load_view()).then(function() {
- self.reload_content();
+ self.render_value();
});
});
});
@@ -4188,10 +4121,6 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
value_ = value_[0][2];
}
this._super(value_);
- this.dataset.set_ids(value_);
- var self = this;
- self.reload_content();
- this.is_setted.resolve();
},
load_view: function() {
var self = this;
@@ -4218,8 +4147,9 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
});
return loaded;
},
- reload_content: function() {
+ render_value: function() {
var self = this;
+ this.dataset.set_ids(this.get("value"));
this.is_loaded = this.is_loaded.pipe(function() {
return self.kanban_view.do_search(self.build_domain(), self.dataset.get_context(), []);
});
@@ -4241,12 +4171,12 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
new instance.web.CompoundDomain(this.build_domain(), ["!", ["id", "in", this.dataset.ids]]),
this.build_context()
);
- pop.on_select_elements.add(function(element_ids) {
+ pop.on("elements_selected", self, function(element_ids) {
_.each(element_ids, function(one_id) {
if(! _.detect(self.dataset.ids, function(x) {return x == one_id;})) {
self.dataset.set_ids([].concat(self.dataset.ids, [one_id]));
self.dataset_changed();
- self.reload_content();
+ self.render_value();
}
});
});
@@ -4257,7 +4187,7 @@ instance.web.form.FieldMany2ManyKanban = instance.web.form.AbstractField.extend(
title: _t("Open: ") + self.string,
write_function: function(id, data, options) {
return self.dataset.write(id, data, {}).then(function() {
- self.reload_content();
+ self.render_value();
});
},
alternative_form_view: self.field.views ? self.field.views["form"] : undefined,
@@ -4407,9 +4337,8 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
self.check_exit(true);
},
title: this.options.title || "",
- buttons: [{text:"tmp"}],
}, this.$el).open();
- this.$buttonpane = dialog.$el.dialog("widget").find(".ui-dialog-buttonpane").html("");
+ this.$buttonpane = dialog.$buttons;
this.start();
},
setup_form_view: function() {
@@ -4440,7 +4369,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
}));
var $snbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save-new");
$snbutton.click(function() {
- $.when(self.view_form.do_save()).then(function() {
+ $.when(self.view_form.save()).then(function() {
self.view_form.reload_mutex.exec(function() {
self.view_form.on_button_new();
});
@@ -4448,7 +4377,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
});
var $sbutton = self.$buttonpane.find(".oe_abstractformpopup-form-save");
$sbutton.click(function() {
- $.when(self.view_form.do_save()).then(function() {
+ $.when(self.view_form.save()).then(function() {
self.view_form.reload_mutex.exec(function() {
self.check_exit();
});
@@ -4461,11 +4390,12 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({
self.view_form.do_show();
});
},
- on_select_elements: function(element_ids) {
+ select_elements: function(element_ids) {
+ this.trigger("elements_selected", element_ids);
},
check_exit: function(no_destroy) {
if (this.created_elements.length > 0) {
- this.on_select_elements(this.created_elements);
+ this.select_elements(this.created_elements);
this.created_elements = [];
}
this.destroy();
@@ -4576,7 +4506,7 @@ instance.web.form.SelectCreatePopup = instance.web.form.AbstractFormPopup.extend
});
var $sbutton = self.$buttonpane.find(".oe_selectcreatepopup-search-select");
$sbutton.click(function() {
- self.on_select_elements(self.selected_ids);
+ self.select_elements(self.selected_ids);
self.destroy();
});
});
@@ -4618,7 +4548,7 @@ instance.web.form.SelectCreateListView = instance.web.ListView.extend({
this.popup.new_object();
},
select_record: function(index) {
- this.popup.on_select_elements([this.dataset.ids[index]]);
+ this.popup.select_elements([this.dataset.ids[index]]);
this.popup.destroy();
},
do_select: function(ids, records) {
@@ -4646,6 +4576,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
destroy_content: function() {
if (this.fm) {
this.fm.destroy();
+ this.fm = undefined;
}
},
initialize_content: function() {
@@ -4667,9 +4598,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
}});
this.selection.on("change:value", this, this.on_selection_changed);
- this.selection.setElement(this.$(".oe_form_view_reference_selection"));
- this.selection.renderElement();
- this.selection.start();
+ this.selection.appendTo(this.$(".oe_form_view_reference_selection"));
this.selection
.on('focused', null, function () {self.trigger('focused')})
.on('blurred', null, function () {self.trigger('blurred')});
@@ -4679,9 +4608,7 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
modifiers: JSON.stringify({readonly: this.get('effective_readonly')}),
}});
this.m2o.on("change:value", this, this.data_changed);
- this.m2o.setElement(this.$(".oe_form_view_reference_m2o"));
- this.m2o.renderElement();
- this.m2o.start();
+ this.m2o.appendTo(this.$(".oe_form_view_reference_m2o"));
this.m2o
.on('focused', null, function () {self.trigger('focused')})
.on('blurred', null, function () {self.trigger('blurred')});
@@ -4689,10 +4616,6 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
is_false: function() {
return typeof(this.get_value()) !== 'string';
},
- set_value: function(value_) {
- this._super(value_);
- this.render_value();
- },
render_value: function() {
this.reference_ready = false;
var vals = [], sel_val, m2o_val;
@@ -4712,9 +4635,9 @@ instance.web.form.FieldReference = instance.web.form.AbstractField.extend(instan
var model = this.selection.get_value(),
id = this.m2o.get_value();
if (typeof(model) === 'string' && typeof(id) === 'number') {
- this.set({'value': model + ',' + id});
+ this.internal_set_value(model + ',' + id);
} else {
- this.set({'value': false});
+ this.internal_set_value(false);
}
},
});
@@ -4813,7 +4736,7 @@ instance.web.form.FieldBinary = instance.web.form.AbstractField.extend(instance.
on_clear: function() {
if (this.get('value') !== false) {
this.binary_value = false;
- this.set({'value': false});
+ this.internal_set_value(false);
}
return false;
}
@@ -4833,10 +4756,6 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
});
}
},
- set_value: function(value_) {
- this._super.apply(this, arguments);
- this.render_value();
- },
render_value: function() {
if (!this.get("effective_readonly")) {
var show_value;
@@ -4858,7 +4777,7 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
},
on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
this.binary_value = true;
- this.set({'value': file_base64});
+ this.internal_set_value(file_base64);
var show_value = name + " (" + this.human_filesize(size) + ")";
this.$el.find('input').eq(0).val(show_value);
this.set_filename(name);
@@ -4872,10 +4791,6 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({
instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
template: 'FieldBinaryImage',
- set_value: function(value_) {
- this._super.apply(this, arguments);
- this.render_value();
- },
render_value: function() {
var self = this;
var url;
@@ -4908,7 +4823,7 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
this._super.apply(this, arguments);
},
on_file_uploaded_and_valid: function(size, name, content_type, file_base64) {
- this.set({'value': file_base64});
+ this.internal_set_value(file_base64);
this.binary_value = true;
this.render_value();
this.set_filename(name);
@@ -4926,38 +4841,34 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
this._super(field_manager, node);
this.options.clickable = this.options.clickable || (this.node.attrs || {}).clickable || false;
this.options.visible = this.options.visible || (this.node.attrs || {}).statusbar_visible || false;
- this.selected_value = null;
+ this.set({value: false});
},
start: function() {
- this._super();
- // backward compatibility
- this.loaded = new $.Deferred();
if (this.options.clickable) {
this.$el.on('click','li',this.on_click_stage);
}
- // TODO move the following into css :after
if (this.$el.parent().is('header')) {
this.$el.after('');
}
+ this._super();
},
set_value: function(value_) {
- var self = this;
- this._super(value_);
- // find selected value:
- // - many2one: [2, "New"] -> 2
- // - selection: new -> new
- if (this.field.type == "many2one") {
- this.selected_value = value_[0];
- } else {
- this.selected_value = value_;
+ if (value_ instanceof Array) {
+ value_ = value_[0];
}
- // trick to be sure all values are loaded in the form, therefore
- // enabling the evaluation of dynamic domains
- self.selection = [];
- $.async_when().then(function() {
- self.get_selection();
+ this._super(value_);
+ },
+ render_value: function() {
+ var self = this;
+ self.get_selection().then(function() {
+ var content = QWeb.render("FieldStatus.content", {widget: self});
+ self.$el.html(content);
+ var colors = JSON.parse((self.node.attrs || {}).statusbar_colors || "{}");
+ var color = colors[self.get('value')];
+ if (color) {
+ self.$("oe_active").css("color", color);
+ }
});
- return this.loaded;
},
/** Get the selection and render it
* selection: [[identifier, value_to_display], ...]
@@ -4966,53 +4877,37 @@ instance.web.form.FieldStatus = instance.web.form.AbstractField.extend({
*/
get_selection: function() {
var self = this;
+ self.selection = [];
if (this.field.type == "many2one") {
var domain = [];
if(!_.isEmpty(this.field.domain) || !_.isEmpty(this.node.attrs.domain)) {
- domain = new instance.web.CompoundDomain(['|'], self.build_domain(), [['id', '=', self.selected_value]]);
+ domain = new instance.web.CompoundDomain(['|'], self.build_domain(), [['id', '=', self.get('value')]]);
}
var ds = new instance.web.DataSetSearch(this, this.field.relation, self.build_context(), domain);
- ds.read_slice(['name'], {}).done( function (records) {
+ return ds.read_slice(['name'], {}).pipe(function (records) {
for(var i = 0; i < records.length; i++) {
self.selection.push([records[i].id, records[i].name]);
}
- self.render_elements();
- self.loaded.resolve();
});
} else {
- this.loaded.resolve();
// For field type selection filter values according to
// statusbar_visible attribute of the field. For example:
// statusbar_visible="draft,open".
var selection = this.field.selection;
- for(var i=0; i< selection.length; i++) {
+ for(var i=0; i < selection.length; i++) {
var key = selection[i][0];
- if(key == this.selected_value || !this.options.visible || this.options.visible.indexOf(key) != -1) {
+ if(key == this.get('value') || !this.options.visible || this.options.visible.indexOf(key) != -1) {
this.selection.push(selection[i]);
}
}
- this.render_elements();
- }
- },
- /** Renders the widget. This function also checks for statusbar_colors='{"pending": "blue"}'
- * attribute in the widget. This allows to set a given color to a given
- * state (given by the key of (key, label)).
- */
- render_elements: function () {
- var self = this;
- var content = instance.web.qweb.render("FieldStatus.content", {widget: this});
- this.$el.html(content);
- var colors = JSON.parse((this.node.attrs || {}).statusbar_colors || "{}");
- var color = colors[this.selected_value];
- if (color) {
- this.$("oe_active").css("color", color);
+ return $.when();
}
},
on_click_stage: function (ev) {
var self = this;
var $li = $(ev.currentTarget);
var val = parseInt($li.data("id"));
- if (val != self.selected_value) {
+ if (val != self.get('value')) {
this.view.recursive_save().then(function() {
var change = {};
change[self.name] = val;
diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js
index 7457ca5ef67..a6aa637f655 100644
--- a/addons/web/static/src/js/view_list.js
+++ b/addons/web/static/src/js/view_list.js
@@ -64,9 +64,9 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
this.set_groups(new (this.options.GroupsType)(this));
if (this.dataset instanceof instance.web.DataSetStatic) {
- this.groups.datagroup = new instance.web.StaticDataGroup(this.dataset);
+ this.groups.datagroup = new StaticDataGroup(this.dataset);
} else {
- this.groups.datagroup = new instance.web.DataGroup(
+ this.groups.datagroup = new DataGroup(
this, this.model,
dataset.get_domain(),
dataset.get_context());
@@ -399,14 +399,10 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
*/
setup_columns: function (fields, grouped) {
var registry = instance.web.list.columns;
- var reorder = this.options.reorderable;
this.columns.splice(0, this.columns.length);
this.columns.push.apply(this.columns,
_(this.fields_view.arch.children).map(function (field) {
var id = field.attrs.name;
- if(field.attrs.widget == 'handle' && !reorder){
- field.attrs.reorderable = reorder || true;
- }
return registry.for_(id, fields[id], field);
}));
if (grouped) {
@@ -415,8 +411,9 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
}
this.visible_columns = _.filter(this.columns, function (column) {
- return column.invisible !== '1' && !column.reorderable;
+ return column.invisible !== '1';
});
+
this.aggregate_columns = _(this.visible_columns).invoke('to_aggregate');
},
/**
@@ -557,7 +554,7 @@ instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListVi
*/
do_search: function (domain, context, group_by) {
this.page = 0;
- this.groups.datagroup = new instance.web.DataGroup(
+ this.groups.datagroup = new DataGroup(
this, this.model, domain, context, group_by);
this.groups.datagroup.sort = this.dataset._sort;
@@ -1153,7 +1150,7 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
passtrough_events: 'action deleted row_link',
/**
* Grouped display for the ListView. Handles basic DOM events and interacts
- * with the :js:class:`~instance.web.DataGroup` bound to it.
+ * with the :js:class:`~DataGroup` bound to it.
*
* Provides events similar to those of
* :js:class:`~instance.web.ListView.List`
@@ -1558,6 +1555,60 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we
}
});
+var DataGroup = instance.web.CallbackEnabled.extend({
+ init: function(parent, model, domain, context, group_by, level) {
+ this._super(parent, null);
+ this.model = new instance.web.Model(model, context, domain);
+ this.group_by = group_by;
+ this.context = context;
+ this.domain = domain;
+
+ this.level = level || 0;
+ },
+ list: function (fields, ifGroups, ifRecords) {
+ var self = this;
+ var query = this.model.query(fields).order_by(this.sort).group_by(this.group_by);
+ $.when(query).then(function (querygroups) {
+ // leaf node
+ if (!querygroups) {
+ var ds = new instance.web.DataSetSearch(self, self.model.name, self.model.context(), self.model.domain());
+ ds._sort = self.sort;
+ ifRecords(ds);
+ return;
+ }
+ // internal node
+ var child_datagroups = _(querygroups).map(function (group) {
+ var child_context = _.extend(
+ {}, self.model.context(), group.model.context());
+ var child_dg = new DataGroup(
+ self, self.model.name, group.model.domain(),
+ child_context, group.model._context.group_by,
+ self.level + 1);
+ child_dg.sort = self.sort;
+ // copy querygroup properties
+ child_dg.__context = child_context;
+ child_dg.__domain = group.model.domain();
+ child_dg.folded = group.get('folded');
+ child_dg.grouped_on = group.get('grouped_on');
+ child_dg.length = group.get('length');
+ child_dg.value = group.get('value');
+ child_dg.openable = group.get('has_children');
+ child_dg.aggregates = group.get('aggregates');
+ return child_dg;
+ });
+ ifGroups(child_datagroups);
+ });
+ }
+});
+var StaticDataGroup = DataGroup.extend({
+ init: function (dataset) {
+ this.dataset = dataset;
+ },
+ list: function (fields, ifGroups, ifRecords) {
+ ifRecords(this.dataset);
+ }
+});
+
/**
* @mixin Events
*/
diff --git a/addons/web/static/src/js/view_list_editable.js b/addons/web/static/src/js/view_list_editable.js
index fe0f525fe3f..cd6b018ea0d 100644
--- a/addons/web/static/src/js/view_list_editable.js
+++ b/addons/web/static/src/js/view_list_editable.js
@@ -201,10 +201,7 @@ openerp.web.list_editable = function (instance) {
}, function () {
return self.editor.edit(item, function (field_name, field) {
var cell = cells[field_name];
- if (!cell || field.get('effective_readonly')) {
- // Readonly fields can just remain the list's,
- // form's usually don't have backgrounds &al
- field.set({invisible: true});
+ if (!cell) {
return;
}
@@ -400,6 +397,21 @@ openerp.web.list_editable = function (instance) {
},
setup_events: function () {
var self = this;
+ _.each(this.editor.form.fields, function(field, field_name) {
+ var field;
+ var setting = false;
+ var set_invisible = function() {
+ if (!setting && field.get("effective_readonly")) {
+ setting = true;
+ field.set({invisible: true});
+ setting = false;
+ }
+ };
+ field.on("change:effective_readonly", self, set_invisible);
+ field.on("change:invisible", self, set_invisible);
+ set_invisible();
+ });
+
this.editor.$el.on('keyup keydown', function (e) {
if (!self.editor.is_editing()) { return; }
var key = _($.ui.keyCode).chain()
@@ -724,7 +736,7 @@ openerp.web.list_editable = function (instance) {
save: function () {
var self = this;
return this.form
- .do_save(this.delegate.prepends_on_create())
+ .save(this.delegate.prepends_on_create())
.pipe(function (result) {
var created = result.created && !self.record.id;
if (created) {
diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js
index f985e5f6dc8..45993db27bb 100644
--- a/addons/web/static/src/js/views.js
+++ b/addons/web/static/src/js/views.js
@@ -113,6 +113,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
var item = this.breadcrumbs[index];
item.show(subindex);
this.inner_widget = item.widget;
+ this.inner_action = item.action;
return true;
},
clear_breadcrumbs: function() {
@@ -131,6 +132,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
if (!dups.length) {
if (this.getParent().has_uncommitted_changes()) {
this.inner_widget = item.widget;
+ this.inner_action = item.action;
this.breadcrumbs.splice(index, 0, item);
return false;
} else {
@@ -139,7 +141,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
}
var last_widget = this.breadcrumbs.slice(-1)[0];
- this.inner_widget = last_widget && last_widget.widget;
+ if (last_widget) {
+ this.inner_widget = last_widget.widget;
+ this.inner_action = last_widget.action;
+ }
},
get_title: function() {
var titles = [];
@@ -164,6 +169,10 @@ instance.web.ActionManager = instance.web.Widget.extend({
state = state || {};
if (this.getParent() && this.getParent().do_push_state) {
if (this.inner_action) {
+ if (this.inner_action._push_me === false) {
+ // this action has been explicitly marked as not pushable
+ return;
+ }
state['title'] = this.inner_action.name;
if(this.inner_action.type == 'ir.actions.act_window') {
state['model'] = this.inner_action.res_model;
@@ -172,7 +181,13 @@ instance.web.ActionManager = instance.web.Widget.extend({
state['action'] = this.inner_action.id;
} else if (this.inner_action.type == 'ir.actions.client') {
state['action'] = this.inner_action.tag;
- //state = _.extend(this.inner_action.params || {}, state);
+ var params = {};
+ _.each(this.inner_action.params, function(v, k) {
+ if(_.isString(v) || _.isNumber(v)) {
+ params[k] = v;
+ }
+ });
+ state = _.extend(params || {}, state);
}
}
if(!this.dialog) {
@@ -224,14 +239,19 @@ instance.web.ActionManager = instance.web.Widget.extend({
}
});
},
- do_action: function(action, on_close, clear_breadcrumbs, on_reverse_breadcrumb) {
+ do_action: function(action, options) {
+ options = _.defaults(options || {}, {
+ clear_breadcrumbs: false,
+ on_reverse_breadcrumb: function() {},
+ on_close: function() {},
+ });
if (_.isString(action) && instance.web.client_actions.contains(action)) {
var action_client = { type: "ir.actions.client", tag: action };
- return this.do_action(action_client, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
+ return this.do_action(action_client, options);
} else if (_.isNumber(action) || _.isString(action)) {
var self = this;
return self.rpc("/web/action/load", { action_id: action }).pipe(function(result) {
- return self.do_action(result, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
+ return self.do_action(result, options);
});
}
if (!action.type) {
@@ -253,7 +273,7 @@ instance.web.ActionManager = instance.web.Widget.extend({
console.error("Action manager can't handle action of type " + action.type, action);
return $.Deferred().reject();
}
- return this[type](action, on_close, clear_breadcrumbs, on_reverse_breadcrumb);
+ return this[type](action, options);
},
null_action: function() {
this.dialog_stop();
@@ -266,32 +286,36 @@ instance.web.ActionManager = instance.web.Widget.extend({
* @param {Function} executor.widget function used to fetch the widget instance
* @param {String} executor.klass CSS class to add on the dialog root, if action.target=new
* @param {Function} executor.post_process cleanup called after a widget has been added as inner_widget
- * @param on_close
- * @param clear_breadcrumbs
+ * @param {Object} options
* @return {*}
*/
- ir_actions_common: function(executor, on_close, clear_breadcrumbs) {
+ ir_actions_common: function(executor, options) {
if (this.inner_widget && executor.action.target !== 'new') {
if (this.getParent().has_uncommitted_changes()) {
return $.Deferred().reject();
- } else if (clear_breadcrumbs) {
+ } else if (options.clear_breadcrumbs) {
this.clear_breadcrumbs();
}
}
var widget = executor.widget();
if (executor.action.target === 'new') {
- if (this.dialog === null) {
- // These buttons will be overwrited by