diff --git a/.project b/.project new file mode 100644 index 0000000..a01f1f9 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + BTable + + + + + + + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..4b1e63e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,356 @@ + +Mozilla Public License, version 2.0 + +1. Definitions + +1.1. “Contributor” + + means each individual or legal entity that creates, contributes to the + creation of, or owns Covered Software. + +1.2. “Contributor Version” + + means the combination of the Contributions of others (if any) used by a + Contributor and that particular Contributor’s Contribution. + +1.3. “Contribution” + + means Covered Software of a particular Contributor. + +1.4. “Covered Software” + + means Source Code Form to which the initial Contributor has attached the + notice in Exhibit A, the Executable Form of such Source Code Form, and + Modifications of such Source Code Form, in each case including portions + thereof. + +1.5. “Incompatible With Secondary Licenses” + + means + + a. that the initial Contributor has attached the notice described in + Exhibit B to the Covered Software; or + + b. that the Covered Software was made available under the terms of version + 1.1 or earlier of the License, but not also under the terms of a + Secondary License. + +1.6. “Executable Form” + + means any form of the work other than Source Code Form. + +1.7. “Larger Work” + + means a work that combines Covered Software with other material, in a separate + file or files, that is not Covered Software. + +1.8. “License” + + means this document. + +1.9. “Licensable” + + means having the right to grant, to the maximum extent possible, whether at the + time of the initial grant or subsequently, any and all of the rights conveyed by + this License. + +1.10. “Modifications” + + means any of the following: + + a. any file in Source Code Form that results from an addition to, deletion + from, or modification of the contents of Covered Software; or + + b. any new file in Source Code Form that contains any Covered Software. + +1.11. “Patent Claims” of a Contributor + + means any patent claim(s), including without limitation, method, process, + and apparatus claims, in any patent Licensable by such Contributor that + would be infringed, but for the grant of the License, by the making, + using, selling, offering for sale, having made, import, or transfer of + either its Contributions or its Contributor Version. + +1.12. “Secondary License” + + means either the GNU General Public License, Version 2.0, the GNU Lesser + General Public License, Version 2.1, the GNU Affero General Public + License, Version 3.0, or any later versions of those licenses. + +1.13. “Source Code Form” + + means the form of the work preferred for making modifications. + +1.14. “You” (or “Your”) + + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that controls, is + controlled by, or is under common control with You. For purposes of this + definition, “control” means (a) the power, direct or indirect, to cause + the direction or management of such entity, whether by contract or + otherwise, or (b) ownership of more than fifty percent (50%) of the + outstanding shares or beneficial ownership of such entity. + + +2. License Grants and Conditions + +2.1. Grants + + Each Contributor hereby grants You a world-wide, royalty-free, + non-exclusive license: + + a. under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or as + part of a Larger Work; and + + b. under Patent Claims of such Contributor to make, use, sell, offer for + sale, have made, import, and otherwise transfer either its Contributions + or its Contributor Version. + +2.2. Effective Date + + The licenses granted in Section 2.1 with respect to any Contribution become + effective for each Contribution on the date the Contributor first distributes + such Contribution. + +2.3. Limitations on Grant Scope + + The licenses granted in this Section 2 are the only rights granted under this + License. No additional rights or licenses will be implied from the distribution + or licensing of Covered Software under this License. Notwithstanding Section + 2.1(b) above, no patent license is granted by a Contributor: + + a. for any code that a Contributor has removed from Covered Software; or + + b. for infringements caused by: (i) Your and any other third party’s + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + + c. under Patent Claims infringed by Covered Software in the absence of its + Contributions. + + This License does not grant any rights in the trademarks, service marks, or + logos of any Contributor (except as may be necessary to comply with the + notice requirements in Section 3.4). + +2.4. Subsequent Licenses + + No Contributor makes additional grants as a result of Your choice to + distribute the Covered Software under a subsequent version of this License + (see Section 10.2) or under the terms of a Secondary License (if permitted + under the terms of Section 3.3). + +2.5. Representation + + Each Contributor represents that the Contributor believes its Contributions + are its original creation(s) or it has sufficient rights to grant the + rights to its Contributions conveyed by this License. + +2.6. Fair Use + + This License is not intended to limit any rights You have under applicable + copyright doctrines of fair use, fair dealing, or other equivalents. + +2.7. Conditions + + Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in + Section 2.1. + + +3. Responsibilities + +3.1. Distribution of Source Form + + All distribution of Covered Software in Source Code Form, including any + Modifications that You create or to which You contribute, must be under the + terms of this License. You must inform recipients that the Source Code Form + of the Covered Software is governed by the terms of this License, and how + they can obtain a copy of this License. You may not attempt to alter or + restrict the recipients’ rights in the Source Code Form. + +3.2. Distribution of Executable Form + + If You distribute Covered Software in Executable Form then: + + a. such Covered Software must also be made available in Source Code Form, + as described in Section 3.1, and You must inform recipients of the + Executable Form how they can obtain a copy of such Source Code Form by + reasonable means in a timely manner, at a charge no more than the cost + of distribution to the recipient; and + + b. You may distribute such Executable Form under the terms of this License, + or sublicense it under different terms, provided that the license for + the Executable Form does not attempt to limit or alter the recipients’ + rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + + You may create and distribute a Larger Work under terms of Your choice, + provided that You also comply with the requirements of this License for the + Covered Software. If the Larger Work is a combination of Covered Software + with a work governed by one or more Secondary Licenses, and the Covered + Software is not Incompatible With Secondary Licenses, this License permits + You to additionally distribute such Covered Software under the terms of + such Secondary License(s), so that the recipient of the Larger Work may, at + their option, further distribute the Covered Software under the terms of + either this License or such Secondary License(s). + +3.4. Notices + + You may not remove or alter the substance of any license notices (including + copyright notices, patent notices, disclaimers of warranty, or limitations + of liability) contained within the Source Code Form of the Covered + Software, except that You may alter any license notices to the extent + required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + + You may choose to offer, and to charge a fee for, warranty, support, + indemnity or liability obligations to one or more recipients of Covered + Software. However, You may do so only on Your own behalf, and not on behalf + of any Contributor. You must make it absolutely clear that any such + warranty, support, indemnity, or liability obligation is offered by You + alone, and You hereby agree to indemnify every Contributor for any + liability incurred by such Contributor as a result of warranty, support, + indemnity or liability terms You offer. You may include additional + disclaimers of warranty and limitations of liability specific to any + jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + + If it is impossible for You to comply with any of the terms of this License + with respect to some or all of the Covered Software due to statute, judicial + order, or regulation then You must: (a) comply with the terms of this License + to the maximum extent possible; and (b) describe the limitations and the code + they affect. Such description must be placed in a text file included with all + distributions of the Covered Software under this License. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Termination + +5.1. The rights granted under this License will terminate automatically if You + fail to comply with any of its terms. However, if You become compliant, + then the rights granted under this License from a particular Contributor + are reinstated (a) provisionally, unless and until such Contributor + explicitly and finally terminates Your grants, and (b) on an ongoing basis, + if such Contributor fails to notify You of the non-compliance by some + reasonable means prior to 60 days after You have come back into compliance. + Moreover, Your grants from a particular Contributor are reinstated on an + ongoing basis if such Contributor notifies You of the non-compliance by + some reasonable means, this is the first time You have received notice of + non-compliance with this License from such Contributor, and You become + compliant prior to 30 days after Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent + infringement claim (excluding declaratory judgment actions, counter-claims, + and cross-claims) alleging that a Contributor Version directly or + indirectly infringes any patent, then the rights granted to You by any and + all Contributors for the Covered Software under Section 2.1 of this License + shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user + license agreements (excluding distributors and resellers) which have been + validly granted by You or Your distributors under this License prior to + termination shall survive termination. + +6. Disclaimer of Warranty + + Covered Software is provided under this License on an “as is” basis, without + warranty of any kind, either expressed, implied, or statutory, including, + without limitation, warranties that the Covered Software is free of defects, + merchantable, fit for a particular purpose or non-infringing. The entire + risk as to the quality and performance of the Covered Software is with You. + Should any Covered Software prove defective in any respect, You (not any + Contributor) assume the cost of any necessary servicing, repair, or + correction. This disclaimer of warranty constitutes an essential part of this + License. No use of any Covered Software is authorized under this License + except under this disclaimer. + +7. Limitation of Liability + + Under no circumstances and under no legal theory, whether tort (including + negligence), contract, or otherwise, shall any Contributor, or anyone who + distributes Covered Software as permitted above, be liable to You for any + direct, indirect, special, incidental, or consequential damages of any + character including, without limitation, damages for lost profits, loss of + goodwill, work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses, even if such party shall have been + informed of the possibility of such damages. This limitation of liability + shall not apply to liability for death or personal injury resulting from such + party’s negligence to the extent applicable law prohibits such limitation. + Some jurisdictions do not allow the exclusion or limitation of incidental or + consequential damages, so this exclusion and limitation may not apply to You. + +8. Litigation + + Any litigation relating to this License may be brought only in the courts of + a jurisdiction where the defendant maintains its principal place of business + and such litigation shall be governed by laws of that jurisdiction, without + reference to its conflict-of-law provisions. Nothing in this Section shall + prevent a party’s ability to bring cross-claims or counter-claims. + +9. Miscellaneous + + This License represents the complete agreement concerning the subject matter + hereof. If any provision of this License is held to be unenforceable, such + provision shall be reformed only to the extent necessary to make it + enforceable. Any law or regulation which provides that the language of a + contract shall be construed against the drafter shall not be used to construe + this License against a Contributor. + + +10. Versions of the License + +10.1. New Versions + + Mozilla Foundation is the license steward. Except as provided in Section + 10.3, no one other than the license steward has the right to modify or + publish new versions of this License. Each version will be given a + distinguishing version number. + +10.2. Effect of New Versions + + You may distribute the Covered Software under the terms of the version of + the License under which You originally received the Covered Software, or + under the terms of any subsequent version published by the license + steward. + +10.3. Modified Versions + + If you create software not governed by this License, and you want to + create a new license for such software, you may create and use a modified + version of this License if you rename the license and remove any + references to the name of the license steward (except to note that such + modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + If You choose to distribute Source Code Form that is Incompatible With + Secondary Licenses under the terms of this version of the License, the + notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the + terms of the Mozilla Public License, v. + 2.0. If a copy of the MPL was not + distributed with this file, You can + obtain one at + http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular file, then +You may include the notice in a location (such as a LICENSE file in a relevant +directory) where a recipient would be likely to look for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is “Incompatible + With Secondary Licenses”, as defined by + the Mozilla Public License, v. 2.0. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7c0903 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +BTable +====== + +A drill-anywhere component for the Pentaho Community Dashboard Designer (CDE). + +Video tutorial and more on [www.biztech.it/btable](http://www.biztech.it/btable). + +BTable is released under the [Mozilla Public Licence (MPLv2)](http://www.mozilla.org/MPL/2.0/). + +This plugin has been made using [Sparkl](https://github.com/webdetails/sparkl). diff --git a/build-res/subfloor-pkg.xml b/build-res/subfloor-pkg.xml new file mode 100644 index 0000000..5e010ec --- /dev/null +++ b/build-res/subfloor-pkg.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build-res/subfloor.xml b/build-res/subfloor.xml new file mode 100644 index 0000000..84f2fae --- /dev/null +++ b/build-res/subfloor.xml @@ -0,0 +1,1841 @@ + + + + + + +------------------------------------------------------------------------------- + subfloor.xml provides tasks needed to perform a project build. + It is typically not used directly but imported by each project's build.xml + file. The build.xml file can override tasks when customization is required. + +MAIN TARGETS +============ + * clean / clean-all : + remove all artifacts of the build, clean-all adds the removal + of any library or jar dependencies downloaded as part of the build + + * resolve : + download/refresh library or jar dependencies needed for the build (uses Apache IVY) + + * compile : + run javac on the project's source + + * jar : + creates a jar file + + * dist : + creates all project distributables + + * test : + runs JUnit tests from your project's test source + +SPECIAL TARGETS +============ + * publish-local : + builds a jar for your project and registers it with the local artifact repository isolated + to your machine at $HOME/.ivy2/local. Further executions of the the resolve target by this + or other projects will find your published jar. + + * ivy-clean* : + this family of targets helps reset your IVY environment in the event that you are having + difficulty resolving dependencies + +TYPICAL TARGET SEQUENCE +============ + * clean-all resolve dist : + a good start to build all project distributables from scratch. Note that jar dependencies + will not be downloaded unless you explicitly run the resolve target. We made the resolution + and retrieval completely discretionary since there are many situations in which + you will not want to get or refresh dependencies, e.g. if you are offline with no Internet + access. In such case, you could just run "dist" if the set of jars you already have are + sufficient. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..2222922 --- /dev/null +++ b/build.properties @@ -0,0 +1,10 @@ +project.revision=STABLE +# Stage: TRUNK | STABLE | BETA | other branch +project.stage=STABLE +# Version: a numeric value or SNAPSHOT. SNAPSHOT is replaced by DSTAMP +project.version=1.0 +ivy.artifact.id=BTable +ivy.artifact.group=Biz Tech +impl.title=BTable - A Drill-Anywhere Component For CDE +testsrc.dir=test +dependency.bi-platform.revision=4.8.0-stable diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..b4b0521 --- /dev/null +++ b/build.xml @@ -0,0 +1,98 @@ + + + This build file is used to create the BTable project + and works with the common_build.xml file. + + + + + + + + + distribution.version = ${distribution.version} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <version> + <branch>TRUNK</branch> + <version>${distribution.version}</version> + <name>Trunk</name> + <package_url>not defined</package_url> + <description>@PLUGIN_PACKAGE_DESCRIPTION</description> + <build_id>${sequential.build.id}</build_id> + </version> + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cpk.xml b/cpk.xml new file mode 100644 index 0000000..be1c526 --- /dev/null +++ b/cpk.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + 3 + BTable - A Drill-Anywhere Component For CDE + BTable + info@biztech.it + Massimo Bonometto, Luca Pazzaglia + Biz Tech + www.biztech.it + 2013-10-11 + 1.0 + + diff --git a/dashboards/About.cdfde b/dashboards/About.cdfde new file mode 100644 index 0000000..fd83635 --- /dev/null +++ b/dashboards/About.cdfde @@ -0,0 +1,181 @@ +{ + "layout": { + "title": "About", + "rows": [ + { + "id": "0272ca53-b773-3c47-221c-6adcef471d28", + "type": "LayoutResourceCode", + "typeDesc": "Resource", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "css", + "type": "Id" + }, + { + "name": "resourceType", + "value": "Css", + "type": "Label" + }, + { + "name": "resourceCode", + "value": ".container {\n margin-top: 18px;\n margin-bottom: 0px;\n margin-left: 19px;\n width: 900px;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n ", + "type": "Resource" + } + ] + }, + { + "id": "00f303f9-b2ce-e836-a339-dc2ef7aeba67", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "fd2467eb-e6bc-811b-22c9-00f590b5396f", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "00f303f9-b2ce-e836-a339-dc2ef7aeba67", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "columnSpan", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "c6437c24-ba57-3d27-b821-5706d9c26d5f", + "type": "LayoutHtml", + "typeDesc": "Html", + "parent": "fd2467eb-e6bc-811b-22c9-00f590b5396f", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "html", + "value": "

\n BTable is a component for the Community Dashboard Designer (CDE) \n that extends the standard Table Component with OLAP functionalities and provides \n a new drill experience.\n

\n

\n Dashboard users can easily interact with the table through a context menu that allows to:\n

\n Dashboard designers can build flexible and rich tables with little effort, \n indicating a Mondrian schema and a JNDI connection and writing the initial \n query in a more friendly manner.\n

\n

\n To use BTable with your data, first you need to create CDA data sources for BTable. \n Click Data Sources in the top menu to create them importing Mondrian catalogs.\n

\n

\n A BTable data source for Steel Wheels is provided with this plugin to run the \n sample dashboard. Check you have the same Mondrian schema location and JNDI in your system.\n

\n

\n Documentation, video tutorials and more on \n www.biztech.it/btable.\n

\n

\n For questions, suggestions and bugs reporting use \n Pentaho Forums.\n

\n

\n Have fun with BTable!\n

", + "type": "Html" + }, + { + "name": "fontSize", + "value": "", + "type": "Integer" + }, + { + "name": "color", + "value": "", + "type": "Color" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + } + ] + }, + "components": { + "rows": [] + }, + "datasources": { + "rows": [] + }, + "filename": "/system/BTable/dashboards/About.cdfde" +} \ No newline at end of file diff --git a/dashboards/About.wcdf b/dashboards/About.wcdf new file mode 100644 index 0000000..c3a2e73 --- /dev/null +++ b/dashboards/About.wcdf @@ -0,0 +1,2 @@ + +AboutBiz Techblueprintfalse \ No newline at end of file diff --git a/dashboards/Datasources.cdfde b/dashboards/Datasources.cdfde new file mode 100644 index 0000000..c4176eb --- /dev/null +++ b/dashboards/Datasources.cdfde @@ -0,0 +1,597 @@ +{ + "layout": { + "title": "Datasources", + "rows": [ + { + "id": "ff454d8f-0e5a-1c25-6a53-8a402cc3ad76", + "type": "LayoutResourceCode", + "typeDesc": "Resource", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "css", + "type": "Id" + }, + { + "name": "resourceType", + "value": "Css", + "type": "Label" + }, + { + "name": "resourceCode", + "value": ".container {\n margin-top: 18px;\n margin-bottom: 18px;\n margin-left: 22px;\n width: 904px;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n\n.buttonBox button {\n padding: 4px;\n background-color: #F6F7F8;\n border: 1px solid #C0C0C0;\n border-radius: 4px 4px 4px 4px;\n cursor: pointer;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n\n.dataTables_wrapper {\n min-height: 0px;\n}\n\n.tableComponent th {\n background-color: #83BD4D;\n border-bottom: 1px solid #C0C0C0;\n \n}\n\n.tableComponent td {\n background-color: #FFFFFF;\n border-bottom: 1px solid #C0C0C0;\n}\n\n.tableComponent td.string {\n text-align: center;\n} ", + "type": "Resource" + } + ] + }, + { + "id": "634c4d6b-d728-21dc-35e0-33667f20957a", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "height", + "value": "44", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "81dc2467-1d59-91a5-3bd0-29e0a1b37acd", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "634c4d6b-d728-21dc-35e0-33667f20957a", + "properties": [ + { + "name": "name", + "value": "buttonObj", + "type": "Id" + }, + { + "name": "columnSpan", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "buttonBox", + "type": "String" + } + ] + }, + { + "id": "ae88420d-a370-dde3-0926-a7acfe5d3718", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "6099ee89-750d-a850-077b-fe86a1daedbd", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "ae88420d-a370-dde3-0926-a7acfe5d3718", + "properties": [ + { + "name": "name", + "value": "tableObj", + "type": "Id" + }, + { + "name": "columnSpan", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + } + ] + }, + "components": { + "rows": [ + { + "id": "OTHERCOMPONENTS", + "name": "Others", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Others", + "type": "Label" + } + ] + }, + { + "id": "9fd04411-9806-423e-58fb-b8aada55f618", + "type": "ComponentsTable", + "typeDesc": "table Component", + "parent": "OTHERCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "datasourcesTable", + "type": "Id" + }, + { + "name": "expandContainerObject", + "value": "", + "type": "String" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners" + }, + { + "name": "oLanguage", + "value": "", + "type": "JavaScript" + }, + { + "name": "parameters", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "colHeaders", + "value": "[]", + "type": "Array" + }, + { + "name": "colTypes", + "value": "[]", + "type": "colTypesCustom" + }, + { + "name": "colFormats", + "value": "[]", + "type": "Array" + }, + { + "name": "colWidths", + "value": "[]", + "type": "Array" + }, + { + "name": "colSortable", + "value": "[]", + "type": "Array" + }, + { + "name": "expandParameters", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "paginate", + "value": "false", + "type": "Boolean" + }, + { + "name": "filter", + "value": "false", + "type": "Boolean" + }, + { + "name": "info", + "value": "false", + "type": "Boolean" + }, + { + "name": "sort", + "value": "false", + "type": "Boolean" + }, + { + "name": "displayLength", + "value": "", + "type": "Integer" + }, + { + "name": "lengthChange", + "value": "false", + "type": "Boolean" + }, + { + "name": "expandOnClick", + "value": "false", + "type": "Boolean" + }, + { + "name": "colSearchable", + "value": "[]", + "type": "Array" + }, + { + "name": "drawCallback", + "value": "function f() {\n if($(\"td.dataTables_empty\")) {\n $(\"td.dataTables_empty\").text(\"No data source found\");\n } \n}", + "type": "JavaScript" + }, + { + "name": "dataSource", + "value": "listCdaDatasources", + "type": "Datasource" + }, + { + "name": "sortBy", + "value": "[]", + "type": "SortByArray" + }, + { + "name": "sDom", + "value": "", + "type": "JavaScript" + }, + { + "name": "priority", + "value": 5, + "type": "Integer" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer" + }, + { + "name": "paginationType", + "value": "two_button", + "type": "PaginationType" + }, + { + "name": "tableStyle", + "value": "classic", + "type": "TableStyle" + }, + { + "name": "htmlObject", + "value": "${p:tableObj}", + "type": "HtmlObject" + }, + { + "name": "paginateServerside", + "value": "false", + "type": "Boolean" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "postFetch", + "value": "function f(data) {\n if(_.isEmpty(data)) {\n data.metadata = [{\"colIndex\":0,\"colType\":\"String\",\"colName\":\"Catalog\"},{\"colIndex\":1,\"colType\":\"String\",\"colName\":\"Jndi\"}];\n }\n}", + "type": "JavaScript" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "tooltip", + "value": "", + "type": "Html" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray" + }, + { + "name": "clickAction", + "value": "", + "type": "JavaScript" + } + ] + }, + { + "id": "93011eba-c8aa-6a8d-0809-a16569124978", + "type": "ComponentsbuttonComponent", + "typeDesc": "Button Component", + "parent": "OTHERCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "importButton", + "type": "Id" + }, + { + "name": "label", + "value": "Import from Mondrian Catalogs", + "type": "String" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners" + }, + { + "name": "expression", + "value": "function f(){\n \n var successCallback = function (json){\n console.log(\"Success\");\n Dashboards.decrementRunningCalls();\n location.href = Dashboards.getWebAppPath() + \"/content/BTable/datasources\";\n }\n \n var errorCallback = function (json){\n Dashboards.decrementRunningCalls();\n alert(\"An error occurred while creating the data sources!\");\n }\n \n Dashboards.incrementRunningCalls();\n \n BTablePlugin.runEndpoint('BTable' , 'createCdaDatasources', {\n params: {},\n success: successCallback,\n error: errorCallback\n });\n \n}\n", + "type": "JavaScript" + }, + { + "name": "priority", + "value": 5, + "type": "Integer" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer" + }, + { + "name": "buttonStyle", + "value": "classic", + "type": "TableStyle" + }, + { + "name": "htmlObject", + "value": "${p:buttonObj}", + "type": "HtmlObject" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "tooltip", + "value": "", + "type": "Html" + } + ] + } + ] + }, + "datasources": { + "rows": [ + { + "id": "BTABLE_CPKENDPOINTS", + "name": "BTABLE Endpoints", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "BTABLE Endpoints", + "type": "Label" + } + ] + }, + { + "id": "00d58396-845f-b093-9abc-772a31edb487", + "type": "ComponentsBTable_createCdaDatasources_CPKENDPOINT", + "typeDesc": "createCdaDatasources Endpoint", + "parent": "BTABLE_CPKENDPOINTS", + "properties": [ + { + "name": "name", + "value": "createCdaDatasources", + "type": "Id" + } + ], + "meta": "CPK", + "meta_pluginId": "BTable", + "meta_endpoint": "createCdaDatasources" + }, + { + "id": "4dec1d48-1e9d-ef98-c5ef-4b8f0019be90", + "type": "ComponentsBTable_listCdaDatasources_CPKENDPOINT", + "typeDesc": "listCdaDatasources Endpoint", + "parent": "BTABLE_CPKENDPOINTS", + "properties": [ + { + "name": "name", + "value": "listCdaDatasources", + "type": "Id" + } + ], + "meta": "CPK", + "meta_pluginId": "BTable", + "meta_endpoint": "listCdaDatasources" + } + ] + }, + "filename": "/system/BTable/dashboards/Datasources.cdfde" +} \ No newline at end of file diff --git a/dashboards/Datasources.wcdf b/dashboards/Datasources.wcdf new file mode 100644 index 0000000..6665671 --- /dev/null +++ b/dashboards/Datasources.wcdf @@ -0,0 +1,2 @@ + +BTable - Data SourcesBiz Techblueprintfalse \ No newline at end of file diff --git a/dashboards/Datasources_tmp.cdfde b/dashboards/Datasources_tmp.cdfde new file mode 100644 index 0000000..546b15f --- /dev/null +++ b/dashboards/Datasources_tmp.cdfde @@ -0,0 +1,981 @@ +{ + "layout": { + "title": "Datasources", + "rows": [ + { + "id": "ff454d8f-0e5a-1c25-6a53-8a402cc3ad76", + "type": "LayoutResourceCode", + "typeDesc": "Resource", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "css", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "resourceType", + "value": "Css", + "type": "Label", + "description": "Type", + "tooltip": "Resource Type to include", + "order": 19, + "classType": "" + }, + { + "name": "resourceCode", + "value": ".container {\n margin-top: 18px;\n margin-bottom: 18px;\n margin-left: 22px;\n width: 904px;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n\n.buttonBox button {\n padding: 4px;\n background-color: #F6F7F8;\n border: 1px solid #C0C0C0;\n border-radius: 4px 4px 4px 4px;\n cursor: pointer;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n\n.dataTables_wrapper {\n min-height: 0px;\n}\n\n.tableComponent th {\n background-color: #83BD4D;\n border-bottom: 1px solid #C0C0C0;\n \n}\n\n.tableComponent td {\n background-color: #FFFFFF;\n border-bottom: 1px solid #C0C0C0;\n}\n\n.tableComponent td.string {\n text-align: center;\n} ", + "type": "Resource", + "description": "Resource code", + "tooltip": "Resource code to include", + "order": 19, + "classType": "" + } + ] + }, + { + "id": "634c4d6b-d728-21dc-35e0-33667f20957a", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "height", + "value": "44", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "81dc2467-1d59-91a5-3bd0-29e0a1b37acd", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "634c4d6b-d728-21dc-35e0-33667f20957a", + "properties": [ + { + "name": "name", + "value": "buttonObj", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "columnSpan", + "value": "", + "type": "Integer", + "description": "Span size", + "tooltip": "Column span size, numeric. The total must be 24", + "order": 30, + "classType": "" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer", + "description": "Prepend size", + "tooltip": "Prepend size - optional", + "order": 32, + "classType": "" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer", + "description": "Append size", + "tooltip": "Append size - optional", + "order": 33, + "classType": "" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to top", + "tooltip": "Prepend space to the top of the element", + "order": 34, + "classType": "" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to bottom", + "tooltip": "Prepend space to the bottom of the element", + "order": 35, + "classType": "" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean", + "description": "Right border", + "tooltip": "Generates a border between the columns", + "order": 36, + "classType": "" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean", + "description": "Big right border", + "tooltip": "Generates a border between the columns, ", + "order": 37, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "buttonBox", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "ae88420d-a370-dde3-0926-a7acfe5d3718", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "6099ee89-750d-a850-077b-fe86a1daedbd", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "ae88420d-a370-dde3-0926-a7acfe5d3718", + "properties": [ + { + "name": "name", + "value": "tableObj", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "columnSpan", + "value": "", + "type": "Integer", + "description": "Span size", + "tooltip": "Column span size, numeric. The total must be 24", + "order": 30, + "classType": "" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer", + "description": "Prepend size", + "tooltip": "Prepend size - optional", + "order": 32, + "classType": "" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer", + "description": "Append size", + "tooltip": "Append size - optional", + "order": 33, + "classType": "" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to top", + "tooltip": "Prepend space to the top of the element", + "order": 34, + "classType": "" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to bottom", + "tooltip": "Prepend space to the bottom of the element", + "order": 35, + "classType": "" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean", + "description": "Right border", + "tooltip": "Generates a border between the columns", + "order": 36, + "classType": "" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean", + "description": "Big right border", + "tooltip": "Generates a border between the columns, ", + "order": 37, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + } + ] + }, + "components": { + "rows": [ + { + "id": "OTHERCOMPONENTS", + "name": "Others", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Others", + "type": "Label", + "description": "Group", + "tooltip": "Group" + } + ] + }, + { + "id": "9fd04411-9806-423e-58fb-b8aada55f618", + "type": "ComponentsTable", + "typeDesc": "table Component", + "parent": "OTHERCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "datasourcesTable", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "expandContainerObject", + "value": "", + "type": "String", + "description": "Expand container Object", + "tooltip": "Id for container object with expanded row contents", + "order": 1, + "classType": "advanced" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners", + "description": "Listeners", + "tooltip": "Parameters to listen to", + "order": 13, + "classType": "" + }, + { + "name": "oLanguage", + "value": "", + "type": "JavaScript", + "description": "oLanguage", + "tooltip": "oLanguage", + "order": 17, + "classType": "advanced" + }, + { + "name": "parameters", + "value": "[]", + "type": "ValuesArray", + "description": "Parameters", + "tooltip": " Parameters to pass to the component", + "order": 40, + "classType": "" + }, + { + "name": "colHeaders", + "value": "[]", + "type": "Array", + "description": "Column Headers", + "tooltip": "The table column header", + "order": 40, + "classType": "" + }, + { + "name": "colTypes", + "value": "[]", + "type": "colTypesCustom", + "description": "Column Types", + "tooltip": "The table column types", + "order": 40, + "classType": "" + }, + { + "name": "colFormats", + "value": "[]", + "type": "Array", + "description": "Column Formats", + "tooltip": "The table column formats", + "order": 40, + "classType": "advanced" + }, + { + "name": "colWidths", + "value": "[]", + "type": "Array", + "description": "Column Widths", + "tooltip": "The table widths", + "order": 40, + "classType": "advanced" + }, + { + "name": "colSortable", + "value": "[]", + "type": "Array", + "description": "Sortable Column", + "tooltip": "Is the column sortable? Example: [true,false]", + "order": 40, + "classType": "advanced" + }, + { + "name": "expandParameters", + "value": "[]", + "type": "ValuesArray", + "description": "Expand Parameters", + "tooltip": " Expand Parameters - arg is column id, value is parameter name to change with column value", + "order": 40, + "classType": "advanced" + }, + { + "name": "paginate", + "value": "false", + "type": "Boolean", + "description": "Paginate", + "tooltip": "Paginate", + "order": 41, + "classType": "advanced" + }, + { + "name": "filter", + "value": "false", + "type": "Boolean", + "description": "Show Filter", + "tooltip": "Show option", + "order": 41, + "classType": "advanced" + }, + { + "name": "info", + "value": "false", + "type": "Boolean", + "description": "Info Filter", + "tooltip": "Info option", + "order": 41, + "classType": "advanced" + }, + { + "name": "sort", + "value": "false", + "type": "Boolean", + "description": "Sort Data", + "tooltip": "Sort Data", + "order": 41, + "classType": "advanced" + }, + { + "name": "displayLength", + "value": "", + "type": "Integer", + "description": "Page Length", + "tooltip": "The page lengh", + "order": 41, + "classType": "advanced" + }, + { + "name": "lengthChange", + "value": "false", + "type": "Boolean", + "description": "Length Change", + "tooltip": "Allow user to change the displayed size?", + "order": 41, + "classType": "advanced" + }, + { + "name": "expandOnClick", + "value": "false", + "type": "Boolean", + "description": "Expand On Click", + "tooltip": "If true, expand row when clicked and show content from expandContainerObject", + "order": 41, + "classType": "advanced" + }, + { + "name": "colSearchable", + "value": "[]", + "type": "Array", + "description": "Searchable Column", + "tooltip": "Array with the indexes of the columns to search", + "order": 42, + "classType": "advanced" + }, + { + "name": "drawCallback", + "value": "function f() {\n if($(\"td.dataTables_empty\")) {\n $(\"td.dataTables_empty\").text(\"No data source found\");\n } \n}", + "type": "JavaScript", + "description": "Draw Function", + "tooltip": "Custom function to be executed when a page table is rendered", + "order": 42, + "classType": "advanced" + }, + { + "name": "dataSource", + "value": "listCdaDatasources", + "type": "Datasource", + "description": "Datasource", + "tooltip": "DataSource to be used in this selector", + "order": 43, + "classType": "" + }, + { + "name": "sortBy", + "value": "[]", + "type": "SortByArray", + "description": "Sort by", + "tooltip": "Choose the columns where the sorting will default. Example: [[0,asc],[1,desc]]", + "order": 43, + "classType": "advanced" + }, + { + "name": "sDom", + "value": "", + "type": "JavaScript", + "description": "sDom control", + "tooltip": "Configuration of where the controls will be in the table", + "order": 43, + "classType": "advanced" + }, + { + "name": "priority", + "value": 5, + "type": "Integer", + "description": "Priority", + "tooltip": "Priority for component execution component. Lower values have higher priority", + "order": 50, + "classType": "advanced" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer", + "description": "Refresh Period", + "tooltip": "Time interval (in seconds) to refresh the component. If 0 or not set component won't refresh.", + "order": 50, + "classType": "advanced" + }, + { + "name": "paginationType", + "value": "two_button", + "type": "PaginationType", + "description": "Pagination Type", + "tooltip": "Pagination Type", + "order": 56, + "classType": "advanced" + }, + { + "name": "tableStyle", + "value": "classic", + "type": "TableStyle", + "description": "Style", + "tooltip": "Table style", + "order": 56, + "classType": "advanced" + }, + { + "name": "htmlObject", + "value": "${p:tableObj}", + "type": "HtmlObject", + "description": "HtmlObject", + "tooltip": "HtmlObject to prompt", + "order": 90, + "classType": "" + }, + { + "name": "paginateServerside", + "value": "false", + "type": "Boolean", + "description": "Paginate server-side", + "tooltip": "Paginate server-side", + "order": 91, + "classType": "advanced" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean", + "description": "Execute at start", + "tooltip": "Execute at start?", + "order": 91, + "classType": "advanced" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript", + "description": "Pre Execution", + "tooltip": "Function to be executed before the component is updated", + "order": 92, + "classType": "advanced" + }, + { + "name": "postFetch", + "value": "function f(data) {\n if(_.isEmpty(data)) {\n data.metadata = [{\"colIndex\":0,\"colType\":\"String\",\"colName\":\"Catalog\"},{\"colIndex\":1,\"colType\":\"String\",\"colName\":\"Jndi\"}];\n }\n}", + "type": "JavaScript", + "description": "Post Fetch", + "tooltip": "Code executed after this component's data is fetched from the server", + "order": 93, + "classType": "advanced" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript", + "description": "Post Execution", + "tooltip": "Function to be executed after the component is updated", + "order": 93, + "classType": "advanced" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript", + "description": "Pre Change", + "tooltip": "Function to be executed before the component is changed. It's a function of the type function(value){return value}, and can be used for validation", + "order": 94, + "classType": "advanced" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript", + "description": "Post Change", + "tooltip": "Function to be executed after the component is changed. It's a function of the type function(value){...}", + "order": 95, + "classType": "advanced" + }, + { + "name": "tooltip", + "value": "", + "type": "Html", + "description": "Tooltip", + "tooltip": "Tooltip to be displayed on component's mouse hover", + "order": 99, + "classType": "advanced" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray", + "description": "Extra Options", + "tooltip": "Extra Options", + "order": 99, + "classType": "advanced" + }, + { + "name": "clickAction", + "value": "", + "type": "JavaScript", + "description": "clickAction", + "tooltip": "A callback function that is called when the user clicks on a visual element.", + "order": 254, + "classType": "" + } + ] + }, + { + "id": "93011eba-c8aa-6a8d-0809-a16569124978", + "type": "ComponentsbuttonComponent", + "typeDesc": "Button Component", + "parent": "OTHERCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "importButton", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "label", + "value": "Import from Mondrian Catalogs", + "type": "String", + "description": "Label", + "tooltip": "Label to be used", + "order": 9, + "classType": "" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners", + "description": "Listeners", + "tooltip": "Parameters to listen to", + "order": 13, + "classType": "" + }, + { + "name": "expression", + "value": "function f(){\n \n var successCallback = function (json){\n console.log(\"Success\");\n Dashboards.decrementRunningCalls();\n location.href = Dashboards.getWebAppPath() + \"/content/BTable/datasources\";\n }\n \n var errorCallback = function (json){\n Dashboards.decrementRunningCalls();\n alert(\"An error occurred while creating the data sources!\");\n }\n \n Dashboards.incrementRunningCalls();\n \n BTablePlugin.runEndpoint('BTable' , 'createCdaDatasources', {\n params: {},\n success: successCallback,\n error: errorCallback\n });\n \n}\n", + "type": "JavaScript", + "description": "Expression", + "tooltip": "Javascript expression to be evaluate.", + "order": 40, + "classType": "" + }, + { + "name": "priority", + "value": 5, + "type": "Integer", + "description": "Priority", + "tooltip": "Priority for component execution component. Lower values have higher priority", + "order": 50, + "classType": "advanced" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer", + "description": "Refresh Period", + "tooltip": "Time interval (in seconds) to refresh the component. If 0 or not set component won't refresh.", + "order": 50, + "classType": "advanced" + }, + { + "name": "buttonStyle", + "value": "classic", + "type": "TableStyle", + "description": "Style", + "tooltip": "Table style", + "order": 56, + "classType": "advanced" + }, + { + "name": "htmlObject", + "value": "${p:buttonObj}", + "type": "HtmlObject", + "description": "HtmlObject", + "tooltip": "HtmlObject to prompt", + "order": 90, + "classType": "" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean", + "description": "Execute at start", + "tooltip": "Execute at start?", + "order": 91, + "classType": "advanced" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript", + "description": "Pre Execution", + "tooltip": "Function to be executed before the component is updated", + "order": 92, + "classType": "advanced" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript", + "description": "Post Execution", + "tooltip": "Function to be executed after the component is updated", + "order": 93, + "classType": "advanced" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript", + "description": "Pre Change", + "tooltip": "Function to be executed before the component is changed. It's a function of the type function(value){return value}, and can be used for validation", + "order": 94, + "classType": "advanced" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript", + "description": "Post Change", + "tooltip": "Function to be executed after the component is changed. It's a function of the type function(value){...}", + "order": 95, + "classType": "advanced" + }, + { + "name": "tooltip", + "value": "", + "type": "Html", + "description": "Tooltip", + "tooltip": "Tooltip to be displayed on component's mouse hover", + "order": 99, + "classType": "advanced" + } + ] + } + ] + }, + "datasources": { + "rows": [ + { + "id": "BTABLE_CPKENDPOINTS", + "name": "BTABLE Endpoints", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "BTABLE Endpoints", + "type": "Label", + "description": "Group", + "tooltip": "Group" + } + ] + }, + { + "id": "00d58396-845f-b093-9abc-772a31edb487", + "type": "ComponentsBTable_createCdaDatasources_CPKENDPOINT", + "typeDesc": "createCdaDatasources Endpoint", + "parent": "BTABLE_CPKENDPOINTS", + "properties": [ + { + "name": "name", + "value": "createCdaDatasources", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + } + ], + "meta": "CPK", + "meta_pluginId": "BTable", + "meta_endpoint": "createCdaDatasources" + }, + { + "id": "4dec1d48-1e9d-ef98-c5ef-4b8f0019be90", + "type": "ComponentsBTable_listCdaDatasources_CPKENDPOINT", + "typeDesc": "listCdaDatasources Endpoint", + "parent": "BTABLE_CPKENDPOINTS", + "properties": [ + { + "name": "name", + "value": "listCdaDatasources", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + } + ], + "meta": "CPK", + "meta_pluginId": "BTable", + "meta_endpoint": "listCdaDatasources" + } + ] + }, + "filename": "/system/BTable/dashboards/Datasources_tmp.cdfde" +} \ No newline at end of file diff --git a/dashboards/Render.cdfde b/dashboards/Render.cdfde new file mode 100644 index 0000000..401020f --- /dev/null +++ b/dashboards/Render.cdfde @@ -0,0 +1,323 @@ +{ + "layout": { + "title": "Render", + "rows": [ + { + "id": "9eee59a9-0cd1-049c-5042-9ad2db54949d", + "type": "LayoutResourceCode", + "typeDesc": "Resource", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "css", + "type": "Id" + }, + { + "name": "resourceType", + "value": "Css", + "type": "Label" + }, + { + "name": "resourceCode", + "value": ".container {\n margin-top: 20px;\n margin-bottom: 20px;\n margin-left: 30px;\n margin-right: 30px;\n} ", + "type": "Resource" + } + ] + }, + { + "id": "3f42a171-31a3-4b7e-a08c-f8c51511e046", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "BTableHtmlObject", + "type": "Id" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + } + ] + }, + "components": { + "rows": [ + { + "id": "COMMUNITYCOMPONENTS", + "name": "Community Contributions", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Community Contributions", + "type": "Label" + } + ] + }, + { + "id": "e2bd5d67-b81b-34f8-a707-3048a7b7ee92", + "type": "ComponentsBTableComponent", + "typeDesc": "BTable (by Biz Tech)", + "parent": "COMMUNITYCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "BTable", + "type": "Id" + }, + { + "name": "expandContainerObject", + "value": "", + "type": "String" + }, + { + "name": "catalog", + "value": "", + "type": "MondrianCatalog" + }, + { + "name": "jndi", + "value": "", + "type": "Jndi" + }, + { + "name": "cube", + "value": "", + "type": "String" + }, + { + "name": "dimensions", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "measures", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "pivotDimensions", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "filters", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "orderBy", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "measuresOnColumns", + "value": "true", + "type": "Boolean" + }, + { + "name": "nonEmptyRows", + "value": "true", + "type": "Boolean" + }, + { + "name": "nonEmptyColumns", + "value": "true", + "type": "Boolean" + }, + { + "name": "grandTotal", + "value": "false", + "type": "Boolean" + }, + { + "name": "subTotals", + "value": "false", + "type": "Boolean" + }, + { + "name": "pivotGrandTotal", + "value": "false", + "type": "Boolean" + }, + { + "name": "pivotSubTotals", + "value": "false", + "type": "Boolean" + }, + { + "name": "showFilters", + "value": "true", + "type": "Boolean" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners" + }, + { + "name": "oLanguage", + "value": "", + "type": "JavaScript" + }, + { + "name": "expandParameters", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "paginate", + "value": "false", + "type": "Boolean" + }, + { + "name": "filter", + "value": "false", + "type": "Boolean" + }, + { + "name": "info", + "value": "false", + "type": "Boolean" + }, + { + "name": "displayLength", + "value": "", + "type": "Integer" + }, + { + "name": "lengthChange", + "value": "false", + "type": "Boolean" + }, + { + "name": "expandOnClick", + "value": "false", + "type": "Boolean" + }, + { + "name": "colSearchable", + "value": "[]", + "type": "Array" + }, + { + "name": "drawCallback", + "value": "", + "type": "JavaScript" + }, + { + "name": "sDom", + "value": "", + "type": "JavaScript" + }, + { + "name": "priority", + "value": 5, + "type": "Integer" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer" + }, + { + "name": "paginationType", + "value": "two_button", + "type": "PaginationType" + }, + { + "name": "tableStyle", + "value": "classic", + "type": "TableStyle" + }, + { + "name": "htmlObject", + "value": "${p:BTableHtmlObject}", + "type": "HtmlObject" + }, + { + "name": "paginateServerside", + "value": "false", + "type": "Boolean" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean" + }, + { + "name": "preExecution", + "value": "function() {\n var urlQuery = getURLQuery();\n \n var btdefObj = JSON.parse(urlQuery.btdef);\n\n this.catalog = (btdefObj.catalog) ? btdefObj.catalog : \"\";\n this.jndi = (btdefObj.jndi) ? btdefObj.jndi : \"\";\n this.cube = (btdefObj.cube) ? btdefObj.cube : \"\";\n this.dimensions = (btdefObj.dimensions) ? btdefObj.dimensions : [];\n this.measures = (btdefObj.measures) ? btdefObj.measures : [];\n this.pivotDimensions = (btdefObj.pivotDimensions) ? btdefObj.pivotDimensions : [];\n this.filters = (btdefObj.filters) ? btdefObj.filters : [];\n this.measuresOnColumns = (btdefObj.hasOwnProperty('measuresOnColumns')) ? btdefObj.measuresOnColumns : true;\n this.nonEmptyRows = (btdefObj.hasOwnProperty('nonEmptyRows')) ? btdefObj.nonEmptyRows : true;\n this.nonEmptyColumns = (btdefObj.hasOwnProperty('nonEmptyColumns')) ? btdefObj.nonEmptyColumns : true;\n this.grandTotal = (btdefObj.hasOwnProperty('grandTotal')) ? btdefObj.grandTotal : false;\n this.subTotals = (btdefObj.hasOwnProperty('subTotals')) ? btdefObj.subTotals : false;\n\tthis.pivotGrandTotal = (btdefObj.hasOwnProperty('pivotGrandTotal')) ? btdefObj.pivotGrandTotal : false;\n\tthis.pivotSubTotals = (btdefObj.hasOwnProperty('pivotSubTotals')) ? btdefObj.pivotSubTotals : false;\n\tthis.totalsPosition = (btdefObj.hasOwnProperty('totalsPosition')) ? btdefObj.totalsPosition : \"bottom\";\n\tthis.hideSpans = (btdefObj.hasOwnProperty('hideSpans')) ? btdefObj.hideSpans : false;\n \n return true;\n}", + "type": "JavaScript" + }, + { + "name": "postFetch", + "value": "", + "type": "JavaScript" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "tooltip", + "value": "", + "type": "Html" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray" + }, + { + "name": "clickAction", + "value": "", + "type": "JavaScript" + } + ] + } + ] + }, + "datasources": { + "rows": [] + }, + "filename": "/system/BTable/dashboards/Render.cdfde" +} \ No newline at end of file diff --git a/dashboards/Render.wcdf b/dashboards/Render.wcdf new file mode 100644 index 0000000..84afcac --- /dev/null +++ b/dashboards/Render.wcdf @@ -0,0 +1,2 @@ + +BTableBTableBiz Techblueprintfalse \ No newline at end of file diff --git a/dashboards/Sample.cda b/dashboards/Sample.cda new file mode 100644 index 0000000..bd5b4fa --- /dev/null +++ b/dashboards/Sample.cda @@ -0,0 +1,20 @@ + + + + + steel-wheels/analysis/steelwheels.mondrian.xml + SampleData + + + + compact + + + select + NON EMPTY {[Measures].[Sales]} ON COLUMNS, + NON EMPTY Order({[Markets].[All Markets].Children}, [Markets].CurrentMember.Name, ASC) ON ROWS +from [SteelWheelsSales] + + \ No newline at end of file diff --git a/dashboards/Sample.cdfde b/dashboards/Sample.cdfde new file mode 100644 index 0000000..f3b2def --- /dev/null +++ b/dashboards/Sample.cdfde @@ -0,0 +1,912 @@ +{ + "layout": { + "title": "Sample", + "rows": [ + { + "id": "ec601d23-9173-87f5-3540-0ab79251d7d4", + "type": "LayoutResourceCode", + "typeDesc": "Resource", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "css", + "type": "Id" + }, + { + "name": "resourceType", + "value": "Css", + "type": "Label" + }, + { + "name": "resourceCode", + "value": ".container {\n margin-top: 12px;\n margin-bottom: 6px;\n margin-left: 12px;\n margin-right: 12px;\n width: 924px;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n\n#top {\n height: 36px;\n}\n\n.selector {\n padding-top: 2px;\n}\n\n.selector > span {\n display: inline-block;\n vertical-align: top;\n line-height: 28px;\n font-size: 13px;\n font-weight: bold;\n padding-left: 5px;\n padding-right: 3px;\n}\n\n.selector > div {\n vertical-align: top;\n display: inline-block;\n}\n\nselect {\n width: 100px;\n}\n\n.overflow {\n overflow: auto;\n padding-bottom: 6px;\n}\n ", + "type": "Resource" + } + ] + }, + { + "id": "b428a9d7-baf8-feaf-a826-a8a98d0cbf37", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "top", + "type": "Id" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "82cf8216-0f8b-3e92-1f6c-c4baea85f79e", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "b428a9d7-baf8-feaf-a826-a8a98d0cbf37", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "columnSpan", + "value": "8", + "type": "Integer" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "height", + "value": "36", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "da114930-2277-0bd0-0cfa-c662bf5eeda1", + "type": "LayoutHtml", + "typeDesc": "Html", + "parent": "82cf8216-0f8b-3e92-1f6c-c4baea85f79e", + "properties": [ + { + "name": "name", + "value": "title", + "type": "Id" + }, + { + "name": "html", + "value": "

Steel Wheels Sales

", + "type": "Html" + }, + { + "name": "fontSize", + "value": "", + "type": "Integer" + }, + { + "name": "color", + "value": "", + "type": "Color" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "8aded277-9512-5c03-ebf5-fcd10c5d9910", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "b428a9d7-baf8-feaf-a826-a8a98d0cbf37", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id" + }, + { + "name": "columnSpan", + "value": "8", + "type": "Integer" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "selector", + "type": "String" + } + ] + }, + { + "id": "c01d44a1-5eba-133b-85e3-520ccd78f31a", + "type": "LayoutHtml", + "typeDesc": "Html", + "parent": "8aded277-9512-5c03-ebf5-fcd10c5d9910", + "properties": [ + { + "name": "name", + "value": "label", + "type": "Id" + }, + { + "name": "html", + "value": "Market ", + "type": "Html" + }, + { + "name": "fontSize", + "value": "", + "type": "Integer" + }, + { + "name": "color", + "value": "", + "type": "Color" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "c0de0658-eb27-6907-da1f-773672cd0a21", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "8aded277-9512-5c03-ebf5-fcd10c5d9910", + "properties": [ + { + "name": "name", + "value": "selectorObj", + "type": "Id" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "27ad70c2-2755-bc5b-7421-e365c2ea5224", + "type": "LayoutSpace", + "typeDesc": "Space", + "parent": "UnIqEiD", + "properties": [ + { + "name": "height", + "value": "1", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "cssClass", + "value": "", + "type": "String" + } + ] + }, + { + "id": "6097fe9c-997e-f80d-3a3c-3d0e3fb01cdb", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "btableObj", + "type": "Id" + }, + { + "name": "height", + "value": "", + "type": "Integer" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign" + }, + { + "name": "cssClass", + "value": "overflow", + "type": "String" + } + ] + } + ] + }, + "components": { + "rows": [ + { + "id": "GENERIC", + "name": "Generic", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Generic", + "type": "Label" + } + ] + }, + { + "id": "a0490e8d-81a5-2445-3a8d-b93a9fca2d78", + "type": "ComponentsParameter", + "typeDesc": "Simple parameter", + "parent": "GENERIC", + "properties": [ + { + "name": "name", + "value": "territory", + "type": "Id" + }, + { + "name": "propertyValue", + "value": "EMEA", + "type": "String" + }, + { + "name": "parameterViewRole", + "value": "unused", + "type": "parameterViewRoleCustom" + }, + { + "name": "bookmarkable", + "value": "false", + "type": "Boolean" + } + ] + }, + { + "id": "e40d7e41-1132-c3a6-700a-6ddfdd8466f4", + "type": "ComponentsJavascriptParameter", + "typeDesc": "Custom parameter", + "parent": "GENERIC", + "properties": [ + { + "name": "name", + "value": "period", + "type": "Id" + }, + { + "name": "javaScript", + "value": "[\"[Time].[2004].[QTR1].[Jan]\", \"[Time].[2004].[QTR2].[Jun]\"]", + "type": "JavaScript" + }, + { + "name": "parameterViewRole", + "value": "unused", + "type": "parameterViewRoleCustom" + }, + { + "name": "bookmarkable", + "value": "false", + "type": "Boolean" + } + ] + }, + { + "id": "SELECTORS", + "name": "Selects", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Selects", + "type": "Label" + } + ] + }, + { + "id": "6212f3db-4353-58b8-90a4-7bb7ee22806e", + "type": "ComponentsSelect", + "typeDesc": "Select Component", + "parent": "SELECTORS", + "properties": [ + { + "name": "name", + "value": "territorySelector", + "type": "Id" + }, + { + "name": "parameter", + "value": "${p:territory}", + "type": "Parameter" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners" + }, + { + "name": "parameters", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "valueAsId", + "value": "true", + "type": "Boolean" + }, + { + "name": "externalPlugin", + "value": "chosen", + "type": "String" + }, + { + "name": "dataSource", + "value": "territoriesQuery", + "type": "Datasource" + }, + { + "name": "valuesArray", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "priority", + "value": 5, + "type": "Integer" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer" + }, + { + "name": "htmlObject", + "value": "${p:selectorObj}", + "type": "HtmlObject" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "postFetch", + "value": "", + "type": "JavaScript" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "tooltip", + "value": "", + "type": "Html" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray" + } + ] + }, + { + "id": "COMMUNITYCOMPONENTS", + "name": "Community Contributions", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Community Contributions", + "type": "Label" + } + ] + }, + { + "id": "a61bd324-4c55-6b99-f532-1efb2c398eb9", + "type": "ComponentsBTableComponent", + "typeDesc": "BTable (by Biz Tech)", + "parent": "COMMUNITYCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "btable", + "type": "Id" + }, + { + "name": "expandContainerObject", + "value": "", + "type": "String" + }, + { + "name": "catalog", + "value": "steel-wheels/analysis/steelwheels.mondrian.xml", + "type": "MondrianCatalog" + }, + { + "name": "jndi", + "value": "SampleData", + "type": "Jndi" + }, + { + "name": "cube", + "value": "SteelWheelsSales", + "type": "String" + }, + { + "name": "dimensions", + "value": "[[\"[Product].[Line]\",\"\"]]", + "type": "ValuesArray" + }, + { + "name": "measures", + "value": "[[\"[Measures].[Sales]\",\"\"]]", + "type": "ValuesArray" + }, + { + "name": "pivotDimensions", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "filters", + "value": "[[\"[Markets].[Territory]\",\"include:territory\"],[\"[Order Status].[Type]\",\"exclude:[Cancelled]\"],[\"[Time].[Months]\",\"between_un:period\"]]", + "type": "ValuesArray" + }, + { + "name": "orderBy", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "measuresOnColumns", + "value": "true", + "type": "Boolean" + }, + { + "name": "nonEmptyRows", + "value": "true", + "type": "Boolean" + }, + { + "name": "nonEmptyColumns", + "value": "true", + "type": "Boolean" + }, + { + "name": "grandTotal", + "value": "false", + "type": "Boolean" + }, + { + "name": "subTotals", + "value": "false", + "type": "Boolean" + }, + { + "name": "pivotGrandTotal", + "value": "false", + "type": "Boolean" + }, + { + "name": "pivotSubTotals", + "value": "false", + "type": "Boolean" + }, + { + "name": "showFilters", + "value": "true", + "type": "Boolean" + }, + { + "name": "listeners", + "value": "['${p:territory}']", + "type": "Listeners" + }, + { + "name": "oLanguage", + "value": "", + "type": "JavaScript" + }, + { + "name": "expandParameters", + "value": "[]", + "type": "ValuesArray" + }, + { + "name": "paginate", + "value": "false", + "type": "Boolean" + }, + { + "name": "filter", + "value": "false", + "type": "Boolean" + }, + { + "name": "info", + "value": "false", + "type": "Boolean" + }, + { + "name": "displayLength", + "value": "", + "type": "Integer" + }, + { + "name": "lengthChange", + "value": "false", + "type": "Boolean" + }, + { + "name": "expandOnClick", + "value": "false", + "type": "Boolean" + }, + { + "name": "colSearchable", + "value": "[]", + "type": "Array" + }, + { + "name": "drawCallback", + "value": "", + "type": "JavaScript" + }, + { + "name": "sDom", + "value": "", + "type": "JavaScript" + }, + { + "name": "priority", + "value": 5, + "type": "Integer" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer" + }, + { + "name": "paginationType", + "value": "two_button", + "type": "PaginationType" + }, + { + "name": "tableStyle", + "value": "classic", + "type": "TableStyle" + }, + { + "name": "htmlObject", + "value": "${p:btableObj}", + "type": "HtmlObject" + }, + { + "name": "paginateServerside", + "value": "false", + "type": "Boolean" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "postFetch", + "value": "", + "type": "JavaScript" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript" + }, + { + "name": "tooltip", + "value": "", + "type": "Html" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray" + }, + { + "name": "clickAction", + "value": "", + "type": "JavaScript" + } + ] + } + ] + }, + "datasources": { + "rows": [ + { + "id": "MDX", + "name": "MDX Queries", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "MDX Queries", + "type": "Label" + } + ] + }, + { + "id": "357acfbe-f8b4-2da3-ce21-7893378adee5", + "type": "Componentsmdx_mondrianJndi", + "typeDesc": "mdx over mondrianJndi", + "parent": "MDX", + "properties": [ + { + "name": "name", + "value": "territoriesQuery", + "type": "Id" + }, + { + "name": "access", + "value": "public", + "type": "Access" + }, + { + "name": "jndi", + "value": "SampleData", + "type": "Jndi" + }, + { + "name": "catalog", + "value": "steel-wheels/analysis/steelwheels.mondrian.xml", + "type": "MondrianCatalog" + }, + { + "name": "query", + "value": "select \n NON EMPTY {[Measures].[Sales]} ON COLUMNS,\n NON EMPTY Order({[Markets].[All Markets].Children}, [Markets].CurrentMember.Name, ASC) ON ROWS\nfrom [SteelWheelsSales]", + "type": "SqlQuery" + }, + { + "name": "parameters", + "value": "[]", + "type": "CdaParameters" + }, + { + "name": "output", + "value": "[]", + "type": "IndexArray" + }, + { + "name": "outputMode", + "value": "include", + "type": "OutputMode" + }, + { + "name": "cdacolumns", + "value": "[]", + "type": "CdaColumnsArray" + }, + { + "name": "cdacalculatedcolumns", + "value": "[]", + "type": "CdaCalculatedColumnsArray" + }, + { + "name": "bandedMode", + "value": "compact", + "type": "BandedMode" + }, + { + "name": "cacheDuration", + "value": 3600, + "type": "Integer" + }, + { + "name": "cache", + "value": "true", + "type": "Boolean" + } + ], + "meta": "CDA", + "meta_conntype": "mondrian.jndi", + "meta_datype": "mdx" + } + ] + }, + "filename": "/system/BTable/dashboards/Sample.cdfde" +} \ No newline at end of file diff --git a/dashboards/Sample.wcdf b/dashboards/Sample.wcdf new file mode 100644 index 0000000..d76dd17 --- /dev/null +++ b/dashboards/Sample.wcdf @@ -0,0 +1,2 @@ + +BTable - SampleBiz Techblueprintfalse \ No newline at end of file diff --git a/dashboards/Sample_tmp.cda b/dashboards/Sample_tmp.cda new file mode 100644 index 0000000..bd5b4fa --- /dev/null +++ b/dashboards/Sample_tmp.cda @@ -0,0 +1,20 @@ + + + + + steel-wheels/analysis/steelwheels.mondrian.xml + SampleData + + + + compact + + + select + NON EMPTY {[Measures].[Sales]} ON COLUMNS, + NON EMPTY Order({[Markets].[All Markets].Children}, [Markets].CurrentMember.Name, ASC) ON ROWS +from [SteelWheelsSales] + + \ No newline at end of file diff --git a/dashboards/Sample_tmp.cdfde b/dashboards/Sample_tmp.cdfde new file mode 100644 index 0000000..03a9476 --- /dev/null +++ b/dashboards/Sample_tmp.cdfde @@ -0,0 +1,1500 @@ +{ + "layout": { + "title": "Sample", + "rows": [ + { + "id": "ec601d23-9173-87f5-3540-0ab79251d7d4", + "type": "LayoutResourceCode", + "typeDesc": "Resource", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "css", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "resourceType", + "value": "Css", + "type": "Label", + "description": "Type", + "tooltip": "Resource Type to include", + "order": 19, + "classType": "" + }, + { + "name": "resourceCode", + "value": ".container {\n margin-top: 12px;\n margin-bottom: 6px;\n margin-left: 12px;\n margin-right: 12px;\n width: 924px;\n font-family: Arial, sans-serif;\n font-size: 12px;\n}\n\n#top {\n height: 36px;\n}\n\n.selector {\n padding-top: 2px;\n}\n\n.selector > span {\n display: inline-block;\n vertical-align: top;\n line-height: 28px;\n font-size: 13px;\n font-weight: bold;\n padding-left: 5px;\n padding-right: 3px;\n}\n\n.selector > div {\n vertical-align: top;\n display: inline-block;\n}\n\nselect {\n width: 100px;\n}\n\n.overflow {\n overflow: auto;\n padding-bottom: 6px;\n}\n ", + "type": "Resource", + "description": "Resource code", + "tooltip": "Resource code to include", + "order": 19, + "classType": "" + } + ] + }, + { + "id": "b428a9d7-baf8-feaf-a826-a8a98d0cbf37", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "top", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "82cf8216-0f8b-3e92-1f6c-c4baea85f79e", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "b428a9d7-baf8-feaf-a826-a8a98d0cbf37", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "columnSpan", + "value": "8", + "type": "Integer", + "description": "Span size", + "tooltip": "Column span size, numeric. The total must be 24", + "order": 30, + "classType": "" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer", + "description": "Prepend size", + "tooltip": "Prepend size - optional", + "order": 32, + "classType": "" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer", + "description": "Append size", + "tooltip": "Append size - optional", + "order": 33, + "classType": "" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to top", + "tooltip": "Prepend space to the top of the element", + "order": 34, + "classType": "" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to bottom", + "tooltip": "Prepend space to the bottom of the element", + "order": 35, + "classType": "" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean", + "description": "Right border", + "tooltip": "Generates a border between the columns", + "order": 36, + "classType": "" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean", + "description": "Big right border", + "tooltip": "Generates a border between the columns, ", + "order": 37, + "classType": "" + }, + { + "name": "height", + "value": "36", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "da114930-2277-0bd0-0cfa-c662bf5eeda1", + "type": "LayoutHtml", + "typeDesc": "Html", + "parent": "82cf8216-0f8b-3e92-1f6c-c4baea85f79e", + "properties": [ + { + "name": "name", + "value": "title", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "html", + "value": "

Steel Wheels Sales

", + "type": "Html", + "description": "HTML", + "tooltip": "Html code to be added", + "order": 15, + "classType": "" + }, + { + "name": "fontSize", + "value": "", + "type": "Integer", + "description": "Font Size", + "tooltip": "Font size, in pixels ", + "order": 49, + "classType": "advanced" + }, + { + "name": "color", + "value": "", + "type": "Color", + "description": "Color", + "tooltip": "Element color", + "order": 55, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "8aded277-9512-5c03-ebf5-fcd10c5d9910", + "type": "LayoutColumn", + "typeDesc": "Column", + "parent": "b428a9d7-baf8-feaf-a826-a8a98d0cbf37", + "properties": [ + { + "name": "name", + "value": "", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "columnSpan", + "value": "8", + "type": "Integer", + "description": "Span size", + "tooltip": "Column span size, numeric. The total must be 24", + "order": 30, + "classType": "" + }, + { + "name": "columnPrepend", + "value": "", + "type": "Integer", + "description": "Prepend size", + "tooltip": "Prepend size - optional", + "order": 32, + "classType": "" + }, + { + "name": "columnAppend", + "value": "", + "type": "Integer", + "description": "Append size", + "tooltip": "Append size - optional", + "order": 33, + "classType": "" + }, + { + "name": "columnPrependTop", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to top", + "tooltip": "Prepend space to the top of the element", + "order": 34, + "classType": "" + }, + { + "name": "columnAppendBottom", + "value": "false", + "type": "Boolean", + "description": "Prepend gutter to bottom", + "tooltip": "Prepend space to the bottom of the element", + "order": 35, + "classType": "" + }, + { + "name": "columnBorder", + "value": "false", + "type": "Boolean", + "description": "Right border", + "tooltip": "Generates a border between the columns", + "order": 36, + "classType": "" + }, + { + "name": "columnBigBorder", + "value": "false", + "type": "Boolean", + "description": "Big right border", + "tooltip": "Generates a border between the columns, ", + "order": 37, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "selector", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "c01d44a1-5eba-133b-85e3-520ccd78f31a", + "type": "LayoutHtml", + "typeDesc": "Html", + "parent": "8aded277-9512-5c03-ebf5-fcd10c5d9910", + "properties": [ + { + "name": "name", + "value": "label", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "html", + "value": "Market ", + "type": "Html", + "description": "HTML", + "tooltip": "Html code to be added", + "order": 15, + "classType": "" + }, + { + "name": "fontSize", + "value": "", + "type": "Integer", + "description": "Font Size", + "tooltip": "Font size, in pixels ", + "order": 49, + "classType": "advanced" + }, + { + "name": "color", + "value": "", + "type": "Color", + "description": "Color", + "tooltip": "Element color", + "order": 55, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "c0de0658-eb27-6907-da1f-773672cd0a21", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "8aded277-9512-5c03-ebf5-fcd10c5d9910", + "properties": [ + { + "name": "name", + "value": "selectorObj", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "27ad70c2-2755-bc5b-7421-e365c2ea5224", + "type": "LayoutSpace", + "typeDesc": "Space", + "parent": "UnIqEiD", + "properties": [ + { + "name": "height", + "value": "1", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "cssClass", + "value": "", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + }, + { + "id": "6097fe9c-997e-f80d-3a3c-3d0e3fb01cdb", + "type": "LayoutRow", + "typeDesc": "Row", + "parent": "UnIqEiD", + "properties": [ + { + "name": "name", + "value": "btableObj", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "height", + "value": "", + "type": "Integer", + "description": "Height", + "tooltip": "Element height, in pixels ", + "order": 50, + "classType": "" + }, + { + "name": "backgroundColor", + "value": "", + "type": "Color", + "description": "BackgroundColor", + "tooltip": "Element background color", + "order": 56, + "classType": "advanced" + }, + { + "name": "roundCorners", + "value": "", + "type": "RoundCorners", + "description": "Corners", + "tooltip": "Corners type", + "order": 70, + "classType": "" + }, + { + "name": "textAlign", + "value": "", + "type": "TextAlign", + "description": "Text Align", + "tooltip": "Text Align", + "order": 75, + "classType": "" + }, + { + "name": "cssClass", + "value": "overflow", + "type": "String", + "description": "Css Class", + "tooltip": "Css Class to be used when this element is rendered", + "order": 80, + "classType": "" + } + ] + } + ] + }, + "components": { + "rows": [ + { + "id": "GENERIC", + "name": "Generic", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Generic", + "type": "Label", + "description": "Group", + "tooltip": "Group" + } + ] + }, + { + "id": "a0490e8d-81a5-2445-3a8d-b93a9fca2d78", + "type": "ComponentsParameter", + "typeDesc": "Simple parameter", + "parent": "GENERIC", + "properties": [ + { + "name": "name", + "value": "territory", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "propertyValue", + "value": "EMEA", + "type": "String", + "description": "Property value", + "tooltip": "Property value", + "order": 20, + "classType": "" + }, + { + "name": "parameterViewRole", + "value": "unused", + "type": "parameterViewRoleCustom", + "description": "Role in View", + "tooltip": "How should this parameter be handled when saving a view?", + "order": 88, + "classType": "advanced" + }, + { + "name": "bookmarkable", + "value": "false", + "type": "Boolean", + "description": "Bookmarkable", + "tooltip": "Is this parameter persisted with bookmarks/links?", + "order": 91, + "classType": "" + } + ] + }, + { + "id": "e40d7e41-1132-c3a6-700a-6ddfdd8466f4", + "type": "ComponentsJavascriptParameter", + "typeDesc": "Custom parameter", + "parent": "GENERIC", + "properties": [ + { + "name": "name", + "value": "period", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "javaScript", + "value": "[\"[Time].[2004].[QTR1].[Jan]\", \"[Time].[2004].[QTR2].[Jun]\"]", + "type": "JavaScript", + "description": "Javascript code ", + "tooltip": "JavaScript code to be included", + "order": 17, + "classType": "" + }, + { + "name": "parameterViewRole", + "value": "unused", + "type": "parameterViewRoleCustom", + "description": "Role in View", + "tooltip": "How should this parameter be handled when saving a view?", + "order": 88, + "classType": "advanced" + }, + { + "name": "bookmarkable", + "value": "false", + "type": "Boolean", + "description": "Bookmarkable", + "tooltip": "Is this parameter persisted with bookmarks/links?", + "order": 91, + "classType": "" + } + ] + }, + { + "id": "SELECTORS", + "name": "Selects", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Selects", + "type": "Label", + "description": "Group", + "tooltip": "Group" + } + ] + }, + { + "id": "6212f3db-4353-58b8-90a4-7bb7ee22806e", + "type": "ComponentsSelect", + "typeDesc": "Select Component", + "parent": "SELECTORS", + "properties": [ + { + "name": "name", + "value": "territorySelector", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "parameter", + "value": "${p:territory}", + "type": "Parameter", + "description": "Parameter", + "tooltip": "Parameter to prompt", + "order": 12, + "classType": "" + }, + { + "name": "listeners", + "value": "[]", + "type": "Listeners", + "description": "Listeners", + "tooltip": "Parameters to listen to", + "order": 13, + "classType": "" + }, + { + "name": "parameters", + "value": "[]", + "type": "ValuesArray", + "description": "Parameters", + "tooltip": " Parameters to pass to the component", + "order": 40, + "classType": "" + }, + { + "name": "valueAsId", + "value": "true", + "type": "Boolean", + "description": "Value as id", + "tooltip": "If false, uses the first column of the dataset as id. If true, Use the value as the id", + "order": 41, + "classType": "" + }, + { + "name": "externalPlugin", + "value": "chosen", + "type": "String", + "description": "jQuery Plugin", + "tooltip": "chosen: uses chosen.jquery.js to render select tags", + "order": 41, + "classType": "" + }, + { + "name": "dataSource", + "value": "territoriesQuery", + "type": "Datasource", + "description": "Datasource", + "tooltip": "DataSource to be used in this selector", + "order": 43, + "classType": "" + }, + { + "name": "valuesArray", + "value": "[]", + "type": "ValuesArray", + "description": "Values array", + "tooltip": "Array to be used ", + "order": 44, + "classType": "" + }, + { + "name": "priority", + "value": 5, + "type": "Integer", + "description": "Priority", + "tooltip": "Priority for component execution component. Lower values have higher priority", + "order": 50, + "classType": "advanced" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer", + "description": "Refresh Period", + "tooltip": "Time interval (in seconds) to refresh the component. If 0 or not set component won't refresh.", + "order": 50, + "classType": "advanced" + }, + { + "name": "htmlObject", + "value": "${p:selectorObj}", + "type": "HtmlObject", + "description": "HtmlObject", + "tooltip": "HtmlObject to prompt", + "order": 90, + "classType": "" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean", + "description": "Execute at start", + "tooltip": "Execute at start?", + "order": 91, + "classType": "advanced" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript", + "description": "Pre Execution", + "tooltip": "Function to be executed before the component is updated", + "order": 92, + "classType": "advanced" + }, + { + "name": "postFetch", + "value": "", + "type": "JavaScript", + "description": "Post Fetch", + "tooltip": "Code executed after this component's data is fetched from the server", + "order": 93, + "classType": "advanced" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript", + "description": "Post Execution", + "tooltip": "Function to be executed after the component is updated", + "order": 93, + "classType": "advanced" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript", + "description": "Pre Change", + "tooltip": "Function to be executed before the component is changed. It's a function of the type function(value){return value}, and can be used for validation", + "order": 94, + "classType": "advanced" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript", + "description": "Post Change", + "tooltip": "Function to be executed after the component is changed. It's a function of the type function(value){...}", + "order": 95, + "classType": "advanced" + }, + { + "name": "tooltip", + "value": "", + "type": "Html", + "description": "Tooltip", + "tooltip": "Tooltip to be displayed on component's mouse hover", + "order": 99, + "classType": "advanced" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray", + "description": "Extra Options", + "tooltip": "Extra Options", + "order": 99, + "classType": "advanced" + } + ] + }, + { + "id": "COMMUNITYCOMPONENTS", + "name": "Community Contributions", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "Community Contributions", + "type": "Label", + "description": "Group", + "tooltip": "Group" + } + ] + }, + { + "id": "a61bd324-4c55-6b99-f532-1efb2c398eb9", + "type": "ComponentsBTableComponent", + "typeDesc": "BTable (by Biz Tech)", + "parent": "COMMUNITYCOMPONENTS", + "properties": [ + { + "name": "name", + "value": "btable", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "expandContainerObject", + "value": "", + "type": "String", + "description": "Expand container Object", + "tooltip": "Id for container object with expanded row contents", + "order": 1, + "classType": "advanced" + }, + { + "name": "catalog", + "value": "steel-wheels/analysis/steelwheels.mondrian.xml", + "type": "MondrianCatalog", + "description": "Catalog", + "tooltip": "Catalog", + "order": 10, + "classType": "" + }, + { + "name": "jndi", + "value": "SampleData", + "type": "Jndi", + "description": "Jndi", + "tooltip": "Jndi", + "order": 10, + "classType": "" + }, + { + "name": "cube", + "value": "SteelWheelsSales", + "type": "String", + "description": "Cube", + "tooltip": "Cube", + "order": 10, + "classType": "" + }, + { + "name": "dimensions", + "value": "[[\"[Product].[Line]\",\"\"]]", + "type": "ValuesArray", + "description": "Dimensions", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "measures", + "value": "[[\"[Measures].[Sales]\",\"\"]]", + "type": "ValuesArray", + "description": "Measures", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "pivotDimensions", + "value": "[]", + "type": "ValuesArray", + "description": "Pivot Dimensions", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "filters", + "value": "[[\"[Markets].[Territory]\",\"include:territory\"],[\"[Order Status].[Type]\",\"exclude:[Cancelled]\"],[\"[Time].[Months]\",\"between_un:period\"]]", + "type": "ValuesArray", + "description": "Filters", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "orderBy", + "value": "[]", + "type": "ValuesArray", + "description": "Order By", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "measuresOnColumns", + "value": "true", + "type": "Boolean", + "description": "Measures on Columns", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "nonEmptyRows", + "value": "true", + "type": "Boolean", + "description": "Non Empty Rows", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "nonEmptyColumns", + "value": "true", + "type": "Boolean", + "description": "Non Empty Columns", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "grandTotal", + "value": "false", + "type": "Boolean", + "description": "Grand Total on Dimensions", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "subTotals", + "value": "false", + "type": "Boolean", + "description": "Subtotals on Dimensions", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "pivotGrandTotal", + "value": "false", + "type": "Boolean", + "description": "Grand Total on Pivot", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "pivotSubTotals", + "value": "false", + "type": "Boolean", + "description": "Subtotals on Pivot", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "showFilters", + "value": "true", + "type": "Boolean", + "description": "Show Applied Filters and Sorts", + "tooltip": "", + "order": 10, + "classType": "" + }, + { + "name": "listeners", + "value": "['${p:territory}']", + "type": "Listeners", + "description": "Listeners", + "tooltip": "Parameters to listen to", + "order": 13, + "classType": "" + }, + { + "name": "oLanguage", + "value": "", + "type": "JavaScript", + "description": "oLanguage", + "tooltip": "oLanguage", + "order": 17, + "classType": "advanced" + }, + { + "name": "expandParameters", + "value": "[]", + "type": "ValuesArray", + "description": "Expand Parameters", + "tooltip": " Expand Parameters - arg is column id, value is parameter name to change with column value", + "order": 40, + "classType": "advanced" + }, + { + "name": "paginate", + "value": "false", + "type": "Boolean", + "description": "Paginate", + "tooltip": "Paginate", + "order": 41, + "classType": "advanced" + }, + { + "name": "filter", + "value": "false", + "type": "Boolean", + "description": "Show Filter", + "tooltip": "Show option", + "order": 41, + "classType": "advanced" + }, + { + "name": "info", + "value": "false", + "type": "Boolean", + "description": "Info Filter", + "tooltip": "Info option", + "order": 41, + "classType": "advanced" + }, + { + "name": "displayLength", + "value": "", + "type": "Integer", + "description": "Page Length", + "tooltip": "The page lengh", + "order": 41, + "classType": "advanced" + }, + { + "name": "lengthChange", + "value": "false", + "type": "Boolean", + "description": "Length Change", + "tooltip": "Allow user to change the displayed size?", + "order": 41, + "classType": "advanced" + }, + { + "name": "expandOnClick", + "value": "false", + "type": "Boolean", + "description": "Expand On Click", + "tooltip": "If true, expand row when clicked and show content from expandContainerObject", + "order": 41, + "classType": "advanced" + }, + { + "name": "colSearchable", + "value": "[]", + "type": "Array", + "description": "Searchable Column", + "tooltip": "Array with the indexes of the columns to search", + "order": 42, + "classType": "advanced" + }, + { + "name": "drawCallback", + "value": "", + "type": "JavaScript", + "description": "Draw Function", + "tooltip": "Custom function to be executed when a page table is rendered", + "order": 42, + "classType": "advanced" + }, + { + "name": "sDom", + "value": "", + "type": "JavaScript", + "description": "sDom control", + "tooltip": "Configuration of where the controls will be in the table", + "order": 43, + "classType": "advanced" + }, + { + "name": "priority", + "value": 5, + "type": "Integer", + "description": "Priority", + "tooltip": "Priority for component execution component. Lower values have higher priority", + "order": 50, + "classType": "advanced" + }, + { + "name": "refreshPeriod", + "value": "", + "type": "Integer", + "description": "Refresh Period", + "tooltip": "Time interval (in seconds) to refresh the component. If 0 or not set component won't refresh.", + "order": 50, + "classType": "advanced" + }, + { + "name": "paginationType", + "value": "two_button", + "type": "PaginationType", + "description": "Pagination Type", + "tooltip": "Pagination Type", + "order": 56, + "classType": "advanced" + }, + { + "name": "tableStyle", + "value": "classic", + "type": "TableStyle", + "description": "Style", + "tooltip": "Table style", + "order": 56, + "classType": "advanced" + }, + { + "name": "htmlObject", + "value": "${p:btableObj}", + "type": "HtmlObject", + "description": "HtmlObject", + "tooltip": "HtmlObject to prompt", + "order": 90, + "classType": "" + }, + { + "name": "paginateServerside", + "value": "false", + "type": "Boolean", + "description": "Paginate server-side", + "tooltip": "Paginate server-side", + "order": 91, + "classType": "advanced" + }, + { + "name": "executeAtStart", + "value": "true", + "type": "Boolean", + "description": "Execute at start", + "tooltip": "Execute at start?", + "order": 91, + "classType": "advanced" + }, + { + "name": "preExecution", + "value": "", + "type": "JavaScript", + "description": "Pre Execution", + "tooltip": "Function to be executed before the component is updated", + "order": 92, + "classType": "advanced" + }, + { + "name": "postFetch", + "value": "", + "type": "JavaScript", + "description": "Post Fetch", + "tooltip": "Code executed after this component's data is fetched from the server", + "order": 93, + "classType": "advanced" + }, + { + "name": "postExecution", + "value": "", + "type": "JavaScript", + "description": "Post Execution", + "tooltip": "Function to be executed after the component is updated", + "order": 93, + "classType": "advanced" + }, + { + "name": "preChange", + "value": "", + "type": "JavaScript", + "description": "Pre Change", + "tooltip": "Function to be executed before the component is changed. It's a function of the type function(value){return value}, and can be used for validation", + "order": 94, + "classType": "advanced" + }, + { + "name": "postChange", + "value": "", + "type": "JavaScript", + "description": "Post Change", + "tooltip": "Function to be executed after the component is changed. It's a function of the type function(value){...}", + "order": 95, + "classType": "advanced" + }, + { + "name": "tooltip", + "value": "", + "type": "Html", + "description": "Tooltip", + "tooltip": "Tooltip to be displayed on component's mouse hover", + "order": 99, + "classType": "advanced" + }, + { + "name": "extraOptions", + "value": "[]", + "type": "OptionArray", + "description": "Extra Options", + "tooltip": "Extra Options", + "order": 99, + "classType": "advanced" + }, + { + "name": "clickAction", + "value": "", + "type": "JavaScript", + "description": "clickAction", + "tooltip": "A callback function that is called when the user clicks on a visual element.", + "order": 254, + "classType": "" + } + ] + } + ] + }, + "datasources": { + "rows": [ + { + "id": "MDX", + "name": "MDX Queries", + "type": "Label", + "typeDesc": "Group", + "parent": "UnIqEiD", + "properties": [ + { + "name": "Group", + "value": "MDX Queries", + "type": "Label", + "description": "Group", + "tooltip": "Group" + } + ] + }, + { + "id": "357acfbe-f8b4-2da3-ce21-7893378adee5", + "type": "Componentsmdx_mondrianJndi", + "typeDesc": "mdx over mondrianJndi", + "parent": "MDX", + "properties": [ + { + "name": "name", + "value": "territoriesQuery", + "type": "Id", + "description": "Name", + "tooltip": "Name", + "order": 5, + "classType": "" + }, + { + "name": "access", + "value": "public", + "type": "Access", + "description": "Access Level", + "tooltip": "The Access Level (Scope) for this data access", + "order": 11, + "classType": "" + }, + { + "name": "jndi", + "value": "SampleData", + "type": "Jndi", + "description": "Jndi", + "tooltip": "JNDI string for the desired connection", + "order": 21, + "classType": "" + }, + { + "name": "catalog", + "value": "steel-wheels/analysis/steelwheels.mondrian.xml", + "type": "MondrianCatalog", + "description": "Mondrian schema", + "tooltip": "Mondrian schema location", + "order": 22, + "classType": "" + }, + { + "name": "query", + "value": "select \n NON EMPTY {[Measures].[Sales]} ON COLUMNS,\n NON EMPTY Order({[Markets].[All Markets].Children}, [Markets].CurrentMember.Name, ASC) ON ROWS\nfrom [SteelWheelsSales]", + "type": "SqlQuery", + "description": "Query", + "tooltip": "Query to be executed in the selected datasource", + "order": 25, + "classType": "" + }, + { + "name": "parameters", + "value": "[]", + "type": "CdaParameters", + "description": "Parameters", + "tooltip": "Parameters to be sent to the xaction", + "order": 28, + "classType": "" + }, + { + "name": "output", + "value": "[]", + "type": "IndexArray", + "description": "Output Options", + "tooltip": "Output options for this data access", + "order": 40, + "classType": "" + }, + { + "name": "outputMode", + "value": "include", + "type": "OutputMode", + "description": "Output Mode", + "tooltip": "Whether the output columns refer to columns that should be Included or Excluded from the final output", + "order": 40, + "classType": "" + }, + { + "name": "cdacolumns", + "value": "[]", + "type": "CdaColumnsArray", + "description": "Columns", + "tooltip": "Column Configuration", + "order": 40, + "classType": "" + }, + { + "name": "cdacalculatedcolumns", + "value": "[]", + "type": "CdaCalculatedColumnsArray", + "description": "Calculated Columns", + "tooltip": "Calculated Columns", + "order": 40, + "classType": "" + }, + { + "name": "bandedMode", + "value": "compact", + "type": "BandedMode", + "description": "Banded Mode", + "tooltip": "Banded Mode", + "order": 40, + "classType": "" + }, + { + "name": "cacheDuration", + "value": 3600, + "type": "Integer", + "description": "Cache Duration", + "tooltip": "Cache Duration, in seconds", + "order": 50, + "classType": "" + }, + { + "name": "cache", + "value": "true", + "type": "Boolean", + "description": "Cache", + "tooltip": "Is this data access's output supposed to be cached?", + "order": 91, + "classType": "" + } + ], + "meta": "CDA", + "meta_conntype": "mondrian.jndi", + "meta_datype": "mdx" + } + ] + }, + "filename": "/system/BTable/dashboards/Sample_tmp.cdfde" +} \ No newline at end of file diff --git a/endpoints/kettle/_createCdaDatasources.ktr b/endpoints/kettle/_createCdaDatasources.ktr new file mode 100644 index 0000000..69b4ff5 --- /dev/null +++ b/endpoints/kettle/_createCdaDatasources.ktr @@ -0,0 +1,314 @@ + + + + _createCdaDatasources + Create CDA datasources for BTable, reading catalogs in /system/olap/datasources.xml + + + Normal + 0 + / + + + btable.datasources.dir + ${Internal.Transformation.Filename.Directory}/../../resources/datasources + + + + + + + + + + +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDTRANSNAMEYTRANSNAMESTATUSYSTATUSLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSSTARTDATEYSTARTDATEENDDATEYENDDATELOGDATEYLOGDATEDEPDATEYDEPDATEREPLAYDATEYREPLAYDATELOG_FIELDYLOG_FIELD + + +
+ + +ID_BATCHYID_BATCHSEQ_NRYSEQ_NRLOGDATEYLOGDATETRANSNAMEYTRANSNAMESTEPNAMEYSTEPNAMESTEP_COPYYSTEP_COPYLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSINPUT_BUFFER_ROWSYINPUT_BUFFER_ROWSOUTPUT_BUFFER_ROWSYOUTPUT_BUFFER_ROWS + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATELOGGING_OBJECT_TYPEYLOGGING_OBJECT_TYPEOBJECT_NAMEYOBJECT_NAMEOBJECT_COPYYOBJECT_COPYREPOSITORY_DIRECTORYYREPOSITORY_DIRECTORYFILENAMEYFILENAMEOBJECT_IDYOBJECT_IDOBJECT_REVISIONYOBJECT_REVISIONPARENT_CHANNEL_IDYPARENT_CHANNEL_IDROOT_CHANNEL_IDYROOT_CHANNEL_ID + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATETRANSNAMEYTRANSNAMESTEPNAMEYSTEPNAMESTEP_COPYYSTEP_COPYLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSLOG_FIELDNLOG_FIELD + + + +
+ + 0.0 + 0.0 + + 10000 + 50 + 50 + N + Y + 50000 + Y + + N + 1000 + 100 + + + + + + + + + - + 2013/07/04 18:48:57.073 + - + 2013/07/04 18:48:57.073 + + + + + Get catalogs from datasources.xmlCreate CDA filename and XML for each datasourceY Create CDA filename and XML for each datasourceWrite CDA filesY + + Create CDA filename and XML for each datasource + ScriptValueMod + + Y + 1 + + none + + + N + 9 + 0 + Script 1 + var Jndi = ""; + +var properties = DataSourceInfo.split(";"); +for(i = 0; i < properties.length; i++) { + var parts = properties[i].split("="); + if(parts[0] == "DataSource") + Jndi = parts[1]; +} + +var Catalog = replace(Definition, "solution:", ""); + +var Filename = getVariable("btable.datasources.dir", "") + "/" + Jndi + "_" + replace(replace(Catalog, "/", "_"), ".xml", ""); + +var Xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><CDADescriptor><DataSources>" + +"<Connection id=\"BTableQuery\" type=\"mondrian.jndi\">" + +"<Catalog>" + Catalog + "</Catalog><Jndi>" + Jndi + "</Jndi></Connection></DataSources>" + +"<DataAccess access=\"public\" cache=\"true\" cacheDuration=\"3600\" " + +"connection=\"BTableQuery\" id=\"BTableQuery\" type=\"mdx\"><BandedMode>classic</BandedMode>" + +"<Columns/><Parameters><Parameter default=\"\" name=\"mdxQuery\" type=\"String\"/></Parameters>" + +"<Query>${mdxQuery}</Query></DataAccess></CDADescriptor>"; + + + + Jndi + Jndi + String + -1 + -1 + N + Catalog + Schema + String + -1 + -1 + N + Filename + Filename + String + -1 + -1 + N + Xml + Xml + String + -1 + -1 + N + + + 495 + 155 + Y + + + + + Get catalogs from datasources.xml + getXMLData + + Y + 1 + + none + + + N + + N + N + N + N + N + N + N + N + Y + + UTF-8 + + ${Internal.Transformation.Filename.Directory}/../../../olap + datasources.xml + + N + N + + + + Catalog + @name + attribut + valueof + String + + + + + -1 + -1 + none + N + + + DataSourceInfo + DataSourceInfo + node + valueof + String + + + + + -1 + -1 + none + N + + + Definition + Definition + node + valueof + String + + + + + -1 + -1 + none + N + + + 0 + /DataSources/DataSource/Catalogs/Catalog + N + N + + + + + + + + + + + + + 191 + 155 + Y + + + + + Write CDA files + TextFileOutput + + Y + 1 + + none + + + ; + + N + N +
N
+
N
+ DOS + None + + + Y + Filename + Y + + file + N + N + Y + cda + N + N + N + N + N + N + + N + N + N + 0 + + + + Xml + String + + + + + + none + -1 + -1 + + + + + 737 + 155 + Y + +
+ + + + + + N + diff --git a/endpoints/kettle/createCdaDatasources.kjb b/endpoints/kettle/createCdaDatasources.kjb new file mode 100644 index 0000000..5521308 --- /dev/null +++ b/endpoints/kettle/createCdaDatasources.kjb @@ -0,0 +1,122 @@ + + + createCdaDatasources + Create CDA datasources for BTable, reading catalogs in /system/olap/datasources.xml + + + 0 + / + - + 2013/07/04 18:48:22.641 + - + 2013/07/04 18:48:22.641 + + + + + + +
+ + + +ID_JOBYID_JOBCHANNEL_IDYCHANNEL_IDJOBNAMEYJOBNAMESTATUSYSTATUSLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSSTARTDATEYSTARTDATEENDDATEYENDDATELOGDATEYLOGDATEDEPDATEYDEPDATEREPLAYDATEYREPLAYDATELOG_FIELDYLOG_FIELD + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATEJOBNAMEYTRANSNAMEJOBENTRYNAMEYSTEPNAMELINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSRESULTYRESULTNR_RESULT_ROWSYNR_RESULT_ROWSNR_RESULT_FILESYNR_RESULT_FILESLOG_FIELDNLOG_FIELDCOPY_NRNCOPY_NR + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATELOGGING_OBJECT_TYPEYLOGGING_OBJECT_TYPEOBJECT_NAMEYOBJECT_NAMEOBJECT_COPYYOBJECT_COPYREPOSITORY_DIRECTORYYREPOSITORY_DIRECTORYFILENAMEYFILENAMEOBJECT_IDYOBJECT_IDOBJECT_REVISIONYOBJECT_REVISIONPARENT_CHANNEL_IDYPARENT_CHANNEL_IDROOT_CHANNEL_IDYROOT_CHANNEL_ID + N + + + + START + + SPECIAL + Y + N + N + 0 + 0 + 60 + 12 + 0 + 1 + 1 + N + Y + 0 + 171 + 137 + + + Success + + SUCCESS + N + Y + 0 + 455 + 137 + + + _createCdaDatasources + + TRANS + filename + + ${Internal.Job.Filename.Directory}/_createCdaDatasources.ktr + + N + N + N + N + N + N + + + N + N + Basic + N + + N + Y + N + N + Y + N + Y + 0 + 312 + 137 + + + + + START + _createCdaDatasources + 0 + 0 + Y + Y + Y + + + _createCdaDatasources + Success + 0 + 0 + Y + Y + N + + + + + diff --git a/endpoints/kettle/getPluginVersion.ktr b/endpoints/kettle/getPluginVersion.ktr new file mode 100644 index 0000000..7daed4e --- /dev/null +++ b/endpoints/kettle/getPluginVersion.ktr @@ -0,0 +1,180 @@ + + + + getPluginVersion + Get BTable plugin branch and version from version.xml + + + Normal + 0 + / + + + + + +
+ + + +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDTRANSNAMEYTRANSNAMESTATUSYSTATUSLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSSTARTDATEYSTARTDATEENDDATEYENDDATELOGDATEYLOGDATEDEPDATEYDEPDATEREPLAYDATEYREPLAYDATELOG_FIELDYLOG_FIELD + + +
+ + +ID_BATCHYID_BATCHSEQ_NRYSEQ_NRLOGDATEYLOGDATETRANSNAMEYTRANSNAMESTEPNAMEYSTEPNAMESTEP_COPYYSTEP_COPYLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSINPUT_BUFFER_ROWSYINPUT_BUFFER_ROWSOUTPUT_BUFFER_ROWSYOUTPUT_BUFFER_ROWS + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATELOGGING_OBJECT_TYPEYLOGGING_OBJECT_TYPEOBJECT_NAMEYOBJECT_NAMEOBJECT_COPYYOBJECT_COPYREPOSITORY_DIRECTORYYREPOSITORY_DIRECTORYFILENAMEYFILENAMEOBJECT_IDYOBJECT_IDOBJECT_REVISIONYOBJECT_REVISIONPARENT_CHANNEL_IDYPARENT_CHANNEL_IDROOT_CHANNEL_IDYROOT_CHANNEL_ID + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATETRANSNAMEYTRANSNAMESTEPNAMEYSTEPNAMESTEP_COPYYSTEP_COPYLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSLOG_FIELDNLOG_FIELD + + + +
+ + 0.0 + 0.0 + + 10000 + 50 + 50 + N + Y + 50000 + Y + + N + 1000 + 100 + + + + + + + + + - + 2013/07/04 18:48:57.073 + - + 2013/07/04 18:48:57.073 + + + + + Get data from version.xmlOUTPUTY + + Get data from version.xml + getXMLData + + Y + 1 + + none + + + N + + N + N + N + N + N + N + N + N + Y + + UTF-8 + + ${Internal.Transformation.Filename.Directory}/../../version.xml + + + N + N + + + + branch + branch + attribut + valueof + String + + + + + -1 + -1 + none + N + + + version + . + node + valueof + String + + + + + -1 + -1 + none + N + + + 0 + /version + N + N + + + + + + + + + + + + + 137 + 99 + Y + + + + + OUTPUT + Dummy + + Y + 1 + + none + + + + + 423 + 99 + Y + + + + + + + + N + diff --git a/endpoints/kettle/listCdaDatasources.ktr b/endpoints/kettle/listCdaDatasources.ktr new file mode 100644 index 0000000..ce3ccde --- /dev/null +++ b/endpoints/kettle/listCdaDatasources.ktr @@ -0,0 +1,204 @@ + + + + listCdaDatasources + List CDA datasources for BTable + + + Normal + 0 + / + + + btable.datasources.dir + ${Internal.Transformation.Filename.Directory}/../../resources/datasources + + + + + + +
+ + + +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDTRANSNAMEYTRANSNAMESTATUSYSTATUSLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSSTARTDATEYSTARTDATEENDDATEYENDDATELOGDATEYLOGDATEDEPDATEYDEPDATEREPLAYDATEYREPLAYDATELOG_FIELDYLOG_FIELD + + +
+ + +ID_BATCHYID_BATCHSEQ_NRYSEQ_NRLOGDATEYLOGDATETRANSNAMEYTRANSNAMESTEPNAMEYSTEPNAMESTEP_COPYYSTEP_COPYLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSINPUT_BUFFER_ROWSYINPUT_BUFFER_ROWSOUTPUT_BUFFER_ROWSYOUTPUT_BUFFER_ROWS + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATELOGGING_OBJECT_TYPEYLOGGING_OBJECT_TYPEOBJECT_NAMEYOBJECT_NAMEOBJECT_COPYYOBJECT_COPYREPOSITORY_DIRECTORYYREPOSITORY_DIRECTORYFILENAMEYFILENAMEOBJECT_IDYOBJECT_IDOBJECT_REVISIONYOBJECT_REVISIONPARENT_CHANNEL_IDYPARENT_CHANNEL_IDROOT_CHANNEL_IDYROOT_CHANNEL_ID + + +
+ +ID_BATCHYID_BATCHCHANNEL_IDYCHANNEL_IDLOG_DATEYLOG_DATETRANSNAMEYTRANSNAMESTEPNAMEYSTEPNAMESTEP_COPYYSTEP_COPYLINES_READYLINES_READLINES_WRITTENYLINES_WRITTENLINES_UPDATEDYLINES_UPDATEDLINES_INPUTYLINES_INPUTLINES_OUTPUTYLINES_OUTPUTLINES_REJECTEDYLINES_REJECTEDERRORSYERRORSLOG_FIELDNLOG_FIELD + + + +
+ + 0.0 + 0.0 + + 10000 + 50 + 50 + N + Y + 50000 + Y + + N + 1000 + 100 + + + + + + + + + - + 2013/07/04 18:48:57.073 + - + 2013/07/04 18:48:57.073 + + + + + Read CDA filesOUTPUTY + + OUTPUT + SortRows + + Y + 1 + + none + + + %%java.io.tmpdir%% + out + 1000000 + + N + + N + + + Catalog + Y + N + + + Jndi + Y + N + + + + + 392 + 155 + Y + + + + + Read CDA files + getXMLData + + Y + 1 + + none + + + N + + N + N + N + N + N + N + N + N + Y + + UTF-8 + + ${btable.datasources.dir} + .*\.cda + + N + N + + + + Catalog + Connection/Catalog + node + valueof + String + + + + + -1 + -1 + none + N + + + Jndi + Connection/Jndi + node + valueof + String + + + + + -1 + -1 + none + N + + + 0 + /CDADescriptor/DataSources + N + N + + + + + + + + + + + + + 190 + 155 + Y + + + + + + + + N + diff --git a/ivy.xml b/ivy.xml new file mode 100644 index 0000000..b2ca495 --- /dev/null +++ b/ivy.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ivysettings.xml b/ivysettings.xml new file mode 100644 index 0000000..0311e3a --- /dev/null +++ b/ivysettings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/cpf-core-TRUNK-SNAPSHOT.jar b/lib/cpf-core-TRUNK-SNAPSHOT.jar new file mode 100644 index 0000000..b081a14 Binary files /dev/null and b/lib/cpf-core-TRUNK-SNAPSHOT.jar differ diff --git a/lib/cpf-pentaho-TRUNK-SNAPSHOT.jar b/lib/cpf-pentaho-TRUNK-SNAPSHOT.jar new file mode 100644 index 0000000..55b2516 Binary files /dev/null and b/lib/cpf-pentaho-TRUNK-SNAPSHOT.jar differ diff --git a/lib/cpk-core-TRUNK-SNAPSHOT.jar b/lib/cpk-core-TRUNK-SNAPSHOT.jar new file mode 100644 index 0000000..c289cb9 Binary files /dev/null and b/lib/cpk-core-TRUNK-SNAPSHOT.jar differ diff --git a/lib/cpk-pentaho-TRUNK-SNAPSHOT.jar b/lib/cpk-pentaho-TRUNK-SNAPSHOT.jar new file mode 100644 index 0000000..4e5a7a7 Binary files /dev/null and b/lib/cpk-pentaho-TRUNK-SNAPSHOT.jar differ diff --git a/lib/jackson-annotations-2.2.2.jar b/lib/jackson-annotations-2.2.2.jar new file mode 100644 index 0000000..c7a2521 Binary files /dev/null and b/lib/jackson-annotations-2.2.2.jar differ diff --git a/lib/jackson-core-2.2.2.jar b/lib/jackson-core-2.2.2.jar new file mode 100644 index 0000000..508117e Binary files /dev/null and b/lib/jackson-core-2.2.2.jar differ diff --git a/lib/jackson-core-asl-1.9.12.jar b/lib/jackson-core-asl-1.9.12.jar new file mode 100644 index 0000000..deb372e Binary files /dev/null and b/lib/jackson-core-asl-1.9.12.jar differ diff --git a/lib/jackson-databind-2.2.2.jar b/lib/jackson-databind-2.2.2.jar new file mode 100644 index 0000000..193627c Binary files /dev/null and b/lib/jackson-databind-2.2.2.jar differ diff --git a/lib/jackson-mapper-asl-1.9.12.jar b/lib/jackson-mapper-asl-1.9.12.jar new file mode 100644 index 0000000..849b0e8 Binary files /dev/null and b/lib/jackson-mapper-asl-1.9.12.jar differ diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..f651e74 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,24 @@ + + + + + + + + + + BTable + A drill-anywhere component for CDE + + + + + + + + + diff --git a/resources/components/BTable/BTableComponent.js b/resources/components/BTable/BTableComponent.js new file mode 100644 index 0000000..f3bf35d --- /dev/null +++ b/resources/components/BTable/BTableComponent.js @@ -0,0 +1,725 @@ +/* + * Copyright 2013 Biz Tech (http://www.biztech.it). All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * Covered Software is provided under this License on an “as is” basis, + * without warranty of any kind, either expressed, implied, or statutory, + * including, without limitation, warranties that the Covered Software is + * free of defects, merchantable, fit for a particular purpose or non-infringing. + * The entire risk as to the quality and performance of the Covered Software is with You. + * Should any Covered Software prove defective in any respect, You (not any Contributor) + * assume the cost of any necessary servicing, repair, or correction. + * This disclaimer of warranty constitutes an essential part of this License. + * No use of any Covered Software is authorized under this License except under this disclaimer. + * + * Initial contributors: Luca Pazzaglia, Massimo Bonometto + * + * Dependencies: CDE, CDF, CDA + * + * This file is a modification of + * https://github.com/webdetails/cdf/blob/13.03.25/bi-platform-v2-plugin/cdf/js/components/table.js + */ + + +/* + * Function: fnLengthChange + * Purpose: Change the number of records on display + * Returns: array: + * Inputs: object:oSettings - DataTables settings object + * int:iDisplay - New display length + */ + // Ensure we load dataTables before this line. If not, just keep going +if($.fn.dataTableExt != undefined){ + $.fn.dataTableExt.oApi.fnLengthChange = function ( oSettings, iDisplay ) + { + oSettings._iDisplayLength = iDisplay; + oSettings.oApi._fnCalculateEnd( oSettings ); + + // If we have space to show extra rows backing up from the end point - then do so + if ( oSettings._iDisplayEnd == oSettings.aiDisplay.length ) + { + oSettings._iDisplayStart = oSettings._iDisplayEnd - oSettings._iDisplayLength; + if ( oSettings._iDisplayStart < 0 ) + { + oSettings._iDisplayStart = 0; + } + } + + if ( oSettings._iDisplayLength == -1 ) + { + oSettings._iDisplayStart = 0; + } + + oSettings.oApi._fnDraw( oSettings ); + + $('select', oSettings.oFeatures.l).val( iDisplay ); + }; +/* Example + * $(document).ready(function() { + * var oTable = $('#example').dataTable(); + * oTable.fnLengthChange( 100 ); + * } ); + */ +} + +var BTableComponent = UnmanagedComponent.extend({ + + ph: undefined, + + cda: { + path: "/system/BTable/resources/datasources/{FILENAME}.cda", + dataAccessId: "BTableQuery" + }, + + btParamName: undefined, + + bTable: undefined, + + headerRows: undefined, + + getBTable: function() { + return this.bTable == undefined ? {} : this.bTable; + }, + + timer: undefined, + + init: function() { + var componentName = this.name.replace("render_", ""); + + this.btParamName = componentName + "MdxQuery"; + + this.cda.path = this.cda.path.replace("{FILENAME}", this.jndi + "_" + this.catalog.replace(/\//g,"_").replace(".xml","")); + + this.bTable = new bt.components.BTable({ + componentName: this.name, + componentHtmlObject: this.htmlObject, + catalog: this.catalog, + jndi: this.jndi, + cube: this.cube, + dimensions: this.dimensions, + measures: this.measures, + filters: this.filters, + pivotDimensions: this.pivotDimensions, + measuresOnColumns: this.measuresOnColumns, + orderBy: this.orderBy, + nonEmptyRows: this.nonEmptyRows, + nonEmptyColumns: this.nonEmptyColumns, + grandTotal: this.grandTotal, + subTotals: this.subTotals, + pivotGrandTotal: this.pivotGrandTotal, + pivotSubTotals: this.pivotSubTotals, + //totalsPosition: this.totalsPosition.toLowerCase(), + showFilters: this.showFilters, + exportStyle: this.exportStyle ? this.exportStyle : {} + }); + + $("#" + this.htmlObject).addClass("bTableComponent"); + }, + + update: function() { + if(this.timer == undefined) + this.timer = getTimer({component: {type: "BTable", name: this.name}}); + this.timer.start("Start component updating"); + + if(!this.preExec()){ + return; + } + + if(!this.isInitialized) { + this.init(); + this.isInitialized = true; + } + + if(!this.htmlObject) { + return this.error("BTableComponent requires an htmlObject"); + } + try{ + this.block(); + this.setup(); + + var mdxQuery = this.bTable.query.getMdx(); + //console.log(mdxQuery); + this.timer.check("Query string returned"); + + Dashboards.setParameter(this.btParamName, mdxQuery); + this.parameters = [["mdxQuery" , this.btParamName]]; + + if(this.chartDefinition.paginateServerside) { + this.paginatingUpdate(); + } else { + /* The non-paging query handler only needs to concern itself + * with handling postFetch and calling the draw function + */ + var success = _.bind(function(data){ + this.rawData = data; + this.processTableComponentResponse(data) + },this); + var handler = this.getSuccessHandler(success); + + this.queryState.setAjaxOptions({async:true}); + this.queryState.fetchData(this.parameters, handler); + } + } catch (e) { + /* + * Something went wrong and we won't have handlers firing in the future + * that will trigger unblock, meaning we need to trigger unblock manually. + */ + this.unblock(); + } + }, + + paginatingUpdate: function() { + var cd = this.chartDefinition; + this.extraOptions = this.extraOptions || []; + this.extraOptions.push(["bServerSide",true]); + this.extraOptions.push(["bProcessing",true]); + this.queryState.setPageSize(parseInt(cd.displayLength || 10)); + this.queryState.setCallback(_.bind(function(values) { + changedValues = undefined; + if((typeof(this.postFetch)=='function')){ + changedValues = this.postFetch(values); + } + if (changedValues != undefined) { + values = changedValues; + } + this.processTableComponentResponse(values); + },this)); + this.queryState.setParameters(this.parameters); + this.queryState.setAjaxOptions({async:true}); + this.processTableComponentResponse(); + }, + + /* Initial setup: clearing out the htmlObject and building the query object */ + setup: function() { + var cd = this.chartDefinition; + + cd.path = this.cda.path; + cd.dataAccessId = this.cda.dataAccessId; + + cd.sort = false; + + var myself = this; + + $("#"+this.htmlObject).contextMenu({ + selector: 'thead th', + className: 'menu-with-title', + build: function($trigger, e) { + // this callback is executed every time the menu is to be shown + // its results are destroyed every time the menu is hidden + // e is the original contextmenu event, containing e.pageX and e.pageY (amongst other data) + var target = $(e.target).closest("th").data("btref"); + return myself.bTable.buildHeaderContextMenu(target); + } + }).contextMenu({ + selector: 'tbody td.dataTables_empty', + className: 'menu-with-title', + build: function($trigger, e) { + return myself.bTable.buildNoDataContextMenu(); + } + }).contextMenu({ + selector: 'tbody td', + className: 'menu-with-title', + build: function($trigger, e) { + var state = {}, + target = $(e.target), + results = myself.rawData; + if(!(target.parents('tbody').length)) { + return; + } else if (target.get(0).tagName != 'TD') { + target = target.closest('td'); + } + var position = myself.dataTable.fnGetPosition(target.get(0)); + state.rawData = myself.rawData; + state.tableData = myself.dataTable.fnGetData(); + state.colIdx = position[2]; + state.rowIdx = position[0]; + + if(cd.colFormats) { + state.colFormat = cd.colFormats[state.colIdx]; + } + state.target = target; + + return myself.bTable.buildBodyContextMenu(state); + } + }); + + if (cd == undefined){ + Dashboards.log("Fatal - No chart definition passed","error"); + return; + } + cd["tableId"] = this.htmlObject + "Table"; + + // Clear previous table + this.ph = $("#"+this.htmlObject).empty(); + // remove drawCallback from the parameters, or + // it'll be called before we have an actual table... + var croppedCd = $.extend({},cd); + croppedCd.drawCallback = undefined; + this.queryState = new Query(croppedCd); + this.query = this.queryState; // for analogy with ccc component's name + // make sure to clean sort options + var sortBy = this.chartDefinition.sortBy || [], + sortOptions = []; + for (var i = 0; i < sortBy.length; i++) { + var col = sortBy[i][0]; + var dir = sortBy[i][1]; + sortOptions.push( col + (dir == "asc" ? "A" : "D")); + } + this.queryState.setSortBy(sortOptions); + + myself.bTable.printFilters(); + }, + + pagingCallback: function(url, params,callback,dataTable) { + function p( sKey ) { + for ( var i=0, iLen=params.length ; i 0) { + for (var i = 0; i < sortingCols; i++) { + var col = p("iSortCol_" + i); + var dir = p("sSortDir_" + i); + sort.push( col + (dir == "asc" ? "A" : "D")); + } + } + var query = this.queryState, + myself = this; + query.setSortBy(sort.join(",")); + query.setPageSize(parseInt(p("iDisplayLength"))); + query.setPageStartingAt(p("iDisplayStart")); + query.fetchData(function(d) { + if (myself.postFetch){ + var mod = myself.postFetch(d,dataTable); + if (typeof mod !== "undefined") { + d = mod; + } + } + var response = { + iTotalRecords: d.queryInfo.totalRows, + iTotalDisplayRecords: d.queryInfo.totalRows + }; + response.aaData = d.resultset; + response.sEcho = p("sEcho"); + myself.rawData = d; + callback(response); + }); + }, + + /* + * Callback for when the table is finished drawing. Called every time there + * is a redraw event (so not only updates, but also pagination and sorting). + * We handle addIns and such things in here. + */ + fnDrawCallback: function(dataTableSettings) { + var dataTable = dataTableSettings.oInstance, + cd = this.chartDefinition, + myself = this, + handleAddIns = _.bind(this.handleAddIns,this); + this.ph.find("tbody tr").each(function(row,tr){ + /* + * Reject rows that are not actually part + * of the datatable (e.g. nested tables) + */ + if (dataTable.fnGetPosition(tr) == null) { + return true; + } + + $(tr).children("td").each(function(col,td){ + + var foundAddIn = handleAddIns(dataTable, td); + /* + * Process column format for those columns + * where we didn't find a matching addIn + */ + if(!foundAddIn && cd.colFormats) { + var position = dataTable.fnGetPosition(td), + rowIdx = position[0], + colIdx = position[2], + format = cd.colFormats[colIdx], + value = myself.rawData.resultset[rowIdx][colIdx]; + if (format && (typeof value != "undefined" && value !== null)) { + $(td).text(sprintf(format,value)); + } + } + }); + }); + + /* Old urlTemplate code. This needs to be here for backward compatibility */ + if(cd.urlTemplate != undefined){ + var td =$("#" + myself.htmlObject + " td:nth-child(1)"); + td.addClass('cdfClickable'); + td.bind("click", function(e){ + var regex = new RegExp("{"+cd.parameterName+"}","g"); + var f = cd.urlTemplate.replace(regex,$(this).text()); + eval(f); + }); + } + + this.timer.check("Table drawn without spans and formatting"); + + var thead = $(""); + for(i = 0; i < this.headerRows.length; i++) { + var lastRow = (i == this.headerRows.length - 1) ? true : false; + var headerRow = this.headerRows[i]; + var tr = $(""); + $.each(headerRow, function(j, col) { + if(lastRow) col.index = j; + var html = ""; + html += "
"; + var th = $(html); + tr.append(th); + }); + thead.append(tr); + } + + this.ph.find("thead").empty().prepend(thead.html()); + + $("#" + myself.htmlObject + " tbody tr").each(function() { + var totalCells = $(this).find("td:contains('BT_TOTAL')"); + if(totalCells.length > 0) { + var isGrandTotalRow = $(this).find("td:eq(0):contains('BT_TOTAL')").length == 1; + var tds = $(this).find("td"); + tds.addClass("subtotal"); + if(isGrandTotalRow) {tds.removeClass("subtotal"); tds.addClass("grandtotal");} + totalCells.each(function(i) { + if(i == 0) + $(this).text("Total"); + else + $(this).empty(); + }); + } + }); + + var zippedRows = myself.bTable.getBodyRowspans(); + $.each(zippedRows, function(i, arr) { + var position = 0; + var indexes = $.map(arr, function(e) { + position += e.rowspan; + return position; + }); + indexes.splice(0, 0, 0); + $("#" + myself.htmlObject + " tbody tr td:nth-child(" + (i + 1) + ")").each(function(k) { + if($.inArray(k, indexes) < 0) + $(this).empty(); + }); + }); + + this.timer.check("Table completely drawn"); + + /* Handle post-draw callback the user might have provided */ + if(typeof cd.drawCallback == 'function'){ + cd.drawCallback.apply(myself,arguments); + } + }, + + /* + * Handler for when the table finishes initialising. This only happens once, + * when the table *initialises* ,as opposed to every time the table is drawn, + * so it provides us with a good place to add the postExec callback. + */ + fnInitComplete: function() { + this.postExec(); + this.unblock(); + }, + + /* + * Resolve and call addIns for the given td in the context of the given + * dataTable. Returns true if there was an addIn and it was successfully + * called, or false otherwise. + */ + handleAddIns: function(dataTable, td) { + var cd = this.chartDefinition, + position = dataTable.fnGetPosition(td), + rowIdx = position[0], + colIdx = position[2], + colType = cd.colTypes[colIdx], + addIn = this.getAddIn("colType",colType), + state = {}, + target = $(td), + results = this.rawData; + if (!addIn) { + return false; + } + try { + if(!(target.parents('tbody').length)) { + return; + } else if (target.get(0).tagName != 'TD') { + target = target.closest('td'); + } + state.rawData = results; + state.tableData = dataTable.fnGetData(); + state.colIdx = colIdx; + state.rowIdx = rowIdx; + state.series = results.resultset[state.rowIdx][0]; + state.category = results.metadata[state.colIdx].colName; + state.value = results.resultset[state.rowIdx][state.colIdx]; + if(cd.colFormats) { + state.colFormat = cd.colFormats[state.colIdx]; + } + state.target = target; + addIn.call(td,state,this.getAddInOptions("colType",addIn.getName())); + return true; + } catch (e) { + this.dashboard.error(e); + return false; + } + }, + + processTableComponentResponse : function(json) { + var myself = this, + cd = this.chartDefinition, + extraOptions = {}; + + this.timer.check("Query result returned"); + + json = myself.bTable.normalizeCdaJson(json); + + this.ph.trigger('cdfTableComponentProcessResponse'); + + /* + * Gestire un resultset vuoto: + * creare comunque le intestazioni + */ + var noResult = json.metadata.length == 0; + + if(!noResult) + myself.bTable.setHeaders(json.metadata.map(function(i){return i.colName})); + + myself.headerRows = noResult ? [] : myself.bTable.getHeaders(); + + // Set defaults for headers / types + cd.colHeaders = noResult ? [] : json.metadata.map(function(i){return i.colName}); + cd.colTypes = noResult ? [] : json.metadata.map(function(i){return i.colType.toLowerCase()}); + cd.colFormats = noResult ? [] : json.metadata.map(function(i){return i.colType.toLowerCase() == "numeric" ? /*"%.2f"*/"%d" : "%s"}); + + var dtData0 = TableComponent.getDataTableOptions(cd); + + if(noResult) + dtData0.aoColumns = [{sClass:"column0 string", sTitle:"Empty Result", sType:"string"}]; + + // Build a default config from the standard options + $.each(this.extraOptions ? this.extraOptions : {}, function(i,e){ + extraOptions[e[0]] = e[1]; + }); + var dtData = $.extend(cd.dataTableOptions,dtData0,extraOptions); + + /* Configure the table event handlers */ + dtData.fnDrawCallback = _.bind(this.fnDrawCallback,this); + dtData.fnInitComplete = _.bind(this.fnInitComplete,this); + /* fnServerData is required for server-side pagination */ + if (dtData.bServerSide) { + var myself = this; + dtData.fnServerData = function(u,p,c) { + myself.pagingCallback(u,p,c,this); + }; + } + + /* We need to make sure we're getting data from the right place, + * depending on whether we're using CDA + */ + if (json) { + dtData.aaData = json.resultset; + } + + this.ph.html("
"); + /* + * We'll first initialize a blank table so that we have a + * table handle to work with while the table is redrawing + */ + this.dataTable = $("#"+this.htmlObject+'Table').dataTable(dtData); + + // We'll create an Array to keep track of the open expandable rows. + this.dataTable.anOpen = []; + + + myself.ph.find ('table').bind('click',function(e) { + if (typeof cd.clickAction === 'function' || myself.expandOnClick) { + var state = {}, + target = $(e.target), + results = myself.rawData; + if(!(target.parents('tbody').length)) { + return; + } else if (target.get(0).tagName != 'TD') { + target = target.closest('td'); + } + var position = myself.dataTable.fnGetPosition(target.get(0)); + state.rawData = myself.rawData; + state.tableData = myself.dataTable.fnGetData(); + state.colIdx = position[2]; + state.rowIdx = position[0]; + state.series = results.resultset[state.rowIdx][0]; + + state.category = results.metadata[state.colIdx].colName; + state.value = results.resultset[state.rowIdx][state.colIdx]; + state.colFormat = cd.colFormats[state.colIdx]; + + /* + if(cd.colFormats) { + state.colFormat = cd.colFormats[state.colIdx]; + } + */ + + state.target = target; + + if ( myself.expandOnClick ) { + myself.handleExpandOnClick(state); + } + if ( cd.clickAction ){ + cd.clickAction.call(myself,state); + } + } + }); + + + myself.ph.trigger('cdfTableComponentFinishRendering'); + }, + + handleExpandOnClick: function(event) { + var myself = this, + detailContainerObj = myself.expandContainerObject, + activeclass = "expandingClass"; + + if(typeof activeclass === 'undefined'){ + activeclass = "activeRow"; + } + + var obj = event.target.closest("tr"), + a = event.target.closest("a"); + + if (a.hasClass ('info')) { + return; + } else { + var row = obj.get(0), + value = event.series, + htmlContent = $("#" + detailContainerObj).html(), + anOpen = myself.dataTable.anOpen, + i = $.inArray( row, anOpen ); + + if( obj.hasClass(activeclass) ){ + obj.removeClass(activeclass); + myself.dataTable.fnClose( row ); + anOpen.splice(i,1); + + } else { + // Closes all open expandable rows . + for ( var j=0; j < anOpen.length; j++ ) { + $(anOpen[j]).removeClass(activeclass); + myself.dataTable.fnClose( anOpen[j] ); + anOpen.splice(j ,1); + } + obj.addClass(activeclass); + + anOpen.push( row ); + // Since the switch to async, we need to open it first + myself.dataTable.fnOpen( row, htmlContent, activeclass ); + + //Read parameters and fire changes + var results = myself.queryState.lastResults(); + $(myself.expandParameters).each(function f(i, elt) { + Dashboards.fireChange(elt[1], results.resultset[event.rowIdx][parseInt(elt[0],10)]); + }); + + }; + }; + $("td.expandingClass").click( + function(event){ + //Does nothing but it prevents problems on expandingClass clicks! + event.stopPropagation(); + return; + } + ); + } + +}, + +{ + getDataTableOptions : function(options) { + var dtData = {}; + + if(options.tableStyle == "themeroller"){ + dtData.bJQueryUI = true; + } + dtData.bInfo = options.info; + dtData.iDisplayLength = options.displayLength; + dtData.bLengthChange = options.lengthChange; + dtData.bPaginate = options.paginate; + dtData.bSort = options.sort; + dtData.bFilter = options.filter; + dtData.sPaginationType = options.paginationType; + dtData.sDom = options.sDom; + dtData.aaSorting = options.sortBy; + + if (typeof options.oLanguage == "string"){ + dtData.oLanguage = eval("(" + options.oLanguage + ")");//TODO: er... + } + else { + dtData.oLanguage = options.oLanguage; + } + + if(options.colHeaders != undefined){ + dtData.aoColumns = new Array(options.colHeaders.length); + for(var i = 0; i< options.colHeaders.length; i++){ + dtData.aoColumns[i]={} + dtData.aoColumns[i].sClass="column"+i; + }; + $.each(options.colHeaders,function(i,val){ + dtData.aoColumns[i].sTitle=val; + if(val == "") dtData.aoColumns[i].bVisible=false; + }); // colHeaders + if(options.colTypes!=undefined){ + $.each(options.colTypes,function(i,val){ + var col = dtData.aoColumns[i]; + // Specific case: hidden cols + if(val == "hidden") col.bVisible=false; + col.sClass+=" "+val; + col.sType=val; + + }) + }; // colTypes + if(options.colFormats!=undefined){ + // Changes are made directly to the json + + }; // colFormats + + var bAutoWidth = true; + if(options.colWidths!=undefined){ + $.each(options.colWidths,function(i,val){ + if (val!=null){ + dtData.aoColumns[i].sWidth=val; + bAutoWidth = false; + } + }) + }; //colWidths + dtData.bAutoWidth = bAutoWidth; + + if(options.colSortable!=undefined){ + $.each(options.colSortable,function(i,val){ + if (val!=null && ( !val || val == "false" ) ){ + dtData.aoColumns[i].bSortable=false + } + }) + }; //colSortable + if(options.colSearchable!=undefined){ + $.each(options.colSearchable,function(i,val){ + if (val!=null && ( !val || val == "false" ) ){ + dtData.aoColumns[i].bSearchable=false + } + }) + }; //colSearchable + + } + + return dtData; + } +}); diff --git a/resources/components/BTable/component.xml b/resources/components/BTable/component.xml new file mode 100644 index 0000000..76e59b0 --- /dev/null +++ b/resources/components/BTable/component.xml @@ -0,0 +1,311 @@ + +
+ BTable + BTableComponent + BTable (by Biz Tech) + COMMUNITYCOMPONENTS + Community Contributions + PalleteEntry + 1.0 +
+ + + htmlObject + listeners + + catalog + jndi + cube + dimensions + measures + pivotDimensions + filters + orderBy + measuresOnColumns + nonEmptyRows + nonEmptyColumns + grandTotal + subTotals + pivotGrandTotal + pivotSubTotals + + showFilters + + + cccClickAction + colSearchable + paginate + paginateServerside + paginationType + filter + info + displayLength + lengthChange + tableStyle + drawCallback + sDom + oLanguage + + executeAtStart + preChange + postChange + postFetch + preExecution + postExecution + refreshPeriod + tooltip + extraOptions + expandParameters + expandOnClick + expandContainerObject + + + + + + + + + + bt.table.js + bt.query.js + bt.olap.js + bt.utils.js + jquery.contextMenu.js + jquery.ui.position + jquery.multiselect.filter.js + + + +
+ catalog + BaseProperty + + Catalog + Catalog + MondrianCatalog + String + 10 + 1.0 +
+
+ +
+ jndi + BaseProperty + + Jndi + Jndi + Jndi + String + 10 + 1.0 +
+
+ +
+ cube + BaseProperty + + Cube + Cube + String + String + 10 + 1.0 +
+
+ +
+ dimensions + BaseProperty + "[]" + Dimensions + + ValuesArray + Array + 10 + 1.0 +
+
+ +
+ measures + BaseProperty + "[]" + Measures + + ValuesArray + Array + 10 + 1.0 +
+
+ +
+ pivotDimensions + BaseProperty + "[]" + Pivot Dimensions + + ValuesArray + Array + 10 + 1.0 +
+
+ +
+ filters + BaseProperty + "[]" + Filters + + ValuesArray + Array + 10 + 1.0 +
+
+ +
+ orderBy + BaseProperty + "[]" + Order By + + ValuesArray + Array + 10 + 1.0 +
+
+ +
+ measuresOnColumns + BaseProperty + "true" + Measures on Columns + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ nonEmptyRows + BaseProperty + "true" + Non Empty Rows + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ nonEmptyColumns + BaseProperty + "true" + Non Empty Columns + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ grandTotal + BaseProperty + "false" + Grand Total on Dimensions + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ subTotals + BaseProperty + "false" + Subtotals on Dimensions + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ pivotGrandTotal + BaseProperty + "false" + Grand Total on Pivot + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ pivotSubTotals + BaseProperty + "false" + Subtotals on Pivot + + Boolean + Boolean + + 10 + 1.0 +
+
+ +
+ totalsPosition + BaseProperty + Bottom + Totals Position + + String + String + 10 + 1.0 +
+
+ +
+ showFilters + BaseProperty + "true" + Show Applied Filters and Sorts + + Boolean + Boolean + + 10 + 1.0 +
+
+
+
+
+
diff --git a/resources/components/BTable/lib/bt.olap.js b/resources/components/BTable/lib/bt.olap.js new file mode 100644 index 0000000..f4593f9 --- /dev/null +++ b/resources/components/BTable/lib/bt.olap.js @@ -0,0 +1,176 @@ +/* + * Copyright 2013 Biz Tech (http://www.biztech.it). All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * Covered Software is provided under this License on an “as is” basis, + * without warranty of any kind, either expressed, implied, or statutory, + * including, without limitation, warranties that the Covered Software is + * free of defects, merchantable, fit for a particular purpose or non-infringing. + * The entire risk as to the quality and performance of the Covered Software is with You. + * Should any Covered Software prove defective in any respect, You (not any Contributor) + * assume the cost of any necessary servicing, repair, or correction. + * This disclaimer of warranty constitutes an essential part of this License. + * No use of any Covered Software is authorized under this License except under this disclaimer. + * + * Initial contributors: Luca Pazzaglia, Massimo Bonometto + */ + + +var bt = bt || {}; +bt.olap = bt.olap || {}; + +bt.olap.OlapCube = function(spec) { + + var defaults = { + url: "/pentaho/content/pentaho-cdf-dd/OlapUtils", + catalog: "", + cube: "" + }; + + var myself = {}; + + myself.options = $.extend({}, defaults, spec); + + var olapUtils = null; + var structure = null; + + myself.initialize = function() { + olapUtils = new bt.utils.OlapUtils(myself.options); + structure = olapUtils.getCube(); + }; + + myself.getStructure = function() { + return structure; + }; + + myself.getHierarchies = function() { + var hierarchies = new Array(); + + $.each( myself.getStructure().dimensions, function( key, value ) { + $.each( value.hierarchies, function( key, value ) { + hierarchies.push( value ); + }); + }); + + return hierarchies; + } + + myself.getLevels = function() { + var levels = new Array(); + + $.each( myself.getStructure().dimensions, function( key, value ) { + $.each( value.hierarchies, function( key, value ) { + $.each( value.levels, function( key, value ) { + levels.push( value ); + }); + }); + }); + + return levels; + } + + myself.getElementName = function(qualifiedName) { + var result = qualifiedName; + $.each( myself.getLevels(), function( key, value ) { + if(value.qualifiedName == qualifiedName) { + result = value.name; + return; + } + }); + $.each( myself.getStructure().measures, function( key, value ) { + if(value.qualifiedName == qualifiedName) { + result = value.name; + return; + } + }); + return result; + }; + + myself.getElementFullName = function(qualifiedName) { + var result = qualifiedName; + $.each( myself.getLevels(), function( key, value ) { + if(value.qualifiedName == qualifiedName) { + var h = qualifiedName.split("].[")[0].substring(1); + var l = value.name; + result = h + " -> " + l; + return; + } + }); + $.each( myself.getStructure().measures, function( key, value ) { + if(value.qualifiedName == qualifiedName) { + var h = qualifiedName.split("].[")[0].substring(1); + var l = value.name; + result = h + " -> " + l; + return; + } + }); + return result; + }; + + myself.getElementType = function(qualifiedName) { + var result = undefined; + var found = false; + + var arr = $.map(myself.getLevels(), function(i){return i.qualifiedName}); + var idx = $.inArray(qualifiedName, arr); + + if(idx >= 0) { + result = "DIMENSION"; + found = true; + } + + if(!found) { + arr = $.map(myself.getStructure().measures, function(i){return i.qualifiedName}); + + idx = $.inArray(qualifiedName, arr); + + if(idx >= 0) { + result = "MEASURE"; + } + } + + return result; + }; + + myself.getLevelDepth = function(qualifiedName) { + var result = 1; + $.each( myself.getLevels(), function( key, value ) { + if(value.qualifiedName == qualifiedName) { + result = value.depth; + return; + } + }); + return result; + }; + + myself.getHierarchyLevels = function(hierarchyQualifiedName) { + var levels = new Array(); + $.each( myself.getStructure().dimensions, function( key, value ) { + $.each( value.hierarchies, function( key, value ) { + if(value.qualifiedName == hierarchyQualifiedName) { + $.each( value.levels, function( key, value ) { + levels.push( value ); + }); + return levels; + } + }); + }); + return levels; + } + + myself.initialize = function() { + olapUtils = new bt.utils.OlapUtils(myself.options); + structure = olapUtils.getCube(); + }; + + myself.getLevelMembers = function(levelQualifiedName) { + return olapUtils.getLevelMembers({level: levelQualifiedName}); + }; + + myself.initialize(); + + return myself; +} diff --git a/resources/components/BTable/lib/bt.query.js b/resources/components/BTable/lib/bt.query.js new file mode 100644 index 0000000..c3f6f4f --- /dev/null +++ b/resources/components/BTable/lib/bt.query.js @@ -0,0 +1,1111 @@ +/* + * Copyright 2013 Biz Tech (http://www.biztech.it). All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * Covered Software is provided under this License on an “as is” basis, + * without warranty of any kind, either expressed, implied, or statutory, + * including, without limitation, warranties that the Covered Software is + * free of defects, merchantable, fit for a particular purpose or non-infringing. + * The entire risk as to the quality and performance of the Covered Software is with You. + * Should any Covered Software prove defective in any respect, You (not any Contributor) + * assume the cost of any necessary servicing, repair, or correction. + * This disclaimer of warranty constitutes an essential part of this License. + * No use of any Covered Software is authorized under this License except under this disclaimer. + * + * Initial contributors: Luca Pazzaglia, Massimo Bonometto + */ + + +var bt = bt || {}; + +bt.Query = function(properties, olapCube) { + + var defaults = { + cube: "", + dimensions: [], + measures: [], + pivotDimensions: [], + filters: [], + measuresOnColumns: true, + nonEmpty: { + columns: true, + rows: true + }, + summary: { + grandTotal: true, + subTotals: true, + pivotGrandTotal: true, + pivotSubTotals: true, + position: "bottom" + }, + orders: [] + }; + + var myself = {}; + + var settings = $.extend({}, defaults, properties); + + var history = []; + + var definition = { + cube: settings.cube, + dimensions: settings.dimensions, + measures: settings.measures, + pivotDimensions: settings.pivotDimensions, + filters: settings.filters, + orders: settings.orders + } + + myself.saveInHistory = function() { + var def = $.extend(true, {}, definition); + history.push(def); + } + + myself.saveInHistory(); + + myself.reset = function() { + definition = $.extend(true, {}, history[0]); + + initializeFiltersMap(definition.dimensions); + initializeFiltersMap(definition.pivotDimensions); + initializeFiltersMap(definition.filters); + + filtersMap.synchronizedByParameters = true; + + initializeOrdersMap(); + } + + myself.validate = function(olapCube) { + // At least one dimension and one measure! + // No measures in filter! + // The same hierarchy can't be in two different axis! + // Levels of a same hierarchy have to be adjacent and in order of increasing depth! + // Only one "MEASURES" placeholder in pivot dimensions! + } + + + myself.getPlainFilter = function(levelQualifiedName) { + var result = ""; + + var lQn = levelQualifiedName; + var hQn = (lQn.split("].[")[0] + "]").replace("]]", "]"); + + var boundToDashboard = filtersMap.synchronizedByParameters; + + var isCalculatedMember = lQn.indexOf("].[") < 0; + + var level = isCalculatedMember ? filtersMap.hierarchies[hQn].calculatedMembers : filtersMap.hierarchies[hQn].levels[lQn]; + + if(level.filtered) { + var filterMode = level.filterMode + (level.uniqueNames ? "_un" : ""); + var members = null; + + if(boundToDashboard && level.synchronizedByParameters) { + var filterExpression = level.initialFilterExpression; + var param = filterExpression.replace(filterMode + ":", ""); + var members = Dashboards.getParameterValue(param); + } else { + members = level.members; + } + + result = filterMode + ":[" + ( $.isArray(members) ? members.join("],[") : members ) + "]"; + } + + return result; + } + + var getMdxFilter = function(levelQualifiedName, hierarchyQualifiedName) { + var mdx = ""; + + var lQn = levelQualifiedName; + var hQn = !hierarchyQualifiedName ? (lQn.split("].[")[0] + "]").replace("]]", "]") : hierarchyQualifiedName; + + var boundToDashboard = filtersMap.synchronizedByParameters; + + var isCalculatedMember = lQn.indexOf("].[") < 0; + + //var level = filtersMap.hierarchies[hQn].levels[lQn]; + + var level = isCalculatedMember ? filtersMap.hierarchies[hQn].calculatedMembers : filtersMap.hierarchies[hQn].levels[lQn]; + + if(level.filtered) { + var filterMode = level.filterMode; + var include = filterMode == "include"; + var exclude = filterMode == "exclude"; + var between = filterMode == "between"; + + var uniqueNames = level.uniqueNames; + if(uniqueNames) filterMode += "_un"; + + var members = null; + + if(boundToDashboard && level.synchronizedByParameters) { + var filterExpression = level.initialFilterExpression; + var param = filterExpression.replace(filterMode + ":", ""); + members = Dashboards.getParameterValue(param); + } else { + members = level.members; + } + + var separator = between ? " :" : ","; + + if(uniqueNames) { + mdx = $.isArray(members) ? members.join(separator + " ") : members; + mdx = "{" + mdx + "}"; + } else { + if(between) { + //mdx = "{Head(Filter({" + lQn + ".Members}, (" + lQn + ".CurrentMember.Name = \"" + members[0] + "\")), 1).Item(0) : Tail(Filter({" + lQn + ".Members}, (" + lQn + ".CurrentMember.Name = \"" + members[1] + "\")), 1).Item(0)}"; + mdx = "Filter({" + lQn + ".Members}, (" + lQn + ".CurrentMember.Name >= \"" + members[0] + "\" AND " + lQn + ".CurrentMember.Name <= \"" + members[1] + "\"))"; + } else { + mdx = $.isArray(members) ? members.join("\" OR " + lQn + ".CurrentMember.Name = \"") : members; + mdx = "Filter({" + lQn + ".Members}, (" + lQn + ".CurrentMember.Name = \"" + mdx + "\"))"; + } + } + + if(exclude) + mdx = "Except(" + lQn + ".Members, " + mdx + ")"; + + if(mdx.indexOf(".[]") > -1 || mdx.indexOf(".[All]") > -1 || mdx.indexOf("\"All\"") > -1) + mdx = ""; + } + + return mdx; + } + + + myself.getMdx = function() { + // Levels of a same hierarchy have to be adjacent and in order of increasing depth! + + var dimensionHierarchies = []; + var pivotHierarchies = []; + var filterHierarchies = []; + + var pivotHierarchyBeforeMeasures = ""; + + var addLevelToHierarchy = function(levelObj, hierarchyObjs) { + var hierarchyIndex = $.map(hierarchyObjs, function(hierarchy, index) { + if(hierarchy.name == levelObj.hierarchy) + return index; + }); + if(hierarchyIndex.length > 0) { + hierarchyObjs[hierarchyIndex[0]].levels.push(levelObj); + } else { + hierarchyObjs.push({ + name: levelObj.hierarchy, + levels: new Array(levelObj) + }); + } + } + + $.each(definition.dimensions, function(i, v) { + var qualifiedName = v[0]; + var qnParts = qualifiedName.substring(1, qualifiedName.length -1).split("].["); + var hierarchy = qnParts[0]; + var level = qnParts.length < 2 ? "" : qnParts[1]; + + addLevelToHierarchy({ + hierarchy: hierarchy, + name: level, + qualifiedName: qualifiedName + }, dimensionHierarchies); + }); + + var previousHierarchyName = ""; + + $.each(definition.pivotDimensions, function(i, v) { + var qualifiedName = v[0]; + if(qualifiedName == "MEASURES") { + pivotHierarchyBeforeMeasures = i == 0 ? "NONE" : previousHierarchyName; + } else { + var qnParts = qualifiedName.substring(1, qualifiedName.length -1).split("].["); + var hierarchy = qnParts[0]; + var level = qnParts.length < 2 ? "" : qnParts[1]; + + addLevelToHierarchy({ + hierarchy: hierarchy, + name: level, + qualifiedName: qualifiedName + }, pivotHierarchies); + + previousHierarchyName = hierarchy; + } + }); + + var invalidHierarchies = $.map(dimensionHierarchies, function(e) { + return "[" + e.name + "]"; + }).concat($.map(pivotHierarchies, function(e) { + return "[" + e.name + "]"; + })); + + //console.log(invalidHierarchies); + + for(var key in filtersMap.hierarchies) { + if($.inArray(key, invalidHierarchies) < 0) { + var hierarchy = filtersMap.hierarchies[key]; + var levels = hierarchy.levels; + $.each(hierarchy.order, function(i, v) { + if(levels[v].filtered) { + var qn = v; + var qnParts = qn.substring(1, qn.length -1).split("].["); + var h = qnParts[0]; + var l = qnParts.length < 2 ? "" : qnParts[1]; + + addLevelToHierarchy({ + hierarchy: h, + name: l, + qualifiedName: qn + }, filterHierarchies); + } + }); + } + } + + //console.log(filterHierarchies); + + var getMdxCrossjoins = function(sets) { + var mdx = ""; + if(sets.length > 0) { + var _sets = sets.slice(); + if(_sets.length == 1) { + mdx = _sets[0]; + } else { + mdx = "Crossjoin(" + _sets.shift() + ", " + getMdxCrossjoins(_sets) + ")"; + } + } + return mdx; + } + + var mdx = []; + mdx["members"] = []; + mdx["sets"] = []; + mdx["columns"] = ""; + mdx["rows"] = ""; + mdx["cube"] = definition.cube; + mdx["slicer"] = ""; + + var mdxSets = []; + var mdxTotalMembers = []; + var mdxAxis = ""; + + $.each(dimensionHierarchies, function(i, hierarchy) { + var lastLevel = hierarchy.levels[hierarchy.levels.length-1]; + + if(settings.summary.grandTotal || settings.summary.subTotals) { + if(lastLevel.name == "") { + mdxTotalMembers.push("[" + lastLevel.hierarchy + "_" + lastLevel.name + "_Set]"); + } else { + mdx["members"].push("member [" + hierarchy.name + "].[BT_TOTAL] as 'Aggregate([" + lastLevel.hierarchy + "_" + lastLevel.name + "_Set])'"); + mdxTotalMembers.push("[" + hierarchy.name + "].[BT_TOTAL]"); + } + } + + var previousLevelName = []; + var previousLevelAllMembers = []; + + $.each(hierarchy.levels, function(j, level) { + var mdxFilteredSet = getMdxFilter(level.qualifiedName, "[" + hierarchy.name + "]"); + var mdxNamedSet = mdxFilteredSet == "" ? "{" + level.qualifiedName + ".Members}" : mdxFilteredSet; + + if(j > 0) { + var mdxConditions = []; + $.each(previousLevelName, function(k, previousLevelName) { + if(!previousLevelAllMembers[k]) + mdxConditions.push("(Exists(Ancestor([" + level.hierarchy + "].CurrentMember, [" + level.hierarchy + "].[" + previousLevelName + "]), [" + level.hierarchy + "_" + previousLevelName + "_Set]).Count > 0))"); + }); + + if(mdxConditions.length > 0) { + mdxNamedSet = "Filter(" + mdxNamedSet + ", "; + mdxNamedSet += "(" + mdxConditions.join(" AND ") + ")"; + mdxNamedSet += ")"; + } + } + + if(ordersMap.levels.hasOwnProperty(level.qualifiedName)) { + var order = ordersMap.levels[level.qualifiedName]; + var by = order.by; + if(by == "name") { + by = level.qualifiedName + ".CurrentMember.Name"; + } + var direction = order.dir; + mdxNamedSet = "Order(" + mdxNamedSet + ", " + by + ", " + direction + ")"; + } + + mdx["sets"].push("set [" + level.hierarchy + "_" + level.name + "_Set] as '" + mdxNamedSet + "'"); + + previousLevelName.push(level.name); + previousLevelAllMembers.push(mdxFilteredSet == "" ? true : false); + }); + + var mdxHierarchySet = "[" + lastLevel.hierarchy + "_" + lastLevel.name + "_Set]"; + if(hierarchy.levels.length > 1) + mdxHierarchySet = "Descendants(" + mdxHierarchySet + ", " + lastLevel.qualifiedName + ", SELF)"; + + if(settings.summary.subTotals && i > 0 && i == dimensionHierarchies.length - 1 && !ordersMap.axes.hasOwnProperty("dimensions")) { + if(settings.summary.position == "top") + mdxHierarchySet = "Union([" + hierarchy.name + "].[BT_TOTAL], " + mdxHierarchySet + ")"; + else if(settings.summary.position == "bottom") + mdxHierarchySet = "Union(" + mdxHierarchySet + ", [" + hierarchy.name + "].[BT_TOTAL])"; + } + + mdxSets.push(mdxHierarchySet); + }); + + + if(settings.summary.subTotals && !ordersMap.axes.hasOwnProperty("dimensions") && mdxSets.length > 2) { + var btTotals = mdxTotalMembers.slice(); + mdxAxis = "{?}"; + var i = 0; + for(i; i < mdxSets.length - 2; i++) { + btTotals.shift(); + mdxAxis = mdxAxis.replace("{?}", "Crossjoin(" + mdxSets[i] + ", Union({?}, " + getMdxCrossjoins(btTotals) + "))"); + } + mdxAxis = mdxAxis.replace("{?}", "Crossjoin(" + mdxSets[i] + ", " + mdxSets[i + 1] + ")"); + } else { + mdxAxis = getMdxCrossjoins(mdxSets); + } + + + if(ordersMap.axes.hasOwnProperty("dimensions")) { + var order = ordersMap.axes.dimensions; + var by = order.by; + if(by.indexOf("[Measures].[") < 0) + by = by + ".CurrentMember.Name"; + mdxAxis = "Order(" + mdxAxis + ", " + by + ", " + order.dir + ")"; + } + + if(settings.summary.grandTotal) { + if(settings.summary.position == "top") + mdxAxis = "Union(" + getMdxCrossjoins(mdxTotalMembers) + ", " + mdxAxis + ")"; + else if(settings.summary.position == "bottom") + mdxAxis = "Union(" + mdxAxis + ", " + getMdxCrossjoins(mdxTotalMembers) + ")"; + } + + if(settings.measuresOnColumns) + mdx["rows"] = mdxAxis; + else + mdx["columns"] = mdxAxis; + + + var mdxMeasuresSet = "{"; + $.each(definition.measures, function(i, v) { + if(i > 0) mdxMeasuresSet += ", "; + mdxMeasuresSet += v[0]; + }); + + mdxMeasuresSet += "}"; + + if(ordersMap.levels.hasOwnProperty("[Measures]")) { + var order = ordersMap.levels["[Measures]"]; + var by = order.by; + var direction = order.dir; + if(by == "name") { + mdxMeasuresSet = "Order(" + mdxMeasuresSet + ", [Measures].CurrentMember.Name, " + direction + ")"; + } + } + + + mdx["sets"].push("set [Measures_Set] as '" + mdxMeasuresSet + "'"); + + + mdxSets = []; + mdxTotalMembers = []; + + $.each(pivotHierarchies, function(i, hierarchy) { + var lastLevel = hierarchy.levels[hierarchy.levels.length-1]; + + if(settings.summary.pivotGrandTotal || settings.summary.pivotSubTotals) { + mdx["members"].push("member [" + hierarchy.name + "].[BT_TOTAL] as 'Aggregate([" + lastLevel.hierarchy + "_" + lastLevel.name + "_Set])'"); + mdxTotalMembers.push("[" + hierarchy.name + "].[BT_TOTAL]"); + } + + var previousLevelName = []; + var previousLevelAllMembers = []; + + $.each(hierarchy.levels, function(j, level) { + var mdxFilteredSet = getMdxFilter(level.qualifiedName, "[" + hierarchy.name + "]"); + var mdxNamedSet = mdxFilteredSet == "" ? "{" + level.qualifiedName + ".Members}" : mdxFilteredSet; + + if(j > 0) { + var mdxConditions = []; + $.each(previousLevelName, function(k, previousLevelName) { + if(!previousLevelAllMembers[k]) + mdxConditions.push("(Exists(Ancestor([" + level.hierarchy + "].CurrentMember, [" + level.hierarchy + "].[" + previousLevelName + "]), [" + level.hierarchy + "_" + previousLevelName + "_Set]).Count > 0))"); + }); + + if(mdxConditions.length > 0) { + mdxNamedSet = "Filter(" + mdxNamedSet + ", "; + mdxNamedSet += "(" + mdxConditions.join(" AND ") + ")"; + mdxNamedSet += ")"; + } + } + + if(ordersMap.levels.hasOwnProperty(level.qualifiedName)) { + var order = ordersMap.levels[level.qualifiedName]; + var by = order.by; + if(by == "name") { + by = level.qualifiedName + ".CurrentMember.Name"; + } + var direction = order.dir; + mdxNamedSet = "Order(" + mdxNamedSet + ", " + by + ", " + direction + ")"; + } + + mdx["sets"].push("set [" + level.hierarchy + "_" + level.name + "_Set] as '" + mdxNamedSet + "'"); + + previousLevelName.push(level.name); + previousLevelAllMembers.push(mdxFilteredSet == "" ? true : false); + }); + + var mdxHierarchySet = "[" + lastLevel.hierarchy + "_" + lastLevel.name + "_Set]"; + if(hierarchy.levels.length > 1) + mdxHierarchySet = "Descendants(" + mdxHierarchySet + ", " + lastLevel.qualifiedName + ", SELF)"; + + if(settings.summary.pivotSubTotals && (i > 0 || pivotHierarchyBeforeMeasures == "NONE") && i == pivotHierarchies.length - 1 && !ordersMap.axes.hasOwnProperty("measures")) { + if(settings.summary.position == "top") + mdxHierarchySet = "Union([" + hierarchy.name + "].[BT_TOTAL], " + mdxHierarchySet + ")"; + else if(settings.summary.position == "bottom") + mdxHierarchySet = "Union(" + mdxHierarchySet + ", [" + hierarchy.name + "].[BT_TOTAL])"; + } + + mdxSets.push(mdxHierarchySet); + }); + + + if(pivotHierarchyBeforeMeasures == "") { + mdxSets.push("[Measures_Set]"); + mdxTotalMembers.push("[Measures_Set]"); + } + else { + var measuresInsertionIndex = $.map(pivotHierarchies, function(hierarchy, index) { + if(hierarchy.name == pivotHierarchyBeforeMeasures) + return index + 1; + }); + if(measuresInsertionIndex.length == 0 && pivotHierarchyBeforeMeasures == "NONE") + measuresInsertionIndex = [0] + + mdxSets.splice(measuresInsertionIndex[0], 0, "[Measures_Set]"); + mdxTotalMembers.splice(measuresInsertionIndex[0], 0, "[Measures_Set]"); + } + + + if(definition.pivotDimensions.length > 0) { + + if(settings.summary.pivotSubTotals && !ordersMap.axes.hasOwnProperty("measures") && mdxSets.length > 2) { + var btTotals = mdxTotalMembers.slice(); + mdxAxis = "{?}"; + var i = 0; + for(i; i < mdxSets.length - 2; i++) { + btTotals.shift(); + mdxAxis = mdxAxis.replace("{?}", "Crossjoin(" + mdxSets[i] + ", Union({?}, " + getMdxCrossjoins(btTotals) + "))"); + } + mdxAxis = mdxAxis.replace("{?}", "Crossjoin(" + mdxSets[i] + ", " + mdxSets[i + 1] + ")"); + } else { + mdxAxis = getMdxCrossjoins(mdxSets); + } + + + if(ordersMap.axes.hasOwnProperty("measures")) { + var order = ordersMap.axes.measures; + var by = order.by; + if(by == "name") + by = "[Measures]"; + by += ".CurrentMember.Name"; + mdxAxis = "Order(" + mdxAxis + ", " + by + ", " + order.dir + ")"; + } + + if(settings.summary.pivotGrandTotal) { + if(settings.summary.position == "top") + mdxAxis = "Union(" + getMdxCrossjoins(mdxTotalMembers) + ", " + mdxAxis + ")"; + else if(settings.summary.position == "bottom") + mdxAxis = "Union(" + mdxAxis + ", " + getMdxCrossjoins(mdxTotalMembers) + ")"; + } + } else { + mdxAxis = "[Measures_Set]"; + + if(ordersMap.axes.hasOwnProperty("measures")) { + var order = ordersMap.axes.measures; + var by = order.by; + if(by == "name") { + by = "[Measures].CurrentMember.Name"; + mdxAxis = "Order(" + mdxAxis + ", " + by + ", " + order.dir + ")"; + } + } + } + + if(settings.measuresOnColumns) + mdx["columns"] = mdxAxis; + else + mdx["rows"] = mdxAxis; + + + mdxSets = []; + mdxTotalMembers = []; + + $.each(filterHierarchies, function(i, hierarchy) { + var previousLevelName = []; + var previousLevelAllMembers = []; + + $.each(hierarchy.levels, function(j, level) { + var mdxFilteredSet = getMdxFilter(level.qualifiedName, "[" + hierarchy.name + "]"); + var mdxNamedSet = mdxFilteredSet == "" ? "{" + level.qualifiedName + ".Members}" : mdxFilteredSet; + + if(j > 0) { + var mdxConditions = []; + $.each(previousLevelName, function(k, previousLevelName) { + if(!previousLevelAllMembers[k]) + mdxConditions.push("(Exists(Ancestor([" + level.hierarchy + "].CurrentMember, [" + level.hierarchy + "].[" + previousLevelName + "]), [" + level.hierarchy + "_" + previousLevelName + "_Set]).Count > 0))"); + }); + + if(mdxConditions.length > 0) { + mdxNamedSet = "Filter(" + mdxNamedSet + ", "; + mdxNamedSet += "(" + mdxConditions.join(" AND ") + ")"; + mdxNamedSet += ")"; + } + } + + mdx["sets"].push("set [" + level.hierarchy + "_" + level.name + "_Set] as '" + mdxNamedSet + "'"); + + previousLevelName.push(level.name); + previousLevelAllMembers.push(mdxFilteredSet == "" ? true : false); + }); + + var levelSets = $.map(hierarchy.levels, function(level) { + return "[" + level.hierarchy + "_" + level.name + "_Set]"; + }); + + var mdxHierarchySet = "{" + levelSets[levelSets.length - 1] + "}"; + + mdxSets.push(mdxHierarchySet); + }); + + mdx["slicer"] = getMdxCrossjoins(mdxSets); + + + var mdxQuery = "with "; + mdxQuery += mdx["sets"].join(" ") + " "; + mdxQuery += mdx["members"].join(" ") + " "; + mdxQuery += "select" + (settings.nonEmpty.columns ? " NON EMPTY" : "") + " " + mdx["columns"] + " on COLUMNS,"; + mdxQuery += (settings.nonEmpty.rows ? " NON EMPTY" : "") + " " + mdx["rows"] + " on ROWS "; + mdxQuery += "from [" + mdx["cube"] + "]"; + mdxQuery += mdx["slicer"] != "" ? " where (" + mdx["slicer"] + ")" : ""; + + + return mdxQuery; + } + + + myself.putMeasuresOnColumns = function() { + settings.measuresOnColumns = true; + } + + myself.putMeasuresOnRows = function() { + settings.measuresOnColumns = false; + } + + myself.hasMeasuresOnColumns = function() { + return settings.measuresOnColumns; + } + + myself.hasPivotDimensions = function() { + if(definition.pivotDimensions.length == 0 || (definition.pivotDimensions.length == 1 && definition.pivotDimensions[0][0] == "MEASURES")) + return false; + else + return true; + } + + + myself.getDimensionQualifiedNames = function() { + return $.map(definition.dimensions, function(i) {return i[0]}); + } + + myself.getPivotDimensionQualifiedNames = function() { + return $.map(definition.pivotDimensions, function(i) {return i[0]}); + } + + myself.getMeasureQualifiedNames = function() { + return $.map(definition.measures, function(i) {return i[0]}); + } + + myself.getFilterQualifiedNames = function() { + return $.map(definition.filters, function(i) {return i[0]}); + } + + + myself.getCube = function() { + return definition.cube; + } + + myself.getFilters = function() { + var filters = []; + + var invalidHierarchies = $.map(myself.getDimensionQualifiedNames(), function(e) { + return (e.split("].[")[0] + "]").replace("]]", "]"); + }).concat($.map(myself.getPivotDimensionQualifiedNames(), function(e) { + return (e.split("].[")[0] + "]").replace("]]", "]"); + })); + + var boundToDashboard = filtersMap.synchronizedByParameters; + + for(var key in filtersMap.hierarchies) { + if($.inArray(key, invalidHierarchies) < 0) { + var hierarchy = filtersMap.hierarchies[key]; + var levels = hierarchy.levels; + $.each(hierarchy.order, function(i, v) { + var level = levels[v]; + if(level.filtered) { + var qn = v; + var filterMode = level.filterMode; + if(level.uniqueNames) filterMode += "_un"; + var members = null; + + if(boundToDashboard && level.synchronizedByParameters) { + var filterExpression = level.initialFilterExpression; + var param = filterExpression.replace(filterMode + ":", ""); + var members = Dashboards.getParameterValue(param); + } else { + members = level.members; + } + + var plainFilter = filterMode + ":[" + ( $.isArray(members) ? members.join("],[") : members ) + "]"; + var filter = [qn, plainFilter]; + + filters.push(filter); + } + }); + } + } + + return filters; + } + + myself.getDimensions = function() { + var dimensions = []; + $.each(definition.dimensions, function(i, v) { + var qn = v[0]; + var arr = [qn, myself.getPlainFilter(qn)]; + dimensions.push(arr); + }); + return dimensions; + } + + myself.getPivotDimensions = function() { + var pivotDimensions = []; + $.each(definition.pivotDimensions, function(i, v) { + var qn = v[0]; + var fe = qn == "MEASURES" ? "" : myself.getPlainFilter(qn); + var arr = [qn, fe]; + pivotDimensions.push(arr); + }); + return pivotDimensions; + } + + myself.getMeasures = function() { + return definition.measures; + } + + myself.setMeasures = function(measures) { + definition.measures = measures; + } + + myself.set = function(properties) { + $.extend(true, settings, properties); + } + + myself.getSettings = function() { + return settings; + } + + myself.isRemovable = function(qualifiedName, type) { + var removable = true; + + if(type == "D") { + removable = definition.dimensions.length > 1; + + if(removable) { + // prevent removing a dimension level if there is only one hierarchy in the axis + // and moving all the levels of this hierarchy in filters make this axis empty! + var hierarchies = _.uniq($.map(myself.getDimensionQualifiedNames(), function(e) { + return (e.split("].[")[0] + "]").replace("]]", "]"); + })); + + if(hierarchies.length == 1) { + if(filtersMap.hierarchies[hierarchies[0]].levels[qualifiedName].filtered) + removable = false; + } + } + } + else if(type == "M") { + removable = definition.measures.length > 1; + } + + return removable; + } + + myself.remove = function(qualifiedName, type) { + var removedElements = undefined; + + var hierarchy = (qualifiedName.split("].[")[0] + "]").replace("]]", "]"); + + var axis = []; + var axisQualifiedNames = []; + + if(type == "D") { + axis = definition.dimensions; + axisQualifiedNames = myself.getDimensionQualifiedNames(); + } + else if(type == "M") { + axis = definition.measures; + axisQualifiedNames = myself.getMeasureQualifiedNames(); + } + else if(type == "P") { + axis = definition.pivotDimensions; + axisQualifiedNames = myself.getPivotDimensionQualifiedNames(); + } + + var index = -1; + var length = 0; + + // also remove all other levels of the same hierarchy if the target level is filtered! + if(type != "M" && filtersMap.hierarchies[hierarchy].levels[qualifiedName].filtered) { + var hierarchies = $.map(axisQualifiedNames, function(e) { + return (e.split("].[")[0] + "]").replace("]]", "]"); + }); + var indexes = []; + $.each(hierarchies, function(i, v) { + if(v == hierarchy) indexes.push(i); + }); + + //console.log(indexes.toSource()); + + index = indexes[0]; + length = indexes.length; + } else { + index = axisQualifiedNames.indexOf(qualifiedName); + length = 1; + } + + if(index >= 0) + removedElements = axis.splice(index, length); + + myself.clearSort(qualifiedName, (length > 1 ? true : false)); + } + + myself.add = function(newQualifiedName, targetQualifiedName, position, type) { + var hierarchy = (newQualifiedName.split("].[")[0] + "]").replace("]]", "]"); + + var axis = []; + var axisQualifiedNames = []; + + if(type == "D") { + axis = definition.dimensions; + axisQualifiedNames = myself.getDimensionQualifiedNames(); + } + else if(type == "M") { + axis = definition.measures; + axisQualifiedNames = myself.getMeasureQualifiedNames(); + } + else if(type == "P") { + axis = definition.pivotDimensions; + if($.inArray("MEASURES", myself.getPivotDimensionQualifiedNames()) < 0) + axis.splice(0, 0, ["MEASURES", ""]); + axisQualifiedNames = myself.getPivotDimensionQualifiedNames(); + } + + var index = $.inArray(targetQualifiedName, axisQualifiedNames); + + // also add all other levels of the same hierarchy if they are filtered and they aren't in the axis! + var hierarchies = $.map(axisQualifiedNames, function(e) { + return (e.split("].[")[0] + "]").replace("]]", "]"); + }); + + if(type != "M" && $.inArray(hierarchy, hierarchies) < 0) { + var fmHierarchy = filtersMap.hierarchies[hierarchy]; + var fmLevels = fmHierarchy.levels; + + var elementsToInsert = []; + + $.each(fmHierarchy.order, function(i, v) { + if(fmLevels[v].filtered || v == newQualifiedName) + elementsToInsert.push("[\"" + v + "\", \"\"]"); + }); + + if(index >= 0) { + if(position == 1) + index++; + + eval("axis.splice(index, 0, " + elementsToInsert.join(", ") + ")"); + } + } else { + var elementToInsert = [newQualifiedName, ""]; + if(index >= 0) { + if(position == 1) + index++; + axis.splice(index, 0, elementToInsert); + } + } + } + + myself.isReplaceable = function(newQualifiedName, oldQualifiedName, type) { + var replaceable = true; + + if(type != "M") { + var newHierarchy = (newQualifiedName.split("].[")[0] + "]").replace("]]", "]"); + var oldHierarchy = (oldQualifiedName.split("].[")[0] + "]").replace("]]", "]"); + + if(newHierarchy == oldHierarchy && filtersMap.hierarchies[oldHierarchy].levels[oldQualifiedName].filtered) + replaceable = false; + } + + return replaceable; + } + + myself.replace = function(newQualifiedName, oldQualifiedName, position, type) { + var hasNewPosition = position != null; + var closeQualifiedName = hasNewPosition ? position.level : oldQualifiedName; + var direction = hasNewPosition ? position.direction : 1; + + var axis = []; + var axisQualifiedNames = []; + + if(type == "D") { + axis = definition.dimensions; + axisQualifiedNames = myself.getDimensionQualifiedNames(); + } + else if(type == "M") { + axis = definition.measures; + axisQualifiedNames = myself.getMeasureQualifiedNames(); + } + else if(type == "P") { + axis = definition.pivotDimensions; + axisQualifiedNames = myself.getPivotDimensionQualifiedNames(); + } + + //console.log("Add " + newQualifiedName + " to the " + (direction == 1 ? "right of " : "left of ") + closeQualifiedName + ". Then remove " + oldQualifiedName); + + myself.add(newQualifiedName, closeQualifiedName, direction, type); + myself.remove(oldQualifiedName, type); + + if(type != "M") { + var newLevelHierarchy = (newQualifiedName.split("].[")[0] + "]").replace("]]", "]"); + var oldLevelHierarchy = (oldQualifiedName.split("].[")[0] + "]").replace("]]", "]"); + var closeLevelHierarchy = (closeQualifiedName.split("].[")[0] + "]").replace("]]", "]"); + if(closeQualifiedName != oldQualifiedName && closeLevelHierarchy == oldLevelHierarchy && newLevelHierarchy != oldLevelHierarchy) { + // positioning correction + var headElements = []; + var tailElements = []; + var newHierarchyElements = []; + var oldHierarchyElements = []; + var newHierarchyFound = false; + $.each(axis, function(i, v) { + var l = v[0]; + var h = (l.split("].[")[0] + "]").replace("]]", "]"); + var e = "[\"" + l + "\", \"\"]"; + if(h == oldLevelHierarchy) { + oldHierarchyElements.push(e); + } + else if(h == newLevelHierarchy) { + newHierarchyElements.push(e); + newHierarchyFound = true; + } + else { + if(!newHierarchyFound) + headElements.push(e); + else + tailElements.push(e); + } + }); + var newAxis = headElements.concat(newHierarchyElements, oldHierarchyElements, tailElements); + eval("axis.splice(0, axis.length, " + newAxis.join(", ") + ")"); + } + } + } + + + var filtersMap = { + synchronizedByParameters: true, + hierarchies: [] + }; + + if(olapCube) { + var hierarchies = olapCube.getHierarchies(); + $.each(hierarchies, function(i, v) { + var levels = []; + var order = []; + $.each(v.levels, function(j, w) { + var qualifiedName = w.qualifiedName; + levels[qualifiedName] = { + depth: w.depth, + initialFilterExpression: "", + synchronizedByParameters: false, + filterMode: "", + uniqueNames: false, + members: [], + filtered: false + } + order.push(qualifiedName); + }); + filtersMap.hierarchies[v.qualifiedName] = { + levels: levels, + order: order, + calculatedMembers: { + initialFilterExpression: "", + synchronizedByParameters: false, + filterMode: "", + //uniqueNames: false, + members: [], + filtered: false + } + } + }); + } + + var initializeFiltersMap = function(axis) { + $.each(axis, function(i, v) { + var lvlQn = v[0]; + var fltExpr = v[1]; + if(fltExpr != "") { + if(lvlQn.indexOf("].[") < 0) { + var hrcQn = lvlQn; + var synchronizedByParameters = fltExpr.indexOf("[") < 0; + var filterMode = synchronizedByParameters ? fltExpr.split(":")[0] : fltExpr.split(":[")[0]; + var membersString = synchronizedByParameters ? "" : fltExpr.replace(filterMode + ":", ""); + var calculatedMembers = filtersMap.hierarchies[hrcQn].calculatedMembers; + calculatedMembers.initialFilterExpression = fltExpr; + calculatedMembers.synchronizedByParameters = synchronizedByParameters; + calculatedMembers.filterMode = filterMode; + calculatedMembers.members = synchronizedByParameters ? [] : membersString.substring(1, membersString.length - 1).split("],["); + calculatedMembers.filtered = true; + } else { + var hrcQn = lvlQn.split("].[")[0] + "]"; + var levels = filtersMap.hierarchies[hrcQn].levels; + var synchronizedByParameters = fltExpr.indexOf("[") < 0; + var filterMode = synchronizedByParameters ? fltExpr.split(":")[0] : fltExpr.split(":[")[0]; + var membersString = synchronizedByParameters ? "" : fltExpr.replace(filterMode + ":", ""); + var level = filtersMap.hierarchies[hrcQn].levels[lvlQn]; + level.initialFilterExpression = fltExpr; + level.synchronizedByParameters = synchronizedByParameters; + level.filterMode = filterMode.replace("_un", ""); + level.uniqueNames = filterMode.indexOf("_un") > -1; + level.members = synchronizedByParameters ? [] : membersString.substring(1, membersString.length - 1).split("],["); + level.filtered = true; + } + } + }); + } + + initializeFiltersMap(definition.dimensions); + initializeFiltersMap(definition.pivotDimensions); + initializeFiltersMap(definition.filters); + + myself.getFiltersMap = function() { + return filtersMap; + } + + myself.synchronizeFiltersWithParameters = function(state) { + filtersMap.synchronizedByParameters = state; + } + + myself.isSynchronizedByParameters = function() { + return filtersMap.synchronizedByParameters; + } + + myself.setFiltersMap = function(hierarchyQualifiedName, levelQualifiedName, filter) { + $.extend(filtersMap.hierarchies[hierarchyQualifiedName].levels[levelQualifiedName], filter); + } + + + var ordersMap = { + axes: {}, + levels: [] + }; + + var initializeOrdersMap = function() { + $.each(definition.orders, function(i, v) { + var arg = v[0]; + var valueParts = v[1].split("::"); + var rule = {by: valueParts[0], dir: valueParts[1]}; + + if(arg == "D") + ordersMap.axes.dimensions = rule; + else if(arg == "M") + ordersMap.axes.measures = rule; + else + ordersMap.levels[arg] = rule; + }); + } + + initializeOrdersMap(); + + myself.getOrdersMap = function() { + return ordersMap; + } + + myself.getSortDirection = function(target, qualifiedName) { + var direction = ""; + if(target == "D") { + if(ordersMap.axes.hasOwnProperty("dimensions")) { + var order = ordersMap.axes.dimensions; + if(order.by == qualifiedName) + direction = order.dir; + } + } + else if(target == "M") { + if(ordersMap.axes.hasOwnProperty("measures")) { + var order = ordersMap.axes.measures; + if(order.by == qualifiedName) + direction = order.dir; + } + } + /*else { + + }*/ + return direction; + } + + myself.sort = function(target, by, direction) { + var removeSort = by == ""; + + if(target == "D") { + if(removeSort) + delete ordersMap.axes.dimensions; + else + ordersMap.axes.dimensions = {by: by, dir: direction}; + } + else if(target == "M") { + if(removeSort) + delete ordersMap.axes.measures; + else + ordersMap.axes.measures = {by: by, dir: direction}; + } + } + + myself.clearSort = function(qualifiedName, hierarchyRemoval) { + var hierarchy = (qualifiedName.split("].[")[0] + "]").replace("]]", "]"); + + if(ordersMap.axes.hasOwnProperty("dimensions") && ( + (!hierarchyRemoval && ordersMap.axes.dimensions.by == qualifiedName) || + (hierarchyRemoval && ordersMap.axes.dimensions.by.indexOf(hierarchy) == 0) + )) + delete ordersMap.axes.dimensions; + + else if(ordersMap.axes.hasOwnProperty("measures") && ( + (!hierarchyRemoval && ordersMap.axes.measures.by == qualifiedName) || + (hierarchyRemoval && ordersMap.axes.measures.by.indexOf(hierarchy) == 0) + )) + delete ordersMap.axes.measures; + + if(hierarchyRemoval) { + for(key in ordersMap.levels) { + if(key.indexOf(hierarchy) == 0) + delete ordersMap.levels[key]; + } + } else { + if(ordersMap.levels.hasOwnProperty(qualifiedName)) + delete ordersMap.levels[qualifiedName]; + } + } + + return myself; +} diff --git a/resources/components/BTable/lib/bt.table.js b/resources/components/BTable/lib/bt.table.js new file mode 100644 index 0000000..93dcf49 --- /dev/null +++ b/resources/components/BTable/lib/bt.table.js @@ -0,0 +1,3079 @@ +/* + * Copyright 2013 Biz Tech (http://www.biztech.it). All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * Covered Software is provided under this License on an “as is” basis, + * without warranty of any kind, either expressed, implied, or statutory, + * including, without limitation, warranties that the Covered Software is + * free of defects, merchantable, fit for a particular purpose or non-infringing. + * The entire risk as to the quality and performance of the Covered Software is with You. + * Should any Covered Software prove defective in any respect, You (not any Contributor) + * assume the cost of any necessary servicing, repair, or correction. + * This disclaimer of warranty constitutes an essential part of this License. + * No use of any Covered Software is authorized under this License except under this disclaimer. + * + * Initial contributors: Luca Pazzaglia, Massimo Bonometto + */ + + +var bt = bt || {}; +bt.components = bt.components || {}; + +bt.components.BTable = function(spec) { + + var defaults = { + componentName: "BTable", + componentHtmlObject: "", + catalog: "", + jndi: "", + cube: "", + dimensions: [], + measures: [], + pivotDimensions: [], + filters: [], + measuresOnColumns: true, + orderBy: [], + nonEmptyRows: true, + nonEmptyColumns: true, + grandTotal: false, + subTotals: false, + pivotGrandTotal: false, + pivotSubTotals: false, + totalsPosition: "bottom", + hideSpans: false, + showFilters: true, + exportStyle: {} + }; + + var myself = {}; + + myself.properties = $.extend({}, defaults, spec); + + myself.properties.filtersPanelHtmlObject = myself.properties.componentHtmlObject + "FiltersPanel"; + $("#" + myself.properties.componentHtmlObject).before(""); + + myself.olapCube = new bt.olap.OlapCube({ + catalog: myself.properties.catalog, + cube: myself.properties.cube + }); + + myself.query = new bt.Query({ + cube: myself.properties.cube, + dimensions: myself.properties.dimensions, + measures: myself.properties.measures, + pivotDimensions: myself.properties.pivotDimensions, + filters: myself.properties.filters, + measuresOnColumns: myself.properties.measuresOnColumns, + nonEmpty: { + columns: myself.properties.nonEmptyColumns, + rows: myself.properties.nonEmptyRows + }, + summary: { + grandTotal: myself.properties.grandTotal, + subTotals: myself.properties.subTotals, + pivotGrandTotal: myself.properties.pivotGrandTotal, + pivotSubTotals: myself.properties.pivotSubTotals, + position: myself.properties.totalsPosition + }, + orders: myself.properties.orderBy + }, myself.olapCube); + + var normalizedCdaResult = {}; + + myself.normalizeCdaJson = function(json) { + var normalizedJson = json; + + var hasMoC = myself.query.hasMeasuresOnColumns(); + var dimensionQualifiedNames = myself.query.getDimensionQualifiedNames(); + var pivotDimensionQualifiedNames = myself.query.getPivotDimensionQualifiedNames(); + var measureQualifiedNames = myself.query.getMeasureQualifiedNames(); + + var unwantedColumns = []; + normalizedJson.metadata = $.grep(json.metadata, function (i) { + // remove *.[(All)] columns generated by CDA when classic BandedMode + // remove not required hierarchy levels when MoC (their columns are generated by + // Hierarchize or Descendants MDX functions + + var colName = i.colName; + var remove = colName.endsWith("[(All)]") || ( + colName.indexOf("]/[") < 0 && ( + (hasMoC && $.inArray(colName, dimensionQualifiedNames) < 0 + && $.inArray(colName, measureQualifiedNames) < 0) || + (!hasMoC && colName != "[Measures].[MeasuresLevel]" + && $.inArray(colName, pivotDimensionQualifiedNames) < 0 + && $.inArray(colName.split("].[")[0], $.map(dimensionQualifiedNames, function(e){ return e.split("].[")[0]; })) < 0 + && $.inArray("[" + colName.split("].[")[1], $.map(dimensionQualifiedNames, function(e){ return e.split("].[")[0]; })) < 0) + ) + ); + + if(remove) unwantedColumns.push(i.colIndex); + return !remove; + }); + $.each(json.resultset, function(i, v) { + normalizedJson.resultset[i] = $.grep(v, function(o, j) { + return $.inArray(j, unwantedColumns) < 0; + }); + }); + + $.each(normalizedJson.metadata, function(i, v) { + var colName = v.colName; + if(colName.indexOf("]/[") > 0 || $.inArray(colName, measureQualifiedNames) >= 0) { + v.colType = "numeric"; + } else { + if(colName != "[Measures].[MeasuresLevel]" && $.inArray(colName, dimensionQualifiedNames) < 0 && $.inArray(colName, pivotDimensionQualifiedNames) < 0) + v.colType = "numeric"; + else + v.colType = "string"; + } + }); + + normalizedCdaResult = normalizedJson; + + return normalizedJson; + } + + var headers = []; + var oldHeaders = [] + + myself.getHeaders = function() { + return headers; + } + + myself.setHeaders = function(cdaHeaders) { + headers = []; + + var getCaption = function(value) { + var caption = ""; + if(value == "[Measures].[MeasuresLevel]") + caption = "Measures"; + else if(value == "BT_TOTAL") + caption = "Total"; + else if(value.indexOf("].[") > -1) + caption = myself.olapCube.getElementName(value); + else + caption = value; + return caption; + } + + var getLevel = function(qualifiedName, memberName) { + var level = ""; + if(memberName.indexOf("].[") > -1) + level = memberName; + else { + if(qualifiedName == "[Measures].[]") + level = "[Measures].[" + memberName + "]"; + else + level = qualifiedName; + } + return level; + } + + var getHeaderRow = function(qualifiedName, uncompressedMembersList, isLastRow, rowSpans) { + + var compressedMembersList = []; + if(isLastRow || myself.properties.hideSpans) { + $.each(uncompressedMembersList, function(i, value) { + compressedMembersList.push({ + level: getLevel(qualifiedName, value), + member: value, + caption: getCaption(value), + colspan: 1, + rowspan: myself.properties.hideSpans ? 1 : rowSpans[i] + }); + }); + } else { + var count = 0; + var previousValue = ""; + var previousRowSpan = 0; + $.each(uncompressedMembersList, function(i, value) { + if((value != previousValue && previousValue != "") || (value == previousValue && rowSpans[i] != previousRowSpan)) { + compressedMembersList.push({ + level: getLevel(qualifiedName, previousValue), + member: previousValue, + caption: getCaption(previousValue), + colspan: count, + rowspan: previousRowSpan + }); + count = 0; + } + previousValue = value; + previousRowSpan = rowSpans[i]; + count++; + }); + compressedMembersList.push({ + level: getLevel(qualifiedName, previousValue), + member: previousValue, + caption: getCaption(previousValue), + colspan: count, + rowspan: previousRowSpan + }); + } + + compressedMembersList = $.grep(compressedMembersList, function(e, i) { + return e.rowspan > 0; + }); + + return compressedMembersList; + } + + var querySetting = myself.query.getSettings(); + + if(!querySetting.measuresOnColumns) { + + var splittedCdaHeaders = []; + $.each(cdaHeaders, function(i, v) { + var splittedHeader = v.split("]/["); + var length = splittedHeader.length; + if(length > 1) { + splittedHeader[0] += "]"; + for(j = 1; j < length-1; j++) { + splittedHeader[j] = "[" + splittedHeader[j] + "]"; + } + splittedHeader[length-1] = "[" + splittedHeader[length-1]; + } + splittedCdaHeaders.push(splittedHeader); + }); + + + var lastElementIndex = splittedCdaHeaders.length - 1; + + var dimensionQualifiedNames = myself.query.getDimensionQualifiedNames(); + var pivotDimensionQualifiedNames = myself.query.getPivotDimensionQualifiedNames(); + + var hh = new Array(); + var levelQualifiedNames = dimensionQualifiedNames.slice().reverse(); + var previousHierarchy = ""; + var maxLevelDepth = 1; + for(i = 0; i < levelQualifiedNames.length; i++) { + var levelQualifiedName = levelQualifiedNames[i]; + + var hierarchy = levelQualifiedName.split("].[")[0].substring(1); + + if(levelQualifiedName.indexOf("].[") < 0) + hierarchy = hierarchy.substring(0, hierarchy.length-1); + + var index = -1; + $.each(splittedCdaHeaders[lastElementIndex], function(j, w) { + if(w.indexOf("[" + hierarchy + "]") > -1 || w.indexOf("[" + hierarchy + "." + hierarchy + "]") > -1) { + index = j; + return; + } + }); + + + hh[levelQualifiedName] = []; + + if(index >= 0) { + + for(j = 0; j < splittedCdaHeaders.length; j++) { + var member = splittedCdaHeaders[j][0]; + if(splittedCdaHeaders[j].length > 1 || (member != "[Measures].[MeasuresLevel]" && $.inArray(member, pivotDimensionQualifiedNames) < 0)) { + var memberUniqueNameParts = splittedCdaHeaders[j][index].split("].[").reverse(); + member = memberUniqueNameParts[0]; + member = member.substring(0, member.length-1); + if(hierarchy == previousHierarchy && member != "BT_TOTAL") { + member = memberUniqueNameParts[maxLevelDepth - myself.olapCube.getLevelDepth(levelQualifiedName)]; + } + } + hh[levelQualifiedName].push(member); + } + + if(hierarchy != previousHierarchy) { + previousHierarchy = hierarchy; + maxLevelDepth = myself.olapCube.getLevelDepth(levelQualifiedName); + } + + } + + } + + + var ohh = new Array(); + + $.each(dimensionQualifiedNames, function(i, v) { + if(hh[v].length > 0) + ohh.push(hh[v]); + }); + + var ors = new Array(ohh.length); + + for(i = 0; i < ohh.length; i++) { + ors[i] = new Array(ohh[i].length); + } + + + $.each(ohh, function(i, row) { + $.each(row, function(j, v) { + if(ors[i][j] != 0) { + ors[i][j] = 1; + count = 1; + var stop = false; + for(k = i + 1; k < ohh.length && !stop; k++) { + if(ohh[k][j] == v) { + count++; + ors[k][j] = 0; + } + else + stop = true; + } + ors[i][j] = count; + } + }); + }); + + + var newIndex = -1; + $.each(dimensionQualifiedNames, function(i, v) { + newIndex++; + if(hh[v].length > 0) { + //console.log(v + " @ " + newIndex); + headers.push(getHeaderRow(v, hh[v], newIndex == ohh.length - 1, ors[newIndex])); + } + else + newIndex--; + }); + + } + + else { + var splittedCdaHeaders = []; + $.each(cdaHeaders, function(i, v) { + var splittedHeader = v.split("]/["); + var length = splittedHeader.length; + if(length > 1) { + splittedHeader[0] += "]"; + for(j = 1; j < length-1; j++) { + splittedHeader[j] = "[" + splittedHeader[j] + "]"; + } + splittedHeader[length-1] = "[" + splittedHeader[length-1]; + } + splittedCdaHeaders.push(splittedHeader); + }); + + + var lastElementIndex = splittedCdaHeaders.length - 1; + + var hh = new Array(); + + var pivotDimensionQualifiedNames = myself.query.getPivotDimensionQualifiedNames(); + if($.inArray("MEASURES", pivotDimensionQualifiedNames) < 0) + pivotDimensionQualifiedNames.push("[Measures].[]"); + else + pivotDimensionQualifiedNames = $.map(pivotDimensionQualifiedNames, function(qn) { + return qn == "MEASURES" ? "[Measures].[]" : qn; + }); + + var levelQualifiedNames = pivotDimensionQualifiedNames.slice().reverse(); //slice() to copy the array + var previousHierarchy = ""; + var maxLevelDepth = 1; + for(i = 0; i < levelQualifiedNames.length; i++) { + var levelQualifiedName = levelQualifiedNames[i]; + var hierarchy = levelQualifiedName.split("].[")[0].substring(1); + + var index = -1; + $.each(splittedCdaHeaders[lastElementIndex], function(j, w) { + if(w.indexOf("[" + hierarchy + "]") > -1 || w.indexOf("[" + hierarchy + "." + hierarchy + "]") > -1) { + index = j; + return; + } + }); + + + hh[levelQualifiedName] = []; + + if(index >= 0) { + + for(j = 0; j < splittedCdaHeaders.length; j++) { + var member = splittedCdaHeaders[j][0]; + if(splittedCdaHeaders[j].length > 1) { + var memberUniqueNameParts = splittedCdaHeaders[j][index].split("].[").reverse(); + member = memberUniqueNameParts[0]; + member = member.substring(0, member.length-1); + if(hierarchy == previousHierarchy && member != "BT_TOTAL") { + member = memberUniqueNameParts[maxLevelDepth - myself.olapCube.getLevelDepth(levelQualifiedName)]; + } + } + //console.log(levelQualifiedName + " -> " + member); + hh[levelQualifiedName].push(member); + } + + if(hierarchy != previousHierarchy) { + previousHierarchy = hierarchy; + maxLevelDepth = myself.olapCube.getLevelDepth(levelQualifiedName); + } + + } + + } + + + var ohh = new Array(); + + $.each(pivotDimensionQualifiedNames, function(i, v) { + if(hh[v].length > 0) + ohh.push(hh[v]); + }); + + var ors = new Array(ohh.length); + + for(i = 0; i < ohh.length; i++) { + ors[i] = new Array(ohh[i].length); + } + + + $.each(ohh, function(i, row) { + $.each(row, function(j, v) { + if(ors[i][j] != 0) { + ors[i][j] = 1; + count = 1; + var stop = false; + for(k = i + 1; k < ohh.length && !stop; k++) { + if(ohh[k][j] == v) { + count++; + ors[k][j] = 0; + } + else + stop = true; + } + ors[i][j] = count; + } + }); + }); + + + var newIndex = -1; + $.each(pivotDimensionQualifiedNames, function(i, v) { + newIndex++; + if(hh[v].length > 0) { + //console.log(v + " @ " + newIndex); + headers.push(getHeaderRow(v, hh[v], newIndex == ohh.length - 1, ors[newIndex])); + } + else + newIndex--; + }); + + } + + + } + + + myself.getElementType = function(qualifiedName) { + if(qualifiedName == "[Measures].[MeasuresLevel]") + return "MEASURES_LEVEL"; + var result = $.grep(myself.query.getDimensionQualifiedNames(), function(e, i) { return e == qualifiedName }); + if(result.length > 0) + return "DIMENSION"; + result = $.grep(myself.query.getPivotDimensionQualifiedNames(), function(e, i) { return e == qualifiedName }); + if(result.length > 0) + return "PIVOT_DIMENSION"; + result = $.grep(myself.query.getMeasureQualifiedNames(), function(e, i) { return e == qualifiedName }); + if(result.length > 0) + return "MEASURE"; + result = $.grep(myself.query.getFilterQualifiedNames(), function(e, i) { return e == qualifiedName }); + if(result.length > 0) + return "FILTER"; + if(myself.olapCube.getElementType(qualifiedName) != undefined) + return "CALCULATED_MEMBER"; + return ""; + }; + + myself.getMenuTitle = function(btRef) { + var title = ""; + + var level = btRef.level; + var member = btRef.member; + + var qualifiedName = btRef.level; + if(level.indexOf("].[") < 0) + qualifiedName += ".[" + member + "]"; + + if(qualifiedName == "[Measures].[MeasuresLevel]") + title = "Measures"; + else { + var fullNameParts = myself.olapCube.getElementFullName(qualifiedName).split(" -> "); + if(fullNameParts[0] != fullNameParts[1]) + title += fullNameParts[0] + " -> "; + title += fullNameParts[1]; + } + + if(member != level && level.indexOf("].[") > -1 && (level.indexOf("[Measures]") < 0 || "[Measures].[" + member + "]" != level)) + title += "
" + (member == "BT_TOTAL" ? "Total" : (member == null ? "NULL" : (!isNaN(parseFloat(member)) && member.toString().indexOf(" ") < 0 && !btRef.colspan ? sprintf(/*"%.2f"*/"%d", member) : member))); + + return title; + }; + + myself.getMeasures = function() { + return myself.query.getMeasures(); + }; + + myself.setMeasures = function(measures) { + myself.query.setMeasures(measures); + }; + + myself.enableGrandTotal = function() { + myself.query.set({summary: { + grandTotal: true + }}); + }; + + myself.disableGrandTotal = function() { + myself.query.set({summary: { + grandTotal: false + }}); + }; + + myself.hasMeasuresOnColumns = function() { + return myself.query.hasMeasuresOnColumns(); + }; + + myself.printFilters = function() { + var dimensions = $.grep(myself.query.getDimensions(), function(e) { + return e[1] != "" && e[0].indexOf("].[") > 0; + }); + var pivotDimensions = $.grep(myself.query.getPivotDimensions(), function(e) { + return e[1] != "" && e[0].indexOf("].[") > 0; + }); + var filters = myself.query.getFilters(); + + + var html = ""; + + var previousHierarchy = ""; + + $.each(dimensions, function(i, v) { + var qualifiedName = v[0]; + var plainFilter = v[1]; + var hierarchy = qualifiedName.split("].[")[0].substring(1).replace("]", ""); + + var name = myself.olapCube.getElementName(qualifiedName); + + var filterParts = plainFilter.split(":["); + var filterMode = filterParts[0].replace("_un", ""); + var prettyFilter = filterParts[1]; + prettyFilter = prettyFilter.substring(0, prettyFilter.length-1); + if(prettyFilter.indexOf("].[") < 0) + prettyFilter = prettyFilter.split("],[").join(" , "); + else { + prettyFilter = $.map(prettyFilter.split("],["), function(e) { + var parts = e.split("].["); + parts = parts.slice(1); + return "[" + parts.join("].["); + }).join(" , "); + } + + if(filterMode == "exclude") + prettyFilter = "all except " + prettyFilter; + else if(filterMode == "between") + prettyFilter = "between " + prettyFilter.replace(" , ", " and "); + + if(hierarchy != previousHierarchy) + html += "  " + hierarchy + ""; + html += " >> " + name + ": " + prettyFilter + ""; + + previousHierarchy = hierarchy; + }); + + $.each(pivotDimensions, function(i, v) { + var qualifiedName = v[0]; + var plainFilter = v[1]; + var hierarchy = qualifiedName.split("].[")[0].substring(1).replace("]", ""); + + var name = myself.olapCube.getElementName(qualifiedName); + + var filterParts = plainFilter.split(":["); + var filterMode = filterParts[0].replace("_un", ""); + var prettyFilter = filterParts[1]; + prettyFilter = prettyFilter.substring(0, prettyFilter.length-1); + if(prettyFilter.indexOf("].[") < 0) + prettyFilter = prettyFilter.split("],[").join(" , "); + else { + prettyFilter = $.map(prettyFilter.split("],["), function(e) { + var parts = e.split("].["); + parts = parts.slice(1); + return "[" + parts.join("].["); + }).join(" , "); + } + + if(filterMode == "exclude") + prettyFilter = "all except " + prettyFilter; + else if(filterMode == "between") + prettyFilter = "between " + prettyFilter.replace(" , ", " and "); + + if(hierarchy != previousHierarchy) + html += "  " + hierarchy + ""; + html += " >> " + name + ": " + prettyFilter + ""; + + previousHierarchy = hierarchy; + }); + + $.each(filters, function(i, v) { + var qualifiedName = v[0]; + var plainFilter = v[1]; + var hierarchy = qualifiedName.split("].[")[0].substring(1).replace("]", ""); + + var name = myself.olapCube.getElementName(qualifiedName); + + var filterParts = plainFilter.split(":["); + var filterMode = filterParts[0].replace("_un", ""); + var prettyFilter = filterParts[1]; + prettyFilter = prettyFilter.substring(0, prettyFilter.length-1); + if(prettyFilter.indexOf("].[") < 0) + prettyFilter = prettyFilter.split("],[").join(" , "); + else { + prettyFilter = $.map(prettyFilter.split("],["), function(e) { + var parts = e.split("].["); + parts = parts.slice(1); + return "[" + parts.join("].["); + }).join(" , "); + } + + if(filterMode == "exclude") + prettyFilter = "all except " + prettyFilter; + else if(filterMode == "between") + prettyFilter = "between " + prettyFilter.replace(" , ", " and "); + + if(hierarchy != previousHierarchy) + html += "  " + hierarchy + ""; + html += " >> " + name + ": " + prettyFilter + ""; + + previousHierarchy = hierarchy; + }); + + if(html.length == 0) + html = "  none"; + + var prefix = myself.query.isSynchronizedByParameters() ? "" : "un"; + html = "FILTERS:  " + html; + + var filtersPanelDiv = $("#" + myself.properties.filtersPanelHtmlObject); + filtersPanelDiv.html(html); + filtersPanelDiv.find("a").bind("click", function(){ + var qn = $(this).data("qn"); + myself.openFiltersSelectorPanel(qn); + }); + + + var ordersMap = myself.query.getOrdersMap(); + var dimensionsAxisSorted = ordersMap.axes.hasOwnProperty("dimensions"); + var measuresAxisSorted = ordersMap.axes.hasOwnProperty("measures"); + + if(dimensionsAxisSorted || measuresAxisSorted) { + var hasMoC = myself.query.hasMeasuresOnColumns(); + var columnsAxisName = (hasMoC && measuresAxisSorted) ? "measures" : ((!hasMoC && dimensionsAxisSorted) ? "dimensions" : ""); + var rowsAxisName = (hasMoC && dimensionsAxisSorted) ? "dimensions" : ((!hasMoC && measuresAxisSorted) ? "measures" : ""); + + html = ""; + if(columnsAxisName != "") { + var columnsSort = ordersMap.axes[columnsAxisName]; + var by = columnsSort.by; + var dir = columnsSort.dir; + var axisLetter = columnsAxisName == "dimensions" ? "D" : "M"; + html += "Columns by  " + myself.olapCube.getElementName(columnsSort.by) + "  " + columnsSort.dir + ""; + if(dir != "ASC") + html += ""; + if(dir != "BASC") + html += ""; + if(dir != "DESC") + html += ""; + if(dir != "BDESC") + html += ""; + html += ""; + } + if(html != "") + html += "  "; + if(rowsAxisName != "") { + var rowsSort = ordersMap.axes[rowsAxisName]; + var by = rowsSort.by; + var dir = rowsSort.dir; + var axisLetter = rowsAxisName == "dimensions" ? "D" : "M"; + html += "Rows by  " + myself.olapCube.getElementName(by) + "  " + rowsSort.dir + "  "; + if(dir != "ASC") + html += ""; + if(dir != "BASC") + html += ""; + if(dir != "DESC") + html += ""; + if(dir != "BDESC") + html += ""; + html += ""; + } + + html = "
SORTS: " + html + "
"; + + filtersPanelDiv.append(html); + + filtersPanelDiv.find(".sortIcon").bind("click", function(){ + var target = $(this).data("target"); + var by = $(this).data("by"); + var direction = $(this).data("dir"); + myself.query.sort(target, by, direction); + Dashboards.getComponent(myself.properties.componentName).update(); + }); + + } + + }; + + + myself.openFiltersSelectorPanel = function(selectedLevel) { + var refreshTable = false; + + var filtersMap = myself.query.getFiltersMap(); + + var html = "
"; + + html += "Filters"; + + html += "
Select from the list on the left, the level to be filtered."; + + html += "
"; + + var hierarchyQualifiedNames = []; + for(key in filtersMap.hierarchies) { + hierarchyQualifiedNames.push(key); + } + hierarchyQualifiedNames.sort(); + + $.each(hierarchyQualifiedNames, function(i, key) { + var hierarchyName = key.substring(1, key.length-1); + var hierarchy = filtersMap.hierarchies[key]; + var levels = hierarchy.levels; + + html += "" + hierarchyName + "
    "; + + $.each(hierarchy.order, function(i, v) { + var levelQualifiedName = v; + var levelName = myself.olapCube.getElementName(levelQualifiedName); + var level = levels[v]; + var filtered = level.filtered; + var synchronizedByParameters = level.synchronizedByParameters; + var filterMode = level.filterMode; + var members = level.members; + var selections = members.length; + + var firstMember = selections > 0 ? members[0] : ""; + var isAllMember = selections > 0 && (firstMember == "All" || firstMember.indexOf("All ") == 0 || firstMember.indexOf(".[All]") > 0 || firstMember.indexOf(".[All ") > 0); + + var filterString = ""; + if(filtered && !isAllMember) + filterString = (synchronizedByParameters && filtersMap.synchronizedByParameters)? "dashboard parameter" : (filterMode == "between" ? filterMode + " " + selections : selections + " to " + filterMode); + html += "
  • " + levelName + "" + filterString + "
  • "; + }); + + html += "
"; + }); + + html += "
"; + + + html += "
"; + + $.fancybox(html, { + 'autoDimensions': true, + 'overlayShow': true, + 'hideOnOverlayClick': false, + 'hideOnContentClick': false, + 'enableEscapeButton': false, + 'showCloseButton': true, + 'onClosed' : function() { if(refreshTable) Dashboards.getComponent(myself.properties.componentName).update(); } + }); + + var multiselectDefaultProperties = { + header: true, + minWidth: 480, + height: 370, + checkAllText: 'Check All', + uncheckAllText: 'Uncheck All', + noneSelectedText: 'Select options', + selectedText: '# of # selected', + //autoOpen: false, + //multiple: true, + //classes: "", + selectedList: 50/*, + click: function(e){}, + optgrouptoggle: function(event, ui){}*/ + }; + + var multiselectBetweenModeProperties = { + header: "Choose a maximum of 2 items!", + minWidth: 480, + height: 370, + noneSelectedText: 'Select options', + selectedList: 2, + click: function(e){ + if( $(this).multiselect("widget").find("input:checked").length > 2 ){ + return false; + } + }, + beforeoptgrouptoggle: function(e, ui){ + return false; + } + }; + + var createSelectContent = function(levelQualifiedName, isCalculatedMember, level, boundToDashboard, uniqueNames) { + var html = ""; + + var members = isCalculatedMember ? [] : myself.olapCube.getLevelMembers(levelQualifiedName).members; + + if(uniqueNames) { + + var previousOptgroup = ""; + + $.each(members, function(i, v) { + var optgroup = ""; + var memberQualifiedName = v.qualifiedName; + var qnParts = memberQualifiedName.split("].["); + if(qnParts.length > 2) { + for(i = 1; i < qnParts.length-1; i++) + optgroup += ".[" + qnParts[i] + "]"; + optgroup = optgroup.substring(1); + } + + if(optgroup != "" && optgroup != previousOptgroup) { + if(previousOptgroup != "") + html += ""; + html += ""; + previousOptgroup = optgroup; + } + + var memberName = v.name; + var selectedMembers = []; + if(boundToDashboard && level.synchronizedByParameters) { + var parameterValue = Dashboards.getParameterValue(level.initialFilterExpression.replace(level.filterMode + "_un:", "")); + if($.isArray(parameterValue)) + selectedMembers = parameterValue; + else + selectedMembers.push(parameterValue); + } else { + selectedMembers = level.members; + } + html += ""; + }); + + if(previousOptgroup != "") + html += ""; + + } else { + + var memberNames = _.uniq($.map(members, function(e){return e.name;}).sort(), true); + + var selectedMembers = []; + if(boundToDashboard && level.synchronizedByParameters) { + var parameterValue = Dashboards.getParameterValue(level.initialFilterExpression.replace(level.filterMode + ":", "")); + if($.isArray(parameterValue)) + selectedMembers = parameterValue; + else + selectedMembers.push(parameterValue); + } else { + selectedMembers = level.members; + } + + $.each(memberNames, function(i, memberName) { + html += ""; + }); + + } + + return html; + }; + + var generateFilterSelector = function(levelQualifiedName, levelLabel) { + var qnParts = levelQualifiedName.split("].["); + var hrcName = qnParts[0].substring(1); + var level = qnParts.length > 1 ? filtersMap.hierarchies["[" + hrcName + "]"].levels[levelQualifiedName] : {}; + + var uniqueNames = level.uniqueNames; + + var boundToDashboard = filtersMap.synchronizedByParameters; + + var title = ""; + if(levelLabel) + title = levelLabel; + else { + var lvlName = qnParts.length > 1 ? myself.olapCube.getElementName(qnParts[1].replace("]", "")) : ""; + title = hrcName + (lvlName == "" ? "" : " -> " + lvlName); + } + + $("#filterSelectorTitle").html("" + title + ""); + + var html = "
"; + html += "
Filter mode: In"; + html += "Between"; + html += "
Unique names: yes"; + html += "no"; + html += "
"; + + html += "
"; + + $("#filterSelectorStage").html(html); + + var membersSelectObj = $("#membersSelect"); + membersSelectObj.multiselect(level.filterMode == "between" ? multiselectBetweenModeProperties : multiselectDefaultProperties).multiselectfilter(); + + if(uniqueNames) { + membersSelectObj.multiselect({ + selectedText: function(numChecked, numTotal, checkedItems){ + var items = $.map(checkedItems, function(e) { + var parts = e.value.split("].["); + parts = parts.slice(1); + return "[" + parts.join("].["); + }); + return numChecked > 50 ? (numChecked + ' of ' + numTotal) : items.join(", "); + } + }); + } + + membersSelectObj.multiselect(boundToDashboard && level.synchronizedByParameters ? 'disable' : 'enable'); + + $("input:radio[name='filter-mode']").change(function() { + if($("input:radio[name='filter-mode']:checked").val() == 'between') { + $("#exceptBox").hide(); + membersSelectObj.multiselect("uncheckAll").multiselectfilter("destroy").multiselect("destroy").multiselect(multiselectBetweenModeProperties).multiselectfilter(); + } + else { + $("#exceptBox").show(); + membersSelectObj.multiselect("uncheckAll").multiselectfilter("destroy").multiselect("destroy").multiselect(multiselectDefaultProperties).multiselectfilter(); + } + }); + + $("input:radio[name='uniquenames']").change(function() { + var isBetweenMode = $("input:radio[name='filter-mode']:checked").val() == 'between'; + var uniqueNames = false; + if($("input:radio[name='uniquenames']:checked").val() == 'yes') + uniqueNames = true; + membersSelectObj.multiselect("uncheckAll").multiselectfilter("destroy").multiselect("destroy"); + membersSelectObj.empty().html(createSelectContent(levelQualifiedName, qnParts.length < 2, level, boundToDashboard, uniqueNames)); + membersSelectObj.multiselect(isBetweenMode ? multiselectBetweenModeProperties : multiselectDefaultProperties).multiselectfilter(); + if(uniqueNames) { + membersSelectObj.multiselect({ + selectedText: function(numChecked, numTotal, checkedItems){ + var items = $.map(checkedItems, function(e) { + var parts = e.value.split("].["); + parts = parts.slice(1); + return "[" + parts.join("].["); + }); + return numChecked > 50 ? (numChecked + ' of ' + numTotal) : items.join(", "); + } + }); + } + }); + + $("#update-filter").click(function() { + var mode = $("input:radio[name='filter-mode']:checked").val(); + var except = $("input:checkbox[name='except']:checked").length; + var uniqueNames = $("input:radio[name='uniquenames']:checked").val(); + var members = membersSelectObj.val(); // null if no selection + + var filterString = ""; + + var filterMode = mode == "in" ? (except ? "exclude" : "include") : mode; + level.filterMode = filterMode; + + level.uniqueNames = uniqueNames == "yes"; + + if(members == null) { + level.members = []; + level.filtered = false; + } else { + if(mode == "between" && members.length == 1) + members.push(members[0]); + level.members = members; + level.filtered = true; + filterString = filterMode == "between" ? filterMode + " " + members.length : members.length + " to " + filterMode; + } + + $(".list-item-level[data-qn='" + levelQualifiedName + "']").closest("li").find(".list-item-filterInfo").text(filterString); + + myself.query.setFiltersMap("[" + hrcName + "]", levelQualifiedName, level); + + refreshTable = true; + }); + }; + + + if(selectedLevel != "") { + generateFilterSelector(selectedLevel); + } + + $(".list-item-level").bind("click", function() { + $(".list-item-selected").removeClass("list-item-selected"); + $(this).addClass("list-item-selected"); + var levelLabel = $(this).data("lbl"); + var levelQualifiedName = $(this).data("qn"); + generateFilterSelector(levelQualifiedName, levelLabel); + }); + + $("#dashboardBindingButton").bind("click", function() { + var bound = !filtersMap.synchronizedByParameters; + filtersMap.synchronizedByParameters = bound; + myself.query.synchronizeFiltersWithParameters(bound); + + $(".list-item-level").each(function() { + if($(this).data("par")) { + var lvlQn = $(this).data("qn"); + var hrcQn = lvlQn.split("].[")[0] + "]"; + var level = filtersMap.hierarchies[hrcQn].levels[lvlQn]; + var initialFilterExpression = level.initialFilterExpression; + + var filterInfoObj = $(this).closest("li").find(".list-item-filterInfo"); + + var isSelected = $(this).hasClass("list-item-selected"); + + if(bound) { + var filterMode = initialFilterExpression.split(":")[0]; + var uniqueNames = filterMode.indexOf("_un") > -1; + filterMode = filterMode.replace("_un", ""); + + if(isSelected) { + $("input:radio[name='filter-mode'][value='" + (filterMode != "between" ? "in" : filterMode) + "']").attr('checked', true); + $("input:checkbox[name='except']").attr('checked', filterMode == "exclude"); + if(filterMode == "between") $("#exceptBox").hide(); else $("#exceptBox").show(); + $("input:radio[name='uniquenames'][value='" + (uniqueNames ? "yes" : "no") + "']").attr('checked', true); + + var membersSelectObj = $("#membersSelect"); + membersSelectObj.multiselect("uncheckAll").multiselectfilter("destroy").multiselect("destroy"); + + membersSelectObj.empty().html(createSelectContent(lvlQn, lvlQn.indexOf("].[") < 0, level, true, uniqueNames)); + membersSelectObj.multiselect(filterMode == "between" ? multiselectBetweenModeProperties : multiselectDefaultProperties).multiselectfilter(); + + if(uniqueNames) { + membersSelectObj.multiselect({ + selectedText: function(numChecked, numTotal, checkedItems){ + var items = $.map(checkedItems, function(e) { + var parts = e.value.split("].["); + parts = parts.slice(1); + return "[" + parts.join("].["); + }); + return numChecked > 50 ? (numChecked + ' of ' + numTotal) : items.join(", "); + } + }); + } + } + + myself.query.setFiltersMap(hrcQn, lvlQn, {filterMode: filterMode, uniqueNames: uniqueNames, members: [], filtered: true}); + + filterInfoObj.text("dashboard parameter"); + } + else { + var filterMode = level.filterMode; + var parameterValue = Dashboards.getParameterValue(initialFilterExpression.replace(filterMode + (level.uniqueNames ? "_un" : "") + ":", "")); + var selectedMembers = []; + if($.isArray(parameterValue)) + selectedMembers = parameterValue; + else + selectedMembers.push(parameterValue); + + myself.query.setFiltersMap(hrcQn, lvlQn, {members: selectedMembers}); + + var firstMember = selectedMembers[0]; + var isAllMember = firstMember == "All" || firstMember.indexOf("All ") == 0 || firstMember.indexOf(".[All]") > 0 || firstMember.indexOf(".[All ") > 0; + if(isAllMember) + filterInfoObj.text(""); + else + filterInfoObj.text(filterMode == "between" ? filterMode + " " + selectedMembers.length : selectedMembers.length + " to " + filterMode); + } + + if(isSelected) { + $("input:radio[name='filter-mode']").prop("disabled", bound); + $("input:checkbox[name='except']").prop("disabled", bound); + $("input:radio[name='uniquenames']").prop("disabled", bound); + $("input:button[id='update-filter']").prop("disabled", bound); + $("#membersSelect").multiselect(bound ? 'disable' : 'enable'); + } + } + }); + + $(this).text(bound ? "Unbind from dashboard" : "Bind to dashboard"); + + //if(bound) + refreshTable = true; + }); + + }; + + + /* Start ContextMenu Functions */ + + myself.getPositionInHierarchyInAxis = function(newQualifiedName, axisQualifiedNames) { + var position = {}; + + var levels = myself.olapCube.getHierarchyLevels(newQualifiedName.split("].[")[0] + "]"); + levels = $.map(levels, function(e, i) { + return e.qualifiedName; + }); + levels = $.grep(levels, function(e, i) { + return e == newQualifiedName || $.inArray(e, axisQualifiedNames) > -1; + }); + + var index = $.inArray(newQualifiedName, levels); + + position.level = index == 0 ? levels[index + 1] : levels[index - 1]; + position.direction = index == 0 ? -1 : 1; + + return position; + }; + + myself.getExtremeLevelsInHierarchyInAxis = function(targetQualifiedName, axisQualifiedNames) { + var extremeLevels = []; + var levels = myself.olapCube.getHierarchyLevels(targetQualifiedName.split("].[")[0] + "]"); + levels = $.map(levels, function(e, i) { + return e.qualifiedName; + }); + levels = $.grep(levels, function(e, i) { + return $.inArray(e, axisQualifiedNames) > -1; + }); + + extremeLevels.push(levels[0]); + extremeLevels.push(levels[levels.length - 1]); + + return extremeLevels; + }; + + myself.buildHeaderContextMenu = function(target) { + var hasMoC = myself.query.hasMeasuresOnColumns(); + + var targetLevel = target.level; + var targetMember = target.member; + var targetCaption = target.caption; + + var targetHierarchy = targetLevel.split("].[")[0].substring(1); + + var qualifiedName = targetLevel; + if(targetLevel.indexOf("].[") < 0) + qualifiedName += ".[" + targetMember + "]"; + var targetType = myself.getElementType(qualifiedName); + + var menu = {}; + + menu.title = {name: "" + myself.getMenuTitle(target) + "", callback: function(key, options) {}}; + menu.titlesep = "---"; + + if(targetType == "DIMENSION" || targetType == "PIVOT_DIMENSION") { + var allLevels = myself.olapCube.getLevels(); + var queryDimensionLevels = myself.query.getDimensionQualifiedNames(); + var queryPivotLevels = myself.query.getPivotDimensionQualifiedNames(); + var queryLevels = queryDimensionLevels.concat(queryPivotLevels); + var newLevels = $.grep(allLevels, function(e, i) { + return queryLevels.indexOf(e.qualifiedName) < 0 && queryLevels.indexOf(e.qualifiedName.split("].[")[0] + "]") < 0; + }); + var otherAxisLevels = targetType == "DIMENSION" ? queryPivotLevels : queryDimensionLevels; + + //console.log(otherAxisLevels); + + var invalidHierachies = _.uniq($.map(otherAxisLevels, function(e, i) { + return e == "MEASURES" ? e : (e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1)); + })); + + //console.log(invalidHierachies); + + newLevels = $.grep(newLevels, function(e, i) { + return $.inArray(e.qualifiedName.split("].[")[0].substring(1), invalidHierachies) < 0; + }); + + //console.log(newLevels); + + var newLevelsAsObjects = $.map(newLevels, function(e, i) { + var qn = e.qualifiedName; + var qnParts = qn.split("].["); + var h = qnParts[0].substring(1); + var l = qnParts[1].substring(0, qnParts[1].length-1); + var d = e.depth; + + return {hierarchy: h, level: l, qualifiedName: qn, depth: d}; + }); + + var hierarchies = $.map(newLevelsAsObjects, function(e, i) { + return e.hierarchy; + }); + hierarchies = _.uniq(hierarchies); + hierarchies.sort(); + + //console.log(hierarchies); + + var menuMatrix = []; + $.each(newLevelsAsObjects, function(i, v) { + var h = v.hierarchy; + var l = v.level; + var qn = v.qualifiedName; + var d = v.depth; + if(menuMatrix[h] == undefined) + menuMatrix[h] = []; + menuMatrix[h].push({name: l, qualifiedName: qn, depth: d}); + }); + + //console.log(menuMatrix); + + var axisLevels = targetType == "DIMENSION" ? myself.query.getDimensionQualifiedNames() : myself.query.getPivotDimensionQualifiedNames(); + var axisHierarchies = $.map(axisLevels, function(e, i) { + return e == "MEASURES" ? e : (e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1)); + }); + + //console.log(axisHierarchies); + + // to find the position where adding a new element after or before an existing one + // which is not the only level of its hierarchy to be showed + var extremeHierarchyLevels = myself.getExtremeLevelsInHierarchyInAxis(targetLevel, axisLevels); + + //console.log(extremeHierarchyLevels); + + menu.add = {name: "Add", items: {}, disabled: newLevelsAsObjects.length == 0}; + menu.change = {name: "Change", items: {}, disabled: newLevelsAsObjects.length == 0}; + menu.remove = { + name: "Remove", + disabled: !myself.query.isRemovable(targetLevel, targetType.substring(0,1)), + callback: function(key, options) { + myself.query.remove(targetLevel, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }; + menu.filter = { + name: "Filter", + callback: function(key, options) { + myself.openFiltersSelectorPanel(targetLevel); + } + }; + + var axisLetter = targetType == "DIMENSION" ? "D" : "M"; + var sortDirection = myself.query.getSortDirection(axisLetter, targetLevel); + menu.sort = { + name: "Sort", + items: { + asc: { + name: "Ascending", + items: { + kasc: { + name: "Keep hierarchy", + disabled: sortDirection == "ASC", + callback: function(key, options) { + myself.query.sort(axisLetter, targetLevel, "ASC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + basc: { + name: "Break hierarchy", + disabled: sortDirection == "BASC", + callback: function(key, options) { + myself.query.sort(axisLetter, targetLevel, "BASC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }, + desc: { + name: "Descending", + items: { + kdesc: { + name: "Keep hierarchy", + disabled: sortDirection == "DESC", + callback: function(key, options) { + myself.query.sort(axisLetter, targetLevel, "DESC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + bdesc: { + name: "Break hierarchy", + disabled: sortDirection == "BDESC", + callback: function(key, options) { + myself.query.sort(axisLetter, targetLevel, "BDESC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }, + clear: { + name: "Clear", + disabled: sortDirection == "", + callback: function(key, options) { + myself.query.sort(axisLetter, "", ""); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }; + + $.each(hierarchies, function(i, hierarchy) { + menu.add.items["add-dim-" + i] = {}; + menu.add.items["add-dim-" + i].name = hierarchy; + menu.add.items["add-dim-" + i].items = {}; + + menu.change.items["change-dim-" + i] = {}; + menu.change.items["change-dim-" + i].name = hierarchy; + + var levels = menuMatrix[hierarchy]; + if(levels.length == 1 && levels[0].name == hierarchy && levels[0].depth == 1) { + var newLevel = levels[0].qualifiedName; + + if($.inArray(hierarchy, axisHierarchies) > -1) { + // to find the hierarchy level after which add the new level + var position = myself.getPositionInHierarchyInAxis(newLevel, axisLevels); + + menu.add.items["add-dim-" + i].callback = function(key, options) { + myself.query.add(newLevel, position.level, position.direction, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + + // If the new element belongs to a hierarchy already existing in the axis, + // you need to remove targetLevel and place the new element in the right position + // that can be different from removed element position + menu.change.items["change-dim-" + i].disabled = !myself.query.isReplaceable(newLevel, targetLevel, targetType.substring(0,1)); + menu.change.items["change-dim-" + i].callback = function(key, options) { + myself.query.replace(newLevel, targetLevel, position, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } else { + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-before"] = {}; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-before"].name = "Before"; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-before"].callback = function(key, options) { + myself.query.add(newLevel, extremeHierarchyLevels[0], -1, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-after"] = {}; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-after"].name = "After"; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-after"].callback = function(key, options) { + myself.query.add(newLevel, extremeHierarchyLevels[1], 1, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + + menu.change.items["change-dim-" + i].disabled = !myself.query.isReplaceable(newLevel, targetLevel, targetType.substring(0,1)); + menu.change.items["change-dim-" + i].callback = function(key, options) { + myself.query.replace(newLevel, targetLevel, {level: extremeHierarchyLevels[1], direction: 1}, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } + + if(targetHierarchy != hierarchy && $.inArray(targetLevel, extremeHierarchyLevels) < 0) + menu.change.items["change-dim-" + i].disabled = true; + } else { + menu.change.items["change-dim-" + i].items = {}; + + $.each(levels, function(j, level) { + var newLevel = level.qualifiedName; + var position = myself.getPositionInHierarchyInAxis(newLevel, axisLevels); + + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j] = {}; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].name = level.name; + + menu.change.items["change-dim-" + i].items["change-dim-" + i + "-" + j] = {}; + menu.change.items["change-dim-" + i].items["change-dim-" + i + "-" + j].name = level.name; + + if($.inArray(hierarchy, axisHierarchies) > -1) { + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].callback = function(key, options) { + myself.query.add(newLevel, position.level, position.direction, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + + menu.change.items["change-dim-" + i].items["change-dim-" + i + "-" + j].disabled = !myself.query.isReplaceable(newLevel, targetLevel, targetType.substring(0,1)); + menu.change.items["change-dim-" + i].items["change-dim-" + i + "-" + j].callback = function(key, options) { + myself.query.replace(newLevel, targetLevel, position, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } else { + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items = {}; + + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items["add-dim-" + i + "-" + j + "-before"] = {}; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items["add-dim-" + i + "-" + j + "-before"].name = "Before"; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items["add-dim-" + i + "-" + j + "-before"].callback = function(key, options) { + myself.query.add(newLevel, extremeHierarchyLevels[0], -1, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items["add-dim-" + i + "-" + j + "-after"] = {}; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items["add-dim-" + i + "-" + j + "-after"].name = "After"; + menu.add.items["add-dim-" + i].items["add-dim-" + i + "-" + j].items["add-dim-" + i + "-" + j + "-after"].callback = function(key, options) { + myself.query.add(newLevel, extremeHierarchyLevels[1], 1, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + + menu.change.items["change-dim-" + i].items["change-dim-" + i + "-" + j].disabled = !myself.query.isReplaceable(newLevel, targetLevel, targetType.substring(0,1)); + menu.change.items["change-dim-" + i].items["change-dim-" + i + "-" + j].callback = function(key, options) { + myself.query.replace(newLevel, targetLevel, {level: extremeHierarchyLevels[1], direction: 1}, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } + + if(targetHierarchy != hierarchy && $.inArray(targetLevel, extremeHierarchyLevels) < 0) + menu.change.items["change-dim-" + i].disabled = true; + }); + } + }); + + var countEnabled = 0; + if(menu.change.hasOwnProperty("items")) { + for(key in menu.change.items) { + if(!menu.change.items[key].disabled) + countEnabled++; + } + } + if(countEnabled == 0) + menu.change.disabled = true; + + + if(targetType == "DIMENSION" && !hasMoC && target.hasOwnProperty("index")) { + var items = myself.buildDrillMenu(); + var disabled = $.isEmptyObject(items) ? true : false; + + menu.drillsep = "---"; + menu.drill = { + name: "Drill Column", + items: items, + disabled: disabled + }; + } + } + + else if(targetType == "MEASURE" || targetType == "MEASURES_LEVEL") { + if(targetType == "MEASURE") { + var allMeasures = myself.olapCube.getStructure().measures; + var queryMeasures = myself.query.getMeasureQualifiedNames(); + var newMeasures = $.grep(allMeasures, function(e, i) { + return queryMeasures.indexOf(e.qualifiedName) < 0; + }); + + newMeasures.sort(function(a, b) { + var comparison = 0; + if(a.name < b.name) + comparison = -1; + else if(a.name > b.name) + comparison = 1; + return comparison; + }); + + + menu.add = {name: "Add", items: {}, disabled: newMeasures.length == 0}; + menu.change = {name: "Change", items: {}, disabled: newMeasures.length == 0}; + menu.remove = { + name: "Remove", + disabled: queryMeasures.length == 1, + callback: function(key, options) { + myself.query.remove(targetLevel, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }; + + $.each(newMeasures, function(i, v) { + menu.add.items["add-kpi-" + i] = {}; + menu.add.items["add-kpi-" + i].name = v.name; + menu.add.items["add-kpi-" + i].items = {}; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-before"] = {}; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-before"].name = "Before"; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-before"].callback = function(key, options) { + myself.query.add(v.qualifiedName, targetLevel, -1, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-after"] = {}; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-after"].name = "After"; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-after"].callback = function(key, options) { + myself.query.add(v.qualifiedName, targetLevel, 1, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + + menu.change.items["change-kpi-" + i] = {}; + menu.change.items["change-kpi-" + i].name = v.name; + menu.change.items["change-kpi-" + i].callback = function(key, options) { + myself.query.replace(v.qualifiedName, targetLevel, null, targetType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + }); + + var sortDirection = myself.query.getSortDirection("D", targetLevel); + menu.sort = { + name: "Sort", + items: { + asc: { + name: "Ascending", + items: { + kasc: { + name: "Keep hierarchy", + disabled: sortDirection == "ASC", + callback: function(key, options) { + myself.query.sort("D", targetLevel, "ASC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + basc: { + name: "Break hierarchy", + disabled: sortDirection == "BASC", + callback: function(key, options) { + myself.query.sort("D", targetLevel, "BASC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }, + desc: { + name: "Descending", + items: { + kdesc: { + name: "Keep hierarchy", + disabled: sortDirection == "DESC", + callback: function(key, options) { + myself.query.sort("D", targetLevel, "DESC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + bdesc: { + name: "Break hierarchy", + disabled: sortDirection == "BDESC", + callback: function(key, options) { + myself.query.sort("D", targetLevel, "BDESC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }, + clear: { + name: "Clear", + disabled: sortDirection == "", + callback: function(key, options) { + myself.query.sort("D", "", ""); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }; + } + + menu.pivot = {name: "Pivot", items: {}}; + + var allLevels = myself.olapCube.getLevels(); + var queryDimensionLevels = myself.query.getDimensionQualifiedNames(); + var queryPivotLevels = myself.query.getPivotDimensionQualifiedNames(); + var queryLevels = queryDimensionLevels.concat(queryPivotLevels); + var newLevels = $.grep(allLevels, function(e, i) { + return queryLevels.indexOf(e.qualifiedName) < 0 && queryLevels.indexOf(e.qualifiedName.split("].[")[0] + "]") < 0; + }); + var invalidHierachies = _.uniq($.map(queryDimensionLevels, function(e, i) { + return e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1); + })); + + //console.log(invalidHierachies); + + newLevels = $.grep(newLevels, function(e, i) { + return $.inArray(e.qualifiedName.split("].[")[0].substring(1), invalidHierachies) < 0; + }); + + //console.log(newLevels); + + var newLevelsAsObjects = $.map(newLevels, function(e, i) { + var qn = e.qualifiedName; + var qnParts = qn.split("].["); + var h = qnParts[0].substring(1); + var l = qnParts[1].substring(0, qnParts[1].length-1); + var d = e.depth; + + return {hierarchy: h, level: l, qualifiedName: qn, depth: d}; + }); + + var hierarchies = $.map(newLevelsAsObjects, function(e, i) { + return e.hierarchy; + }); + hierarchies = _.uniq(hierarchies); + hierarchies.sort(); + + //console.log(hierarchies); + + var menuMatrix = []; + $.each(newLevelsAsObjects, function(i, v) { + var h = v.hierarchy; + var l = v.level; + var qn = v.qualifiedName; + var d = v.depth; + if(menuMatrix[h] == undefined) + menuMatrix[h] = []; + menuMatrix[h].push({name: l, qualifiedName: qn, depth: d}); + }); + + //console.log(menuMatrix); + + var axisLevels = myself.query.getPivotDimensionQualifiedNames(); + var axisHierarchies = $.map(axisLevels, function(e, i) { + return e == "MEASURES" ? e : (e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1)); + }); + + //console.log(axisHierarchies); + + $.each(hierarchies, function(i, hierarchy) { + menu.pivot.items["add-pivot-" + i] = {}; + menu.pivot.items["add-pivot-" + i].name = hierarchy; + menu.pivot.items["add-pivot-" + i].items = {}; + + var levels = menuMatrix[hierarchy]; + if(levels.length == 1 && levels[0].name == hierarchy && levels[0].depth == 1) { + var newLevel = levels[0].qualifiedName; + + if($.inArray(hierarchy, axisHierarchies) > -1) { + menu.pivot.items["add-pivot-" + i].callback = function(key, options) { + var position = myself.getPositionInHierarchyInAxis(newLevel, axisLevels); + myself.query.add(newLevel, position.level, position.direction, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } else { + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-before"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-before"].name = "Before"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-before"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", -1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-after"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-after"].name = "After"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-after"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", 1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } + } else { + $.each(levels, function(j, level) { + var newLevel = level.qualifiedName; + + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].name = level.name; + if($.inArray(hierarchy, axisHierarchies) > -1) { + var position = myself.getPositionInHierarchyInAxis(newLevel, axisLevels); + + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].callback = function(key, options) { + myself.query.add(newLevel, position.level, position.direction, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } else { + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items = {}; + + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-before"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-before"].name = "Before"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-before"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", -1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-after"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-after"].name = "After"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-after"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", 1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } + }); + } + }); + + } + + // else if CALCULATED_MEMBER { ... } + + menu.filterssep = "---"; + menu.filters = { + name: "Manage Filters", + callback: function(key, options) { + myself.openFiltersSelectorPanel(""); + } + }; + + menu.toggleFilters = { + name: (myself.properties.showFilters ? "Hide" : "Show") + " Filters and Sorts", + callback: function() { + myself.properties.showFilters = !myself.properties.showFilters; + $("#" + myself.properties.filtersPanelHtmlObject).toggle(); + } + }; + + menu.settingssep = "---"; + var settingsMenu = myself.buildSettingsMenu(); + menu.settings = {name: "Table Settings", items: settingsMenu.items}; + + menu.mdx = { + name: "Show MDX", + callback: function(key, options) { + var html = "
" + Dashboards.getParameterValue(myself.properties.componentName.replace("render_", "") + "MdxQuery") + "
"; + $.fancybox(html, { + 'autoDimensions': true, + 'overlayShow': true, + 'hideOnOverlayClick': false, + 'hideOnContentClick': false, + 'enableEscapeButton': false, + 'showCloseButton': true, + }); + } + } + + menu.export2excel = { + name: "Export to Excel", + callback: function(key, options) { + myself.exportToExcel(); + } + }; + + menu.reset = { + name: "Reset", + callback: function() { + myself.query.reset(); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }; + + return { + callback: function(key, options) { + if(targetType == "DIMENSION" && !hasMoC && target.hasOwnProperty("index")) { + //console.log("-------------------- drill column by " + key + " --------------------"); + //console.log(target); + //console.log(normalizedCdaResult); + + var measures = myself.query.getMeasures(); + + //console.log(measures.toSource()); + + var pivotDimensions = myself.query.getPivotDimensions(); + + //console.log(pivotDimensions.toSource()); + + var queryFilters = myself.query.getFilters(); + + var dimensions = $.grep(queryFilters, function(f) { + var qn = f[0]; + return qn == key || qn.split("].[")[0] == key.split("].[")[0]; + }); + + //console.log(dimensions.toSource()); + + var filters = $.grep(queryFilters, function(f) { + return f[0].split("].[")[0] != key.split("].[")[0]; + }); + + var pivotDimensionQualifiedNames = myself.query.getPivotDimensionQualifiedNames(); + var count = pivotDimensionQualifiedNames.length; + if($.inArray("MEASURES", pivotDimensionQualifiedNames) < 0) + count++; + var index = myself.properties.hideSpans ? target.index : (target.index + count); + + if(headers.length == 1) { + index = target.index; + } + + var cdaHeaderParts = normalizedCdaResult.metadata[index].colName.split("]/["); + + var length = cdaHeaderParts.length; + if(length > 1) { + cdaHeaderParts[0] += "]"; + for(i = 1; i < length-1; i++) { + cdaHeaderParts[i] = "[" + cdaHeaderParts[i] + "]"; + } + cdaHeaderParts[length-1] = "[" + cdaHeaderParts[length-1]; + } + + //console.log(cdaHeaderParts.toSource()); + + var dimensionQualifiedNames = myself.query.getDimensionQualifiedNames(); + + var ht = new Array(); + var levelQualifiedNames = dimensionQualifiedNames.slice().reverse(); + var previousHierarchy = ""; + var maxLevelDepth = 1; + for(i = 0; i < levelQualifiedNames.length; i++) { + var levelQualifiedName = levelQualifiedNames[i]; + + var hierarchy = levelQualifiedName.split("].[")[0].substring(1); + + if(levelQualifiedName.indexOf("].[") < 0) + hierarchy = hierarchy.substring(0, hierarchy.length-1); + + var index = -1; + $.each(cdaHeaderParts, function(j, w) { + if(w.indexOf("[" + hierarchy + "]") > -1 || w.indexOf("[" + hierarchy + "." + hierarchy + "]") > -1) { + index = j; + return; + } + }); + + //console.log(levelQualifiedName + " -> " + hierarchy + " -> " + index); + + ht[levelQualifiedName] = ""; + + if(index >= 0) { + var member = cdaHeaderParts[0]; + if(cdaHeaderParts.length > 1 || (member != "[Measures].[MeasuresLevel]" && $.inArray(member, pivotDimensionQualifiedNames) < 0)) { + var memberUniqueNameParts = cdaHeaderParts[index].split("].[").reverse(); + member = memberUniqueNameParts[0]; + member = member.substring(0, member.length-1); + if(hierarchy == previousHierarchy) { + member = memberUniqueNameParts[maxLevelDepth - myself.olapCube.getLevelDepth(levelQualifiedName)]; + } + } + ht[levelQualifiedName] = member; + + if(hierarchy != previousHierarchy) { + previousHierarchy = hierarchy; + maxLevelDepth = myself.olapCube.getLevelDepth(levelQualifiedName); + } + + } + + //console.log("ht[" + levelQualifiedName + "] = " + ht[levelQualifiedName]); + } + + if(dimensions.length == 0) { + var keyDepth = myself.olapCube.getLevelDepth(key); + var leftArr = []; + var rightArr = []; + + $.each(dimensionQualifiedNames, function(i, v) { + var el = [v, "include:[" + ht[v] + "]"]; + if(v.split("].[")[0] != key.split("].[")[0]) + filters.push(el); + else { + if(myself.olapCube.getLevelDepth(v) < keyDepth) + leftArr.push(el); + else + rightArr.push(el); + } + }); + + dimensions = leftArr.concat([[key, ""]], rightArr); + } + else { + $.each(dimensionQualifiedNames, function(i, v) { + filters.push([v, "include:[" + ht[v] + "]"]); + }); + + var keyDepth = myself.olapCube.getLevelDepth(key); + var leftArr = []; + var rightArr = []; + $.each(dimensions, function(i, v) { + var qn = v[0]; + if(myself.olapCube.getLevelDepth(qn) < keyDepth) + leftArr.push(v); + else + rightArr.push(v); + }); + dimensions = leftArr.concat([[key, ""]], rightArr); + } + + //console.log(dimensions.toSource()); + + //console.log(filters.toSource()); + + //console.log("-----------------------------------------------------------"); + + var currentDimensions = myself.query.getDimensions(); + $.each(dimensions, function(i, v) { + var qn = v[0]; + if(v[1].indexOf("BT_TOTAL") > -1 || v[1].indexOf("undefined") > -1) { + var d = $.grep(currentDimensions, function(e) { + return e[0] == qn; + }); + v[1] = d[0][1]; + } + }); + + //console.log(dimensions.toSource()); + + $.each(filters, function(i, v) { + var qn = v[0]; + if(v[1].indexOf("BT_TOTAL") > -1 || v[1].indexOf("undefined") > -1) { + var d = $.grep(currentDimensions, function(e) { + return e[0] == qn; + }); + v[1] = d[0][1]; + } + }); + + //console.log(filters.toSource()); + + + var querySetting = myself.query.getSettings(); + + var BTableDrillProp = {}; + BTableDrillProp.catalog = myself.properties.catalog; + BTableDrillProp.jndi = myself.properties.jndi; + BTableDrillProp.cube = myself.query.getCube(); + BTableDrillProp.dimensions = dimensions; + BTableDrillProp.measures = measures; + BTableDrillProp.pivotDimensions = pivotDimensions; + BTableDrillProp.filters = filters; + BTableDrillProp.measuresOnColumns = querySetting.measuresOnColumns; + BTableDrillProp.nonEmptyRows = querySetting.nonEmpty.rows; + BTableDrillProp.nonEmptyColumns = querySetting.nonEmpty.columns; + BTableDrillProp.grandTotal = querySetting.summary.grandTotal; + BTableDrillProp.subTotals = querySetting.summary.subTotals; + BTableDrillProp.pivotGrandTotal = querySetting.summary.pivotGrandTotal; + BTableDrillProp.pivotSubTotals = querySetting.summary.pivotSubTotals; + BTableDrillProp.totalsPosition = querySetting.summary.position; + BTableDrillProp.hideSpans = myself.properties.hideSpans; + + //console.log(BTableDrillProp); + + var urlQuery = getURLQuery(); + + var url = webAppPath + "/content/BTable/render?"; + url += "btdef=" + JSON.stringify(BTableDrillProp); + url += (urlQuery.hasOwnProperty("debug") && urlQuery.debug == "true") ? "&debug=true" : ""; + + //console.log(url); + + window.open(url, "_blank"); + //location.href = url; + //top.mantle_openTab("BTable Drill", "BTable Drill", url); + + } else { + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + items: menu + }; + }; + + + myself.buildSettingsMenu = function() { + var menu = {}; + + var settings = myself.query.getSettings(); + + menu.items = { + nonEmptyCol: { + name: "Non Empty Columns", + type: 'checkbox', + selected: settings.nonEmpty.columns, + events: { + click: function(e) { + myself.query.set({nonEmpty: {columns: !settings.nonEmpty.columns}}); + } + } + }, + nonEmptyRow: { + name: "Non Empty Rows", + type: 'checkbox', + selected: settings.nonEmpty.rows, + events: { + click: function(e) { + myself.query.set({nonEmpty: {rows: !settings.nonEmpty.rows}}); + } + } + }, + sep1: "---------", + grandTotal: { + name: "Grand Total", + type: 'checkbox', + selected: settings.summary.grandTotal, + events: { + click: function(e) { + myself.query.set({summary: {grandTotal: !settings.summary.grandTotal}}); + } + } + }, + subtotals: { + name: "Subtotals", + type: 'checkbox', + selected: settings.summary.subTotals, + events: { + click: function(e) { + myself.query.set({summary: {subTotals: !settings.summary.subTotals}}); + } + } + }, + pivotGrandTotal: { + name: "Pivot Grand Total", + type: 'checkbox', + selected: settings.summary.pivotGrandTotal, + events: { + click: function(e) { + myself.query.set({summary: {pivotGrandTotal: !settings.summary.pivotGrandTotal}}); + } + } + }, + pivotSubtotals: { + name: "Pivot Subtotals", + type: 'checkbox', + selected: settings.summary.pivotSubTotals, + events: { + click: function(e) { + myself.query.set({summary: {pivotSubTotals: !settings.summary.pivotSubTotals}}); + } + } + }, + /*totalsPosition: { + name: "Position", + type: 'select', + options: {'top': 'Top', 'bottom': 'Bottom'}, + selected: settings.summary.position, + events: { + change: function(e) { + myself.query.set({summary: {position: settings.summary.position == "top" ? "bottom" : "top"}}); + } + } + },*/ + sep2: "---------", + measuresOnColumns: { + name: "Measures on Columns", + type: 'radio', + radio: 'radio', + value: 'true', + selected: settings.measuresOnColumns, + events: { + click: function(e) { + myself.query.set({measuresOnColumns: true}); + } + } + }, + measuresOnRows: { + name: "Measures on Rows", + type: 'radio', + radio: 'radio', + value: 'false', + selected: !settings.measuresOnColumns, + events: { + click: function(e) { + myself.query.set({measuresOnColumns: false}); + } + } + }, + sep3: "---------", + hideSpans: { + name: "Hide Spans", + type: 'checkbox', + selected: myself.properties.hideSpans, + events: { + click: function(e) { + myself.properties.hideSpans = !myself.properties.hideSpans; + } + } + }, + sep4: "---------", + apply: { + name: "Apply Changes", + callback: function() { + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + }; + + return menu; + } + + + myself.buildBodyContextMenu = function(state) { + var hasMoC = myself.query.hasMeasuresOnColumns(); + + var rawData = state.rawData; + var tableData = state.tableData; + var colIdx = state.colIdx; + var rowIdx = state.rowIdx; + var row = rawData.resultset[rowIdx]; + var column = rawData.metadata[colIdx].colName; + var value = rawData.resultset[rowIdx][colIdx]; + + //console.log(row); + //console.log(column); + //console.log(value); + + var menu = {}; + + var menuType = ""; + if(column.indexOf("[Measures]") < 0) { + if($.inArray(column, myself.query.getPivotDimensionQualifiedNames()) > -1) + menuType = "MEMBER_MENU"; + else + menuType = hasMoC ? "DRILL_ROW_MENU" : "DRILL_CELL_MENU"; + } else { + menuType = hasMoC ? "DRILL_CELL_MENU" : "MEASURE_MENU"; + } + + var btRef = {}; + if(menuType == "MEASURE_MENU") { + btRef.level = "[Measures].[" + value + "]", + btRef.member = value + } + else if(menuType == "DRILL_ROW_MENU" || menuType == "MEMBER_MENU") { + btRef.level = column, + btRef.member = value + } + + else if(menuType == "DRILL_CELL_MENU") { + var measureLevel = ""; + if(hasMoC) { + var parts = column.split("]/["); + $.each(parts, function(i, v) { + if(v.indexOf("Measures].[") > -1) { + measureLevel = ("[" + v + "]").replace("[[", "[").replace("]]", "]"); + return; + } + }); + } + else { + var measuresIdx = $.inArray("[Measures].[MeasuresLevel]", $.map(rawData.metadata, function(e){ return e.colName; })); + measureLevel = "[Measures].[" + tableData[rowIdx][measuresIdx] + "]"; + } + btRef.level = measureLevel, + btRef.member = value + } + + if(value == null) + menuType = "MEMBER_MENU"; + + + if(menuType == "DRILL_ROW_MENU") { + var dimensions = myself.query.getDimensionQualifiedNames(); + if(btRef.level != dimensions[dimensions.length - 1]) + menuType = "MEMBER_MENU"; + } + + //console.log(menuType); + + var title = myself.getMenuTitle(btRef); + + menu.title = {name: "" + title + "", callback: function(key, options) {}}; + menu.titlesep = "---"; + + + if(menuType == "MEASURE_MENU") { + var allMeasures = myself.olapCube.getStructure().measures; + var queryMeasures = myself.query.getMeasureQualifiedNames(); + var newMeasures = $.grep(allMeasures, function(e, i) { + return queryMeasures.indexOf(e.qualifiedName) < 0; + }); + + newMeasures.sort(function(a, b) { + var comparison = 0; + if(a.name < b.name) + comparison = -1; + else if(a.name > b.name) + comparison = 1; + return comparison; + }); + + + menu.add = {name: "Add", items: {}, disabled: newMeasures.length == 0}; + menu.change = {name: "Change", items: {}, disabled: newMeasures.length == 0}; + menu.remove = { + name: "Remove", + disabled: queryMeasures.length == 1, + callback: function(key, options) { + myself.query.remove(btRef.level, menuType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }; + + $.each(newMeasures, function(i, v) { + menu.add.items["add-kpi-" + i] = {}; + menu.add.items["add-kpi-" + i].name = v.name; + menu.add.items["add-kpi-" + i].items = {}; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-before"] = {}; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-before"].name = "Before"; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-before"].callback = function(key, options) { + myself.query.add(v.qualifiedName, btRef.level, -1, menuType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-after"] = {}; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-after"].name = "After"; + menu.add.items["add-kpi-" + i].items["add-kpi-" + i + "-after"].callback = function(key, options) { + myself.query.add(v.qualifiedName, btRef.level, 1, menuType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + + menu.change.items["change-kpi-" + i] = {}; + menu.change.items["change-kpi-" + i].name = v.name; + menu.change.items["change-kpi-" + i].callback = function(key, options) { + myself.query.replace(v.qualifiedName, btRef.level, null, menuType.substring(0,1)); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + }); + + var sortDirection = myself.query.getSortDirection("D", btRef.level); + + menu.sort = { + name: "Sort", + items: { + asc: { + name: "Ascending", + items: { + kasc: { + name: "Keep hierarchy", + disabled: sortDirection == "ASC", + callback: function(key, options) { + myself.query.sort("D", btRef.level, "ASC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + basc: { + name: "Break hierarchy", + disabled: sortDirection == "BASC", + callback: function(key, options) { + myself.query.sort("D", btRef.level, "BASC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }, + desc: { + name: "Descending", + items: { + kdesc: { + name: "Keep hierarchy", + disabled: sortDirection == "DESC", + callback: function(key, options) { + myself.query.sort("D", btRef.level, "DESC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }, + bdesc: { + name: "Break hierarchy", + disabled: sortDirection == "BDESC", + callback: function(key, options) { + myself.query.sort("D", btRef.level, "BDESC"); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }, + clear: { + name: "Clear", + disabled: sortDirection == "", + callback: function(key, options) { + myself.query.sort("D", "", ""); + Dashboards.getComponent(myself.properties.componentName).update(); + } + } + } + }; + + menu.pivot = {name: "Pivot", items: {}}; + + var allLevels = myself.olapCube.getLevels(); + var queryDimensionLevels = myself.query.getDimensionQualifiedNames(); + var queryPivotLevels = myself.query.getPivotDimensionQualifiedNames(); + var queryLevels = queryDimensionLevels.concat(queryPivotLevels); + var newLevels = $.grep(allLevels, function(e, i) { + return queryLevels.indexOf(e.qualifiedName) < 0 && queryLevels.indexOf(e.qualifiedName.split("].[")[0] + "]") < 0; + }); + var invalidHierachies = _.uniq($.map(queryDimensionLevels, function(e, i) { + return e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1); + })); + + //console.log(invalidHierachies); + + newLevels = $.grep(newLevels, function(e, i) { + return $.inArray(e.qualifiedName.split("].[")[0].substring(1), invalidHierachies) < 0; + }); + + //console.log(newLevels); + + var newLevelsAsObjects = $.map(newLevels, function(e, i) { + var qn = e.qualifiedName; + var qnParts = qn.split("].["); + var h = qnParts[0].substring(1); + var l = qnParts[1].substring(0, qnParts[1].length-1); + + return {hierarchy: h, level: l, qualifiedName: qn}; + }); + + var hierarchies = $.map(newLevelsAsObjects, function(e, i) { + return e.hierarchy; + }); + hierarchies = _.uniq(hierarchies); + hierarchies.sort(); + + //console.log(hierarchies); + + var menuMatrix = []; + $.each(newLevelsAsObjects, function(i, v) { + var h = v.hierarchy; + var l = v.level; + var qn = v.qualifiedName; + if(menuMatrix[h] == undefined) + menuMatrix[h] = []; + menuMatrix[h].push({name: l, qualifiedName: qn}); + }); + + //console.log(menuMatrix); + + var axisLevels = myself.query.getPivotDimensionQualifiedNames(); + var axisHierarchies = $.map(axisLevels, function(e, i) { + return e == "MEASURES" ? e : (e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1)); + }); + + //console.log(axisHierarchies); + + $.each(hierarchies, function(i, hierarchy) { + menu.pivot.items["add-pivot-" + i] = {}; + menu.pivot.items["add-pivot-" + i].name = hierarchy; + menu.pivot.items["add-pivot-" + i].items = {}; + + var levels = menuMatrix[hierarchy]; + if(levels.length == 1 && levels[0].name == hierarchy) { + var newLevel = levels[0].qualifiedName; + + if($.inArray(hierarchy, axisHierarchies) > -1) { + menu.pivot.items["add-pivot-" + i].callback = function(key, options) { + var position = myself.getPositionInHierarchyInAxis(newLevel, axisLevels); + myself.query.add(newLevel, position.level, position.direction, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } else { + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-before"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-before"].name = "Before"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-before"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", -1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-after"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-after"].name = "After"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-after"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", 1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } + } else { + $.each(levels, function(j, level) { + var newLevel = level.qualifiedName; + + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].name = level.name; + if($.inArray(hierarchy, axisHierarchies) > -1) { + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].callback = function(key, options) { + var position = myself.getPositionInHierarchyInAxis(newLevel, axisLevels); + myself.query.add(newLevel, position.level, position.direction, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } else { + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items = {}; + + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-before"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-before"].name = "Before"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-before"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", -1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-after"] = {}; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-after"].name = "After"; + menu.pivot.items["add-pivot-" + i].items["add-pivot-" + i + "-" + j].items["add-pivot-" + i + "-" + j + "-after"].callback = function(key, options) { + myself.query.add(newLevel, "MEASURES", 1, "P"); + Dashboards.getComponent(myself.properties.componentName).update(); + }; + } + }); + } + }); + + } + + else if(menuType == "DRILL_ROW_MENU") { + var items = myself.buildDrillMenu(); + var disabled = $.isEmptyObject(items) ? true : false; + menu.drill = { + name : "Drill Row", + items: items, + disabled: disabled + }; + } + + else if(menuType == "DRILL_CELL_MENU") { + var items = myself.buildDrillMenu(); + var disabled = $.isEmptyObject(items) ? true : false; + menu.drill = { + name : "Drill Cell", + items: items, + disabled: disabled + }; + } + + if(menuType != "MEMBER_MENU") + menu.filterssep = "---"; + menu.filters = { + name: "Manage Filters", + callback: function(key, options) { + myself.openFiltersSelectorPanel(""); + } + }; + + menu.toggleFilters = { + name: (myself.properties.showFilters ? "Hide" : "Show") + " Filters and Sorts", + callback: function() { + myself.properties.showFilters = !myself.properties.showFilters; + $("#" + myself.properties.filtersPanelHtmlObject).toggle(); + } + }; + + menu.settingssep = "---"; + var settingsMenu = myself.buildSettingsMenu(); + menu.settings = {name: "Table Settings", items: settingsMenu.items}; + + menu.mdx = { + name: "Show MDX", + callback: function(key, options) { + var html = "
" + Dashboards.getParameterValue(myself.properties.componentName.replace("render_", "") + "MdxQuery") + "
"; + $.fancybox(html, { + 'autoDimensions': true, + 'overlayShow': true, + 'hideOnOverlayClick': false, + 'hideOnContentClick': false, + 'enableEscapeButton': false, + 'showCloseButton': true, + }); + } + } + + menu.export2excel = { + name: "Export to Excel", + callback: function(key, options) { + myself.exportToExcel(); + } + }; + + menu.reset = { + name: "Reset", + callback: function() { + myself.query.reset(); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }; + + return { + callback: function(key, options) { + var drillCell = menuType == "DRILL_CELL_MENU"; + + //console.log("Drill " + (drillCell ? "cell" : "row" ) + " by " + key); + + var measures = myself.query.getMeasures(); + if(drillCell) { + if(hasMoC) { + measures = $.grep(measures, function(m) { + return column.indexOf(m[0]) > -1; + }); + } else { + var measuresLevelIdx = 0; + $.each(rawData.metadata, function(i, v) { + if(v.colName == "[Measures].[MeasuresLevel]") { + measuresLevelIdx = i; + return; + } + }); + + //console.log("measuresLevelIdx = " + measuresLevelIdx); + + measures = $.grep(measures, function(m) { + return m[0] == "[Measures].[" + row[measuresLevelIdx] + "]"; + }); + } + } + + //console.log(measures.toSource()); + + var pivotDimensions = []; + + if(drillCell) { + var pivotQualifiedNames = $.grep(myself.query.getPivotDimensionQualifiedNames(), function(e){ return e != "MEASURES"; }); + + if(hasMoC) { + + var cdaHeaderParts = column.split("]/["); + var length = cdaHeaderParts.length; + if(length > 1) { + cdaHeaderParts[0] += "]"; + for(i = 1; i < length-1; i++) { + cdaHeaderParts[i] = "[" + cdaHeaderParts[i] + "]"; + } + cdaHeaderParts[length-1] = "[" + cdaHeaderParts[length-1]; + } + + //console.log(cdaHeaderParts.toSource()); + + var ht = new Array(); + var levelQualifiedNames = pivotQualifiedNames.slice().reverse(); + var previousHierarchy = ""; + var maxLevelDepth = 1; + for(i = 0; i < levelQualifiedNames.length; i++) { + var levelQualifiedName = levelQualifiedNames[i]; + + var hierarchy = levelQualifiedName.split("].[")[0].substring(1); + + if(levelQualifiedName.indexOf("].[") < 0) + hierarchy = hierarchy.substring(0, hierarchy.length-1); + + var index = -1; + $.each(cdaHeaderParts, function(j, w) { + if(w.indexOf("[" + hierarchy + "]") > -1 || w.indexOf("[" + hierarchy + "." + hierarchy + "]") > -1) { + index = j; + return; + } + }); + + //console.log(levelQualifiedName + " -> " + hierarchy + " -> " + index); + + ht[levelQualifiedName] = ""; + + if(index >= 0) { + var member = cdaHeaderParts[0]; + if(cdaHeaderParts.length > 1 || (member != "[Measures].[MeasuresLevel]" && $.inArray(member, pivotDimensionQualifiedNames) < 0)) { + var memberUniqueNameParts = cdaHeaderParts[index].split("].[").reverse(); + member = memberUniqueNameParts[0]; + member = member.substring(0, member.length-1); + if(hierarchy == previousHierarchy) { + member = memberUniqueNameParts[maxLevelDepth - myself.olapCube.getLevelDepth(levelQualifiedName)]; + } + } + ht[levelQualifiedName] = member; + + if(hierarchy != previousHierarchy) { + previousHierarchy = hierarchy; + maxLevelDepth = myself.olapCube.getLevelDepth(levelQualifiedName); + } + + } + + //console.log("ht[" + levelQualifiedName + "] = " + ht[levelQualifiedName]); + } + + $.each(pivotQualifiedNames, function(i, v) { + pivotDimensions.push([v, "include:[" + ht[v] + "]"]); + }); + + } else { + $.each(pivotQualifiedNames, function(i, v) { + var idx = $.inArray(v, $.map(rawData.metadata, function(e){ return e.colName })); + + //console.log(v + " @ " + idx); + + pivotDimensions.push([v, "include:[" + row[idx] + "]"]); + }); + } + + var pivotMeasuresIdx = myself.query.getPivotDimensionQualifiedNames().indexOf("MEASURES"); + //console.log(pivotMeasuresIdx); + if(pivotMeasuresIdx >= 0) + pivotDimensions.splice(pivotMeasuresIdx, 0, ["MEASURES", ""]); + + } else { + pivotDimensions = myself.query.getPivotDimensions(); + } + + //console.log(pivotDimensions.toSource()); + + var queryFilters = myself.query.getFilters(); + + var dimensions = $.grep(queryFilters, function(f) { + var qn = f[0]; + return qn == key || qn.split("].[")[0] == key.split("].[")[0]; + }); + + //console.log(dimensions.toSource()); + + var filters = $.grep(queryFilters, function(f) { + return f[0].split("].[")[0] != key.split("].[")[0]; + }); + + if(hasMoC) { + var dims = myself.query.getDimensionQualifiedNames(); + + if(dimensions.length == 0) { + var keyDepth = myself.olapCube.getLevelDepth(key); + var leftArr = []; + var rightArr = []; + + $.each(dims, function(i, v) { + // a level in query definition could not be found in query result if NON EMPTY is enabled, + // so row[i] wouldn't be the right element!!! + var idx = -1; + $.each($.map(rawData.metadata, function(e){ return e.colName }), function(j, w) { + if(w.indexOf(v) > -1) { + idx = j; + return; + } + }); + + //console.log(v + " @ " + idx); + + var el = [v, "include:[" + row[idx] + "]"]; + if(v.split("].[")[0] != key.split("].[")[0]) + filters.push(el); + else { + if(myself.olapCube.getLevelDepth(v) < keyDepth) + leftArr.push(el); + else + rightArr.push(el); + } + }); + + dimensions = leftArr.concat([[key, ""]], rightArr); + } + else { + $.each(dims, function(i, v) { + var idx = -1; + $.each($.map(rawData.metadata, function(e){ return e.colName }), function(j, w) { + if(w.indexOf(v) > -1) { + idx = j; + return; + } + }); + + //console.log(v + " @ " + idx); + + var filter = [v, "include:[" + row[idx] + "]"]; + filters.push(filter); + }); + + var keyDepth = myself.olapCube.getLevelDepth(key); + var leftArr = []; + var rightArr = []; + $.each(dimensions, function(i, v) { + var qn = v[0]; + if(myself.olapCube.getLevelDepth(qn) < keyDepth) + leftArr.push(v); + else + rightArr.push(v); + }); + dimensions = leftArr.concat([[key, ""]], rightArr); + } + + //console.log(dimensions.toSource()); + + } else { + //console.log("-------------------- drill cell MoD --------------------"); + //console.log(rowIdx + ":" + colIdx + " -> " + column + " -> " + value); + + var cdaHeaderParts = column.split("]/["); + var length = cdaHeaderParts.length; + if(length > 1) { + cdaHeaderParts[0] += "]"; + for(i = 1; i < length-1; i++) { + cdaHeaderParts[i] = "[" + cdaHeaderParts[i] + "]"; + } + cdaHeaderParts[length-1] = "[" + cdaHeaderParts[length-1]; + } + + //console.log(cdaHeaderParts.toSource()); + + var dimensionQualifiedNames = myself.query.getDimensionQualifiedNames(); + + var ht = new Array(); + var levelQualifiedNames = dimensionQualifiedNames.slice().reverse(); + var previousHierarchy = ""; + var maxLevelDepth = 1; + for(i = 0; i < levelQualifiedNames.length; i++) { + var levelQualifiedName = levelQualifiedNames[i]; + + var hierarchy = levelQualifiedName.split("].[")[0].substring(1); + + if(levelQualifiedName.indexOf("].[") < 0) + hierarchy = hierarchy.substring(0, hierarchy.length-1); + + var index = -1; + $.each(cdaHeaderParts, function(j, w) { + if(w.indexOf("[" + hierarchy + "]") > -1 || w.indexOf("[" + hierarchy + "." + hierarchy + "]") > -1) { + index = j; + return; + } + }); + + //console.log(levelQualifiedName + " -> " + hierarchy + " -> " + index); + + ht[levelQualifiedName] = ""; + + if(index >= 0) { + var member = cdaHeaderParts[0]; + if(cdaHeaderParts.length > 1 || (member != "[Measures].[MeasuresLevel]" && $.inArray(member, myself.query.getPivotDimensionQualifiedNames()) < 0)) { + var memberUniqueNameParts = cdaHeaderParts[index].split("].[").reverse(); + member = memberUniqueNameParts[0]; + member = member.substring(0, member.length-1); + if(hierarchy == previousHierarchy) { + member = memberUniqueNameParts[maxLevelDepth - myself.olapCube.getLevelDepth(levelQualifiedName)]; + } + } + ht[levelQualifiedName] = member; + + if(hierarchy != previousHierarchy) { + previousHierarchy = hierarchy; + maxLevelDepth = myself.olapCube.getLevelDepth(levelQualifiedName); + } + + } + + //console.log("ht[" + levelQualifiedName + "] = " + ht[levelQualifiedName]); + } + + if(dimensions.length == 0) { + var keyDepth = myself.olapCube.getLevelDepth(key); + var leftArr = []; + var rightArr = []; + + $.each(dimensionQualifiedNames, function(i, v) { + var el = [v, "include:[" + ht[v] + "]"]; + if(v.split("].[")[0] != key.split("].[")[0]) + filters.push(el); + else { + if(myself.olapCube.getLevelDepth(v) < keyDepth) + leftArr.push(el); + else + rightArr.push(el); + } + }); + + dimensions = leftArr.concat([[key, ""]], rightArr); + } + else { + $.each(dimensionQualifiedNames, function(i, v) { + filters.push([v, "include:[" + ht[v] + "]"]); + }); + + var keyDepth = myself.olapCube.getLevelDepth(key); + var leftArr = []; + var rightArr = []; + $.each(dimensions, function(i, v) { + var qn = v[0]; + if(myself.olapCube.getLevelDepth(qn) < keyDepth) + leftArr.push(v); + else + rightArr.push(v); + }); + dimensions = leftArr.concat([[key, ""]], rightArr); + } + + //console.log(dimensions.toSource()); + + //console.log("-----------------------------------------------------------"); + + } + + //console.log(filters.toSource()); + + var currentDimensions = myself.query.getDimensions(); + $.each(dimensions, function(i, v) { + var qn = v[0]; + if(v[1].indexOf("BT_TOTAL") > -1 || v[1].indexOf("undefined") > -1) { + var d = $.grep(currentDimensions, function(e) { + return e[0] == qn; + }); + v[1] = d[0][1]; + } + }); + + //console.log(dimensions.toSource()); + + var currentPivotDimensions = myself.query.getPivotDimensions(); + $.each(pivotDimensions, function(i, v) { + var qn = v[0]; + if(v[1].indexOf("BT_TOTAL") > -1 || v[1].indexOf("undefined") > -1) { + var d = $.grep(currentPivotDimensions, function(e) { + return e[0] == qn; + }); + v[1] = d[0][1]; + } + }); + + //console.log(pivotDimensions.toSource()); + + var currentAllDimensions = currentDimensions.concat(currentPivotDimensions); + + $.each(filters, function(i, v) { + var qn = v[0]; + if(v[1].indexOf("BT_TOTAL") > -1 || v[1].indexOf("undefined") > -1) { + var d = $.grep(currentAllDimensions, function(e) { + return e[0] == qn; + }); + v[1] = d[0][1]; + } + }); + + //console.log(filters.toSource()); + + + var querySetting = myself.query.getSettings(); + + var BTableDrillProp = {}; + BTableDrillProp.catalog = myself.properties.catalog; + BTableDrillProp.jndi = myself.properties.jndi; + BTableDrillProp.cube = myself.query.getCube(); + BTableDrillProp.dimensions = dimensions; + BTableDrillProp.measures = measures; + BTableDrillProp.pivotDimensions = pivotDimensions; + BTableDrillProp.filters = filters; + BTableDrillProp.measuresOnColumns = querySetting.measuresOnColumns; + BTableDrillProp.nonEmptyRows = querySetting.nonEmpty.rows; + BTableDrillProp.nonEmptyColumns = querySetting.nonEmpty.columns; + BTableDrillProp.grandTotal = querySetting.summary.grandTotal; + BTableDrillProp.subTotals = querySetting.summary.subTotals; + BTableDrillProp.pivotGrandTotal = querySetting.summary.pivotGrandTotal; + BTableDrillProp.pivotSubTotals = querySetting.summary.pivotSubTotals; + BTableDrillProp.totalsPosition = querySetting.summary.position; + BTableDrillProp.hideSpans = myself.properties.hideSpans; + + //console.log(BTableDrillProp); + + var urlQuery = getURLQuery(); + + var url = webAppPath + "/content/BTable/render?"; + url += "btdef=" + JSON.stringify(BTableDrillProp); + url += (urlQuery.hasOwnProperty("debug") && urlQuery.debug == "true") ? "&debug=true" : ""; + + //console.log(url); + + window.open(url, "_blank"); + //location.href = url; + //top.mantle_openTab("BTable Drill", "BTable Drill", url); + + }, + items: menu + } + }; + + myself.buildDrillMenu = function() { + var allLevels = myself.olapCube.getLevels(); + var queryDimensionLevels = myself.query.getDimensionQualifiedNames(); + var queryPivotLevels = myself.query.getPivotDimensionQualifiedNames(); + var queryLevels = queryDimensionLevels.concat(queryPivotLevels); + var newLevels = $.grep(allLevels, function(e, i) { + return queryLevels.indexOf(e.qualifiedName) < 0 && queryLevels.indexOf(e.qualifiedName.split("].[")[0] + "]") < 0; + }); + + var invalidHierachies = _.uniq($.map(queryPivotLevels, function(e, i) { + return e == "MEASURES" ? e : (e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1)); + })); + + //console.log(invalidHierachies); + + newLevels = $.grep(newLevels, function(e, i) { + return $.inArray(e.qualifiedName.split("].[")[0].substring(1), invalidHierachies) < 0; + }); + + //console.log(newLevels); + + var newLevelsAsObjects = $.map(newLevels, function(e, i) { + var qn = e.qualifiedName; + var qnParts = qn.split("].["); + var h = qnParts[0].substring(1); + var l = qnParts[1].substring(0, qnParts[1].length-1); + + return {hierarchy: h, level: l, qualifiedName: qn}; + }); + + var hierarchies = $.map(newLevelsAsObjects, function(e, i) { + return e.hierarchy; + }); + hierarchies = _.uniq(hierarchies); + hierarchies.sort(); + + //console.log(hierarchies); + + var menuMatrix = []; + $.each(newLevelsAsObjects, function(i, v) { + var h = v.hierarchy; + var l = v.level; + var qn = v.qualifiedName; + if(menuMatrix[h] == undefined) + menuMatrix[h] = []; + menuMatrix[h].push({name: l, qualifiedName: qn}); + }); + + //console.log(menuMatrix); + + var axisLevels = myself.query.getDimensionQualifiedNames(); + var axisHierarchies = $.map(axisLevels, function(e, i) { + return e == "MEASURES" ? e : (e.indexOf("].[") < 0 ? e.substring(1, e.length-1) : e.split("].[")[0].substring(1)); + }); + + //console.log(axisHierarchies); + + var menu = {}; + + $.each(hierarchies, function(i, hierarchy) { + var levels = menuMatrix[hierarchy]; + if(levels.length == 1 && levels[0].name == hierarchy) { + var newLevel = levels[0].qualifiedName; + menu[newLevel] = {}; + menu[newLevel].name = hierarchy; + } else { + menu[hierarchy] = {}; + menu[hierarchy].name = hierarchy; + menu[hierarchy].items = {}; + $.each(levels, function(j, level) { + var newLevel = level.qualifiedName; + menu[hierarchy].items[newLevel] = {}; + menu[hierarchy].items[newLevel].name = level.name; + }); + } + }); + + return menu; + } + + + myself.buildNoDataContextMenu = function(target) { + var menu = {}; + + menu.title = {name: "No data", callback: function(key, options) {}}; + menu.titlesep = "---"; + + menu.filters = { + name: "Manage Filters", + callback: function(key, options) { + myself.openFiltersSelectorPanel(""); + } + }; + + menu.toggleFilters = { + name: (myself.properties.showFilters ? "Hide" : "Show") + " Filters and Sorts", + callback: function() { + myself.properties.showFilters = !myself.properties.showFilters; + $("#" + myself.properties.filtersPanelHtmlObject).toggle(); + } + }; + + menu.settingssep = "---"; + var settingsMenu = myself.buildSettingsMenu(); + menu.settings = {name: "Table Settings", items: settingsMenu.items}; + + menu.mdx = { + name: "Show MDX", + callback: function(key, options) { + var html = "
" + Dashboards.getParameterValue(myself.properties.componentName.replace("render_", "") + "MdxQuery") + "
"; + $.fancybox(html, { + 'autoDimensions': true, + 'overlayShow': true, + 'hideOnOverlayClick': false, + 'hideOnContentClick': false, + 'enableEscapeButton': false, + 'showCloseButton': true, + }); + } + } + + menu.export2excel = { + name: "Export to Excel", + callback: function(key, options) { + myself.exportToExcel(); + } + }; + + menu.reset = { + name: "Reset", + callback: function() { + myself.query.reset(); + Dashboards.getComponent(myself.properties.componentName).update(); + } + }; + + return { + callback: function(key, options) {}, + items: menu + }; + }; + + + /* End ContextMenu Functions */ + + + myself.getBodyRowspans = function() { + var metadata = normalizedCdaResult.metadata; + var resultset = normalizedCdaResult.resultset; + + var querySettings = myself.query.getSettings(); + var hasMoC = querySettings.measuresOnColumns; + var hasGrandTotal = querySettings.summary.grandTotal; + var hasSubTotals = querySettings.summary.subTotals; + var totalsAtTop = querySettings.summary.position == "top"; + + var zippedRows = []; + + if(!myself.properties.hideSpans) { + var colNames = $.map(metadata, function(m){ return m.colName; }); + var maxIdx = -1; + if(hasMoC) { + var dimQns = myself.query.getDimensionQualifiedNames(); + $.each(colNames, function(i, cn) { + if($.inArray(cn, dimQns) > -1) + maxIdx = i; + }); + } else { + var pivotQns = myself.query.getPivotDimensionQualifiedNames(); + $.each(colNames, function(i, cn) { + if($.inArray(cn, pivotQns) > -1 || cn == "[Measures].[MeasuresLevel]") + maxIdx = i; + }); + } + + for(i = 0; i < maxIdx; i++) { + zippedRows[i] = []; + var len = resultset.length; + var count = 1; + var prevValue = len > 0 ? resultset[0][i] : ""; + var start = 1; + + if(totalsAtTop && hasGrandTotal && prevValue != "") { + zippedRows[i].push({value: prevValue, rowspan: 1}); + prevValue = resultset[1][i]; + start = 2; + } + + for(j = start; j < len; j++) { + var value = resultset[j][i]; + if(value != prevValue) { + zippedRows[i].push({value: prevValue, rowspan: count}); + count = 0; + } + count++; + prevValue = value; + } + if(prevValue != "") { + if(!totalsAtTop && hasGrandTotal && prevValue == "BT_TOTAL" && count == 2) { + zippedRows[i].push({value: prevValue, rowspan: 1}); + zippedRows[i].push({value: prevValue, rowspan: 1}); + } + else + zippedRows[i].push({value: prevValue, rowspan: count}); + } + } + } + + return zippedRows; + } + + var setExportStyle = function(exportStyle) { + var defaultStyle = { + rules: [ + {selector: "table", properties: [{name: "border-collapse", value: "collapse"}]}, + {selector: "th", properties: [{name: "border", value: "1px solid #000"}, {name: "background-color", value: "#C3D9FF"}]}, + {selector: "td", properties: [{name: "border", value: "1px solid #000"}]}, + {selector: "tbody tr.odd td", properties: [{name: "background-color", value: "#E2E4FF"}]}, + {selector: "tbody tr.even td", properties: [{name: "background-color", value: "#FFFFFF"}]}, + {selector: "td.string", properties: [{name: "font-family", value: "Arial, serif"}, {name: "font-size", value: "12px"}]}, + {selector: "td.numeric", properties: [{name: "font-family", value: "Arial, serif"}, {name: "font-size", value: "12px"}, {name: "padding-right", value: "4px"}]}, + {selector: "td.subtotal", properties: [{name: "font-weight", value: "bold"}]}, + {selector: "tr.odd td.grandtotal", properties: [{name: "font-weight", value: "bold"}, {name: "background-color", value: "#C3D9FF"}]}, + {selector: "tr.even td.grandtotal", properties: [{name: "font-weight", value: "bold"}, {name: "background-color", value: "#C3D9FF"}]}, + {selector: ".filtersTitle", properties: [{name: "font-weight", value: "bold"}, {name: "color", value: "black"}]}, + {selector: ".hierarchy", properties: [{name: "font-weight", value: "bold"}, {name: "color", value: "blue"}]}, + {selector: ".separator", properties: [{name: "font-weight", value: "normal"}, {name: "color", value: "blue"}]}, + {selector: ".level", properties: [{name: "font-weight", value: "bold"}, {name: "color", value: "red"}]}, + {selector: ".filter", properties: [{name: "font-weight", value: "normal"}]} + ] + }; + + var tmpDiv = $("#" + myself.properties.componentHtmlObject + "_eXtmp"); + var rules = exportStyle.hasOwnProperty("rules") ? exportStyle.rules : defaultStyle.rules; + $.each(rules, function(i, v) { + var obj = tmpDiv.find(v.selector); + if(obj.length > 0) { + $.each(v.properties, function(j, w) { + obj.css(w.name, w.value); + }); + } + }); + } + + myself.exportToExcel = function() { + var html = $("#" + myself.properties.filtersPanelHtmlObject).html() + $("#" + myself.properties.componentHtmlObject).html(); + var tmpId = myself.properties.componentHtmlObject + "_eXtmp"; + var tmpObj = $("" ); + $("#" + myself.properties.componentHtmlObject).after(tmpObj); + setExportStyle(myself.properties.exportStyle); + tmpObj.find("img").remove(); + var tmpHtml = tmpObj.html(); + tmpObj.remove(); + window.open("data:application/vnd.ms-excel," + encodeURIComponent(tmpHtml)); + } + + return myself; +} diff --git a/resources/components/BTable/lib/bt.utils.js b/resources/components/BTable/lib/bt.utils.js new file mode 100644 index 0000000..0245289 --- /dev/null +++ b/resources/components/BTable/lib/bt.utils.js @@ -0,0 +1,247 @@ +/* + * Copyright 2013 Biz Tech (http://www.biztech.it). All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + * If a copy of the MPL was not distributed with this file, You can obtain one at + * http://mozilla.org/MPL/2.0/. + * + * Covered Software is provided under this License on an “as is” basis, + * without warranty of any kind, either expressed, implied, or statutory, + * including, without limitation, warranties that the Covered Software is + * free of defects, merchantable, fit for a particular purpose or non-infringing. + * The entire risk as to the quality and performance of the Covered Software is with You. + * Should any Covered Software prove defective in any respect, You (not any Contributor) + * assume the cost of any necessary servicing, repair, or correction. + * This disclaimer of warranty constitutes an essential part of this License. + * No use of any Covered Software is authorized under this License except under this disclaimer. + * + * Initial contributors: Luca Pazzaglia, Massimo Bonometto + * + * This file includes a modification of + * https://github.com/webdetails/cde/blob/13.03.25/server/plugin/resource/resources/custom/components/OlapSelector/lib/OlapUtils.js + */ + + +var bt = bt || {}; +bt.utils = bt.utils || {}; + +bt.utils.OlapUtils = function(spec) { + + var defaults = { + url: "OlapUtils", + extraParams: {} + }; + + var myself = {}; + + myself.options = $.extend({}, defaults, spec); + + var catalog = myself.options.catalog; + var cube = myself.options.cube; + + var cubeStructureCache = {}; + + var olapOperations = { + GET_CUBE_STRUCTURE: 'GetCubeStructure', + GET_PAGINATED_LEVEL_MEMBERS: 'GetPaginatedLevelMembers', + GET_MEMBER_STRUCTURE: 'GetLevelMembersStructure', + GET_OLAP_CUBES: 'GetOlapCubes' + }; + + myself.setOptions = function(_args) { + myself.options = $.extend(myself.options,_args); + } + + myself.getOlapUtilsUrl = function() { + return myself.options.url + }; + + myself.getCubeStructure = function(_args) { + var catalog = myself.getSelectedCatalogName(_args); + + var cube = myself.getSelectedCubeName(_args); + var cacheKey = catalog + "::" + cube; + + if(!catalog || !cube) { + return null; + } + + if(cubeStructureCache[cacheKey]) { + return cubeStructureCache[cacheKey]; + } + + var params = { + operation: olapOperations.GET_CUBE_STRUCTURE, + catalog: catalog, + cube: cube + }; + + // make a sync call + var result = myself.callOlapUtilsSync(params); + + cubeStructureCache[cacheKey] = result; + + return result; + } + + myself.getSelectedCatalogName = function(_args) { + var catalog = $.extend({}, myself.options, _args).catalog; + + if(catalog.charAt(0) == '/'){ + catalog = 'solution:' + catalog.substring(1); + } + else { + catalog = 'solution:' + catalog; + } + + return catalog; + }; + + myself.getSelectedCubeName = function(_args) { + return $.extend({},myself.options,_args).cube; + }; + + myself.callOlapUtilsSync = function(params) { + return myself.callOlapUtils(params, undefined, undefined, true); + } + + myself.callOlapUtils = function(params, callback, errorCallback, sync) { + var myself = this; + + var ret; + + $.ajax({ + url: myself.getOlapUtilsUrl(), + data: $.extend({}, myself.options.extraParams, params), + dataType: "json", + success: function(json){ + if(json && json.status == "true" && json.result) { + + // sync only sets the value + if(sync){ + ret = json.result + } + else{ + callback(json.result); + } + } + else { + if(typeof(errorCallback) != 'function' ) errorCallback = alert; + return errorCallback(json); + } + }, + async: !sync + }); + + return ret; + }; + + myself.getCube = function(_args) { + return myself.getCubeStructure(_args); + } + + myself.getLevelMembers = function(_args, callback){ + + var defaults = { + operation: 'GetLevelMembers', + } + + var params = $.extend({},defaults,_args); + + params.catalog = myself.getSelectedCatalogName(_args); + params.cube = myself.getSelectedCubeName(_args); + + params.member = params.level; + + var result = myself.callOlapUtilsSync(params); + + return result; + }; + + + return myself; + +} + + +function getURLQuery() { + var query = {}; + var conditions = window.location.search.slice(1).split('&'); + $.each(conditions, function(i, c) { + var condition = c.split('='); + query[condition[0]] = decodeURIComponent(condition[1]); + }); + return query; +} + + +function getTimer(spec) { + var defaults = { + log: true, + component: { + type: "BTable", + name: "" + }, + }; + + var myself = {}; + + myself.options = $.extend({}, defaults, spec); + + var startDate = null; + var prevDate = null; + var lastDate = null; + var lastElapsedTime = 0; + var totalElapsedTime = 0; + + myself.start = function(message) { + startDate = new Date(); + prevDate = startDate; + lastDate = startDate; + lastElapsedTime = 0; + totalElapsedTime = 0; + if(myself.options.log) + myself.log("START", message); + }; + + myself.check = function(message) { + if(startDate != null) { + lastDate = new Date(); + lastElapsedTime = lastDate.getTime() - prevDate.getTime(); + totalElapsedTime = lastDate.getTime() - startDate.getTime(); + prevDate = lastDate; + if(myself.options.log) + myself.log("CHECK", message); + } else { + console.log("You have missed to start timer for component '" + myself.options.component.name + "' !"); + } + }; + + myself.log = function(action, message) { + var text = "TIMER." + action + " [" + myself.options.component.type + ": " + myself.options.component.name + "] >> " + message + " @ " + myself.formatDate(lastDate); + if (action == "CHECK") + text += " (" + myself.formatTime(lastElapsedTime) + " since last check, " + myself.formatTime(totalElapsedTime) + " since start)"; + console.log(text); + }; + + myself.formatDate = function(date) { + var year = date.getFullYear(); + var month = date.getMonth() + 1; + var day = date.getDate(); + var hours = date.getHours(); + var minutes = date.getMinutes(); + var seconds = date.getSeconds(); + var milliseconds = date.getMilliseconds(); + + return year + "/" + (month < 10 ? "0" : "") + month + "/" + (day < 10 ? "0" : "") + day + + " " + (hours < 10 ? "0" : "") + hours + ":" + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds + + "." + (milliseconds < 10 ? "00" : (milliseconds < 100 ? "0" : "")) + milliseconds; + } + + myself.formatTime = function(milliseconds) { + var seconds = milliseconds / 1000; + return seconds + " s"; + } + + return myself; +} diff --git a/resources/components/BTable/lib/btable.css b/resources/components/BTable/lib/btable.css new file mode 100644 index 0000000..808b9a9 --- /dev/null +++ b/resources/components/BTable/lib/btable.css @@ -0,0 +1,219 @@ +/************************* CONTEXT MENU *************************/ + +.data-title:before { + content: attr(data-menutitle); + display: block; + position: absolute; + top: 0; + right: 0; + left: 0; + background: #DDD; + padding: 2px; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; + font-weight: bold; +} + +.data-title :first-child { + margin-top: 20px; +} + +.menu-with-title > li:first-child { + cursor: default; + background-color: #EEE; +} + +.menu-with-title > li:first-child ~ li:first-child { + cursor: pointer; + background-color: #39F; +} + +.context-menu-item label { + font-weight: normal; +} + + +/******************** FILTERS PANEL ********************/ + +.filtersPanel { + margin-bottom: 10px; +} + +.filtersPanel .filtersTitle { + font-weight: bold; + color: black; +} + +.filtersPanel .hierarchy { + font-weight: bold; + color: blue; +} + +.filtersPanel .separator { + font-weight: normal; + color: blue; +} + +.filtersPanel .level { + font-weight: bold; + color: red; +} + +.filtersPanel .filter { + font-weight: normal; +} + +img.sortIcon { + width: 16px; + height: 16px; + vertical-align: middle; + cursor: pointer; +} + +img.lockedIcon { + width: 10px; + height: 12px; +} + +img.unlockedIcon { + width: 14px; + height: 12px; +} + + +/******************** FILTERS SELECTOR PANEL ********************/ + +#filtersSelectorPanel { + width: 850px; + height: 500px; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; +} + +#filtersSelectorPanel .topBox { + width: 100%; + height: 6%; +} + +#filtersSelectorPanel .topBoxLeft { + width: 36%; + height: 100%; + float: left; +} + +#filtersSelectorPanel .topBoxRight { + width: 60%; + height: 100%; + float: left; + padding-left: 4%; +} + +#filtersSelectorPanel .centralBox { + width: 100%; + height: 94%; +} + +#filtersSelectorPanel .centralBoxLeft { + width: 36%; + height: 100%; + float: left; + overflow: auto; +} + +#filtersSelectorPanel .centralBoxRight { + width: 60%; + height: 100%; + float: left; + overflow: auto; + padding-left: 4%; +} + +.btTitle { + font-size: 14px; + font-weight: bold; + margin-right: 10px; +} + +.centralBoxLeft li { + padding: 3px; +} + +.list-item-level { + cursor: pointer; +} + +.list-item-selected { + padding: 3px; + border: 1px solid #AED0EA; + border-radius: 4px 4px 4px 4px; + background-color: #E6F2FB; +} + +.filterModeBar { + width: 480px; + margin-bottom: 30px; +} +.filterModeBar div { + float: left; + margin-right: 16px; +} + +.list-item-filterInfo { + font-style: italic; + color: red; + margin-left: 6px; +} + +.updateFilterBar { + width: 480px; + text-align: right; + margin-top: 14px; +} + + +/******************** MDX PANEL ********************/ + +.mdxPanel { + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; +} + + +/************************* TABLE *************************/ + +.bTableComponent .dataTables_wrapper { + min-height:0; +} +.bTableComponent table { + border-collapse: collapse; +} +.bTableComponent th { + border: 1px solid #000; + background-color: #C3D9FF; +} +.bTableComponent td { + border: 1px solid #000; +} +.bTableComponent tbody tr.odd td { + background-color: #E2E4FF; +} +.bTableComponent tbody tr.even td { + background-color: #FFFFFF; +} +.bTableComponent td.string { + font-family: Arial, serif; + font-size: 12px; +} +.bTableComponent td.numeric { + font-family: Arial, serif; + font-size: 12px; + padding-right: 4px; +} +.bTableComponent td.subtotal { + font-weight: bold; +} +.bTableComponent tr.odd td.grandtotal, +.bTableComponent tr.even td.grandtotal { + font-weight: bold; + background-color: #C3D9FF; +} diff --git a/resources/components/BTable/lib/hynds/jquery.multiselect.filter.css b/resources/components/BTable/lib/hynds/jquery.multiselect.filter.css new file mode 100644 index 0000000..6accd5a --- /dev/null +++ b/resources/components/BTable/lib/hynds/jquery.multiselect.filter.css @@ -0,0 +1,3 @@ +.ui-multiselect-hasfilter ul { position:relative; top:2px } +.ui-multiselect-filter { float:left; margin-right:10px;/* font-size:11px*/ } +.ui-multiselect-filter input { width:100px;/* font-size:10px;*/ margin-left:5px; height:15px; padding:2px; border:1px solid #292929; -webkit-appearance:textfield; -webkit-box-sizing:content-box; } diff --git a/resources/components/BTable/lib/hynds/jquery.multiselect.filter.js b/resources/components/BTable/lib/hynds/jquery.multiselect.filter.js new file mode 100644 index 0000000..1560700 --- /dev/null +++ b/resources/components/BTable/lib/hynds/jquery.multiselect.filter.js @@ -0,0 +1,174 @@ +/* jshint forin:true, noarg:true, noempty:true, eqeqeq:true, boss:true, undef:true, curly:true, browser:true, jquery:true */ +/* + * jQuery MultiSelect UI Widget Filtering Plugin 1.5pre + * Copyright (c) 2012 Eric Hynds + * + * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/ + * + * Depends: + * - jQuery UI MultiSelect widget + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ +(function($) { + var rEscape = /[\-\[\]{}()*+?.,\\\^$|#\s]/g; + + $.widget('ech.multiselectfilter', { + + options: { + label: 'Filter:', + width: null, /* override default width set in css file (px). null will inherit */ + placeholder: 'Enter keywords', + autoReset: false + }, + + _create: function() { + var opts = this.options; + var elem = $(this.element); + + // get the multiselect instance + var instance = (this.instance = (elem.data('echMultiselect') || elem.data("multiselect") || elem.data("ech-multiselect"))); + + // store header; add filter class so the close/check all/uncheck all links can be positioned correctly + var header = (this.header = instance.menu.find('.ui-multiselect-header').addClass('ui-multiselect-hasfilter')); + + // wrapper elem + var wrapper = (this.wrapper = $('
' + (opts.label.length ? opts.label : '') + '
').prependTo(this.header)); + + // reference to the actual inputs + this.inputs = instance.menu.find('input[type="checkbox"], input[type="radio"]'); + + // build the input box + this.input = wrapper.find('input').bind({ + keydown: function(e) { + // prevent the enter key from submitting the form / closing the widget + if(e.which === 13) { + e.preventDefault(); + } + }, + keyup: $.proxy(this._handler, this), + click: $.proxy(this._handler, this) + }); + + // cache input values for searching + this.updateCache(); + + // rewrite internal _toggleChecked fn so that when checkAll/uncheckAll is fired, + // only the currently filtered elements are checked + instance._toggleChecked = function(flag, group) { + var $inputs = (group && group.length) ? group : this.labels.find('input'); + var _self = this; + + // do not include hidden elems if the menu isn't open. + var selector = instance._isOpen ? ':disabled, :hidden' : ':disabled'; + + $inputs = $inputs + .not(selector) + .each(this._toggleState('checked', flag)); + + // update text + this.update(); + + // gather an array of the values that actually changed + var values = $inputs.map(function() { + return this.value; + }).get(); + + // select option tags + this.element.find('option').filter(function() { + if(!this.disabled && $.inArray(this.value, values) > -1) { + _self._toggleState('selected', flag).call(this); + } + }); + + // trigger the change event on the select + if($inputs.length) { + this.element.trigger('change'); + } + }; + + // rebuild cache when multiselect is updated + var doc = $(document).bind('multiselectrefresh', $.proxy(function() { + this.updateCache(); + this._handler(); + }, this)); + + // automatically reset the widget on close? + if(this.options.autoReset) { + doc.bind('multiselectclose', $.proxy(this._reset, this)); + } + }, + + // thx for the logic here ben alman + _handler: function(e) { + var term = $.trim(this.input[0].value.toLowerCase()), + + // speed up lookups + rows = this.rows, inputs = this.inputs, cache = this.cache; + + if(!term) { + rows.show(); + } else { + rows.hide(); + + var regex = new RegExp(term.replace(rEscape, "\\$&"), 'gi'); + + this._trigger("filter", e, $.map(cache, function(v, i) { + if(v.search(regex) !== -1) { + rows.eq(i).show(); + return inputs.get(i); + } + + return null; + })); + } + + // show/hide optgroups + this.instance.menu.find(".ui-multiselect-optgroup-label").each(function() { + var $this = $(this); + var isVisible = $this.nextUntil('.ui-multiselect-optgroup-label').filter(function() { + return $.css(this, "display") !== 'none'; + }).length; + + $this[isVisible ? 'show' : 'hide'](); + }); + }, + + _reset: function() { + this.input.val('').trigger('keyup'); + }, + + updateCache: function() { + // each list item + this.rows = this.instance.menu.find(".ui-multiselect-checkboxes li:not(.ui-multiselect-optgroup-label)"); + + // cache + this.cache = this.element.children().map(function() { + var elem = $(this); + + // account for optgroups + if(this.tagName.toLowerCase() === "optgroup") { + elem = elem.children(); + } + + return elem.map(function() { + return this.innerHTML.toLowerCase(); + }).get(); + }).get(); + }, + + widget: function() { + return this.wrapper; + }, + + destroy: function() { + $.Widget.prototype.destroy.call(this); + this.input.val('').trigger("keyup"); + this.wrapper.remove(); + } + }); + +})(jQuery); diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/cut.png b/resources/components/BTable/lib/jQuery-contextMenu/images/cut.png new file mode 100644 index 0000000..f215d6f Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/cut.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/door.png b/resources/components/BTable/lib/jQuery-contextMenu/images/door.png new file mode 100644 index 0000000..369fc46 Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/door.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_add.png b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_add.png new file mode 100644 index 0000000..a70de09 Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_add.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_copy.png b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_copy.png new file mode 100644 index 0000000..a9f31a2 Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_copy.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_delete.png b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_delete.png new file mode 100644 index 0000000..af1ecaf Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_delete.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_edit.png b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_edit.png new file mode 100644 index 0000000..b93e776 Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_edit.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_paste.png b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_paste.png new file mode 100644 index 0000000..5b2cbb3 Binary files /dev/null and b/resources/components/BTable/lib/jQuery-contextMenu/images/page_white_paste.png differ diff --git a/resources/components/BTable/lib/jQuery-contextMenu/jquery.contextMenu.css b/resources/components/BTable/lib/jQuery-contextMenu/jquery.contextMenu.css new file mode 100644 index 0000000..ee58116 --- /dev/null +++ b/resources/components/BTable/lib/jQuery-contextMenu/jquery.contextMenu.css @@ -0,0 +1,142 @@ +/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: git-master + * + * Authors: Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://medialize.github.com/jQuery-contextMenu/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ + +.context-menu-list { + margin:0; + padding:0; + + min-width: 120px; + max-width: 250px; + display: inline-block; + position: absolute; + list-style-type: none; + + border: 1px solid #DDD; + background: #EEE; + + -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; +} + +.context-menu-item { + padding: 2px 2px 2px 24px; + background-color: #EEE; + position: relative; + -webkit-user-select: none; + -moz-user-select: -moz-none; + -ms-user-select: none; + user-select: none; +} + +.context-menu-separator { + padding-bottom:0; + border-bottom: 1px solid #DDD; +} + +.context-menu-item > label > input, +.context-menu-item > label > textarea { + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.context-menu-item.hover { + cursor: pointer; + background-color: #39F; +} + +.context-menu-item.disabled { + color: #666; +} + +.context-menu-input.hover, +.context-menu-item.disabled.hover { + cursor: default; + background-color: #EEE; +} + +.context-menu-submenu:after { + content: ">"; + color: #666; + position: absolute; + top: 0; + right: 3px; + z-index: 1; +} + +/* icons + #protip: + In case you want to use sprites for icons (which I would suggest you do) have a look at + http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement + .context-menu-item.icon:before {} + */ +.context-menu-item.icon { min-height: 18px; background-repeat: no-repeat; background-position: 4px 2px; } +.context-menu-item.icon-edit { background-image: url(images/page_white_edit.png); } +.context-menu-item.icon-cut { background-image: url(images/cut.png); } +.context-menu-item.icon-copy { background-image: url(images/page_white_copy.png); } +.context-menu-item.icon-paste { background-image: url(images/page_white_paste.png); } +.context-menu-item.icon-delete { background-image: url(images/page_white_delete.png); } +.context-menu-item.icon-add { background-image: url(images/page_white_add.png); } +.context-menu-item.icon-quit { background-image: url(images/door.png); } + +/* vertically align inside labels */ +.context-menu-input > label > * { vertical-align: top; } + +/* position checkboxes and radios as icons */ +.context-menu-input > label > input[type="checkbox"], +.context-menu-input > label > input[type="radio"] { + margin-left: -17px; +} +.context-menu-input > label > span { + margin-left: 5px; +} + +.context-menu-input > label, +.context-menu-input > label > input[type="text"], +.context-menu-input > label > textarea, +.context-menu-input > label > select { + display: block; + width: 100%; + + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + -ms-box-sizing: border-box; + -o-box-sizing: border-box; + box-sizing: border-box; +} + +.context-menu-input > label > textarea { + height: 100px; +} +.context-menu-item > .context-menu-list { + display: none; + /* re-positioned by js */ + right: -5px; + top: 5px; +} + +.context-menu-item.hover > .context-menu-list { + display: block; +} + +.context-menu-accesskey { + text-decoration: underline; +} diff --git a/resources/components/BTable/lib/jQuery-contextMenu/jquery.contextMenu.js b/resources/components/BTable/lib/jQuery-contextMenu/jquery.contextMenu.js new file mode 100644 index 0000000..9f92350 --- /dev/null +++ b/resources/components/BTable/lib/jQuery-contextMenu/jquery.contextMenu.js @@ -0,0 +1,1688 @@ +/*! + * jQuery contextMenu - Plugin for simple contextMenu handling + * + * Version: git-master + * + * Authors: Rodney Rehm, Addy Osmani (patches for FF) + * Web: http://medialize.github.com/jQuery-contextMenu/ + * + * Licensed under + * MIT License http://www.opensource.org/licenses/mit-license + * GPL v3 http://opensource.org/licenses/GPL-3.0 + * + */ + +(function($, undefined){ + + // TODO: - + // ARIA stuff: menuitem, menuitemcheckbox und menuitemradio + // create structure if $.support[htmlCommand || htmlMenuitem] and !opt.disableNative + +// determine html5 compatibility +$.support.htmlMenuitem = ('HTMLMenuItemElement' in window); +$.support.htmlCommand = ('HTMLCommandElement' in window); +$.support.eventSelectstart = ("onselectstart" in document.documentElement); +/* // should the need arise, test for css user-select +$.support.cssUserSelect = (function(){ + var t = false, + e = document.createElement('div'); + + $.each('Moz|Webkit|Khtml|O|ms|Icab|'.split('|'), function(i, prefix) { + var propCC = prefix + (prefix ? 'U' : 'u') + 'serSelect', + prop = (prefix ? ('-' + prefix.toLowerCase() + '-') : '') + 'user-select'; + + e.style.cssText = prop + ': text;'; + if (e.style[propCC] == 'text') { + t = true; + return false; + } + + return true; + }); + + return t; +})(); +*/ + +if (!$.ui || !$.ui.widget) { + // duck punch $.cleanData like jQueryUI does to get that remove event + // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js#L16-24 + var _cleanData = $.cleanData; + $.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); + }; +} + +var // currently active contextMenu trigger + $currentTrigger = null, + // is contextMenu initialized with at least one menu? + initialized = false, + // window handle + $win = $(window), + // number of registered menus + counter = 0, + // mapping selector to namespace + namespaces = {}, + // mapping namespace to options + menus = {}, + // custom command type handlers + types = {}, + // default values + defaults = { + // selector of contextMenu trigger + selector: null, + // where to append the menu to + appendTo: null, + // method to trigger context menu ["right", "left", "hover"] + trigger: "right", + // hide menu when mouse leaves trigger / menu elements + autoHide: false, + // ms to wait before showing a hover-triggered context menu + delay: 200, + // flag denoting if a second trigger should simply move (true) or rebuild (false) an open menu + // as long as the trigger happened on one of the trigger-element's child nodes + reposition: true, + // determine position to show menu at + determinePosition: function($menu) { + // position to the lower middle of the trigger element + if ($.ui && $.ui.position) { + // .position() is provided as a jQuery UI utility + // (...and it won't work on hidden elements) + $menu.css('display', 'block').position({ + my: "center top", + at: "center bottom", + of: this, + offset: "0 5", + collision: "fit" + }).css('display', 'none'); + } else { + // determine contextMenu position + var offset = this.offset(); + offset.top += this.outerHeight(); + offset.left += this.outerWidth() / 2 - $menu.outerWidth() / 2; + $menu.css(offset); + } + }, + // position menu + position: function(opt, x, y) { + var $this = this, + offset; + // determine contextMenu position + if (!x && !y) { + opt.determinePosition.call(this, opt.$menu); + return; + } else if (x === "maintain" && y === "maintain") { + // x and y must not be changed (after re-show on command click) + offset = opt.$menu.position(); + } else { + // x and y are given (by mouse event) + offset = {top: y, left: x}; + } + + // correct offset if viewport demands it + var bottom = $win.scrollTop() + $win.height(), + right = $win.scrollLeft() + $win.width(), + height = opt.$menu.height(), + width = opt.$menu.width(); + + if (offset.top + height > bottom) { + offset.top -= height; + } + + if (offset.left + width > right) { + offset.left -= width; + } + + opt.$menu.css(offset); + }, + // position the sub-menu + positionSubmenu: function($menu) { + if ($.ui && $.ui.position) { + // .position() is provided as a jQuery UI utility + // (...and it won't work on hidden elements) + $menu.css('display', 'block').position({ + my: "left top", + at: "right top", + of: this, + collision: "flipfit fit" + }).css('display', ''); + } else { + // determine contextMenu position + var offset = { + top: 0, + left: this.outerWidth() + }; + $menu.css(offset); + } + }, + // offset to add to zIndex + zIndex: 1, + // show hide animation settings + animation: { + duration: 50, + show: 'slideDown', + hide: 'slideUp' + }, + // events + events: { + show: $.noop, + hide: $.noop + }, + // default callback + callback: null, + // list of contextMenu items + items: {} + }, + // mouse position for hover activation + hoveract = { + timer: null, + pageX: null, + pageY: null + }, + // determine zIndex + zindex = function($t) { + var zin = 0, + $tt = $t; + + while (true) { + zin = Math.max(zin, parseInt($tt.css('z-index'), 10) || 0); + $tt = $tt.parent(); + if (!$tt || !$tt.length || "html body".indexOf($tt.prop('nodeName').toLowerCase()) > -1 ) { + break; + } + } + + return zin; + }, + // event handlers + handle = { + // abort anything + abortevent: function(e){ + e.preventDefault(); + e.stopImmediatePropagation(); + }, + + // contextmenu show dispatcher + contextmenu: function(e) { + var $this = $(this); + + // disable actual context-menu + e.preventDefault(); + e.stopImmediatePropagation(); + + // abort native-triggered events unless we're triggering on right click + if (e.data.trigger != 'right' && e.originalEvent) { + return; + } + + // abort event if menu is visible for this trigger + if ($this.hasClass('context-menu-active')) { + return; + } + + if (!$this.hasClass('context-menu-disabled')) { + // theoretically need to fire a show event at + // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus + // var evt = jQuery.Event("show", { data: data, pageX: e.pageX, pageY: e.pageY, relatedTarget: this }); + // e.data.$menu.trigger(evt); + + $currentTrigger = $this; + if (e.data.build) { + var built = e.data.build($currentTrigger, e); + // abort if build() returned false + if (built === false) { + return; + } + + // dynamically build menu on invocation + e.data = $.extend(true, {}, defaults, e.data, built || {}); + + // abort if there are no items to display + if (!e.data.items || $.isEmptyObject(e.data.items)) { + // Note: jQuery captures and ignores errors from event handlers + if (window.console) { + (console.error || console.log)("No items specified to show in contextMenu"); + } + + throw new Error('No Items sepcified'); + } + + // backreference for custom command type creation + e.data.$trigger = $currentTrigger; + + op.create(e.data); + } + // show menu + op.show.call($this, e.data, e.pageX, e.pageY); + } + }, + // contextMenu left-click trigger + click: function(e) { + e.preventDefault(); + e.stopImmediatePropagation(); + $(this).trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY })); + }, + // contextMenu right-click trigger + mousedown: function(e) { + // register mouse down + var $this = $(this); + + // hide any previous menus + if ($currentTrigger && $currentTrigger.length && !$currentTrigger.is($this)) { + $currentTrigger.data('contextMenu').$menu.trigger('contextmenu:hide'); + } + + // activate on right click + if (e.button == 2) { + $currentTrigger = $this.data('contextMenuActive', true); + } + }, + // contextMenu right-click trigger + mouseup: function(e) { + // show menu + var $this = $(this); + if ($this.data('contextMenuActive') && $currentTrigger && $currentTrigger.length && $currentTrigger.is($this) && !$this.hasClass('context-menu-disabled')) { + e.preventDefault(); + e.stopImmediatePropagation(); + $currentTrigger = $this; + $this.trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY })); + } + + $this.removeData('contextMenuActive'); + }, + // contextMenu hover trigger + mouseenter: function(e) { + var $this = $(this), + $related = $(e.relatedTarget), + $document = $(document); + + // abort if we're coming from a menu + if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) { + return; + } + + // abort if a menu is shown + if ($currentTrigger && $currentTrigger.length) { + return; + } + + hoveract.pageX = e.pageX; + hoveract.pageY = e.pageY; + hoveract.data = e.data; + $document.on('mousemove.contextMenuShow', handle.mousemove); + hoveract.timer = setTimeout(function() { + hoveract.timer = null; + $document.off('mousemove.contextMenuShow'); + $currentTrigger = $this; + $this.trigger($.Event("contextmenu", { data: hoveract.data, pageX: hoveract.pageX, pageY: hoveract.pageY })); + }, e.data.delay ); + }, + // contextMenu hover trigger + mousemove: function(e) { + hoveract.pageX = e.pageX; + hoveract.pageY = e.pageY; + }, + // contextMenu hover trigger + mouseleave: function(e) { + // abort if we're leaving for a menu + var $related = $(e.relatedTarget); + if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) { + return; + } + + try { + clearTimeout(hoveract.timer); + } catch(e) {} + + hoveract.timer = null; + }, + + // click on layer to hide contextMenu + layerClick: function(e) { + var $this = $(this), + root = $this.data('contextMenuRoot'), + mouseup = false, + button = e.button, + x = e.pageX, + y = e.pageY, + target, + offset, + selectors; + + e.preventDefault(); + e.stopImmediatePropagation(); + + setTimeout(function() { + var $window, hideshow, possibleTarget; + var triggerAction = ((root.trigger == 'left' && button === 0) || (root.trigger == 'right' && button === 2)); + + // find the element that would've been clicked, wasn't the layer in the way + if (document.elementFromPoint) { + root.$layer.hide(); + target = document.elementFromPoint(x - $win.scrollLeft(), y - $win.scrollTop()); + root.$layer.show(); + } + + if (root.reposition && triggerAction) { + if (document.elementFromPoint) { + if (root.$trigger.is(target) || root.$trigger.has(target).length) { + root.position.call(root.$trigger, root, x, y); + return; + } + } else { + offset = root.$trigger.offset(); + $window = $(window); + // while this looks kinda awful, it's the best way to avoid + // unnecessarily calculating any positions + offset.top += $window.scrollTop(); + if (offset.top <= e.pageY) { + offset.left += $window.scrollLeft(); + if (offset.left <= e.pageX) { + offset.bottom = offset.top + root.$trigger.outerHeight(); + if (offset.bottom >= e.pageY) { + offset.right = offset.left + root.$trigger.outerWidth(); + if (offset.right >= e.pageX) { + // reposition + root.position.call(root.$trigger, root, x, y); + return; + } + } + } + } + } + } + + if (target && triggerAction) { + root.$trigger.one('contextmenu:hidden', function() { + $(target).contextMenu({x: x, y: y}); + }); + } + + root.$menu.trigger('contextmenu:hide'); + }, 50); + }, + // key handled :hover + keyStop: function(e, opt) { + if (!opt.isInput) { + e.preventDefault(); + } + + e.stopPropagation(); + }, + key: function(e) { + var opt = $currentTrigger.data('contextMenu') || {}; + + switch (e.keyCode) { + case 9: + case 38: // up + handle.keyStop(e, opt); + // if keyCode is [38 (up)] or [9 (tab) with shift] + if (opt.isInput) { + if (e.keyCode == 9 && e.shiftKey) { + e.preventDefault(); + opt.$selected && opt.$selected.find('input, textarea, select').blur(); + opt.$menu.trigger('prevcommand'); + return; + } else if (e.keyCode == 38 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') { + // checkboxes don't capture this key + e.preventDefault(); + return; + } + } else if (e.keyCode != 9 || e.shiftKey) { + opt.$menu.trigger('prevcommand'); + return; + } + // omitting break; + + // case 9: // tab - reached through omitted break; + case 40: // down + handle.keyStop(e, opt); + if (opt.isInput) { + if (e.keyCode == 9) { + e.preventDefault(); + opt.$selected && opt.$selected.find('input, textarea, select').blur(); + opt.$menu.trigger('nextcommand'); + return; + } else if (e.keyCode == 40 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') { + // checkboxes don't capture this key + e.preventDefault(); + return; + } + } else { + opt.$menu.trigger('nextcommand'); + return; + } + break; + + case 37: // left + handle.keyStop(e, opt); + if (opt.isInput || !opt.$selected || !opt.$selected.length) { + break; + } + + if (!opt.$selected.parent().hasClass('context-menu-root')) { + var $parent = opt.$selected.parent().parent(); + opt.$selected.trigger('contextmenu:blur'); + opt.$selected = $parent; + return; + } + break; + + case 39: // right + handle.keyStop(e, opt); + if (opt.isInput || !opt.$selected || !opt.$selected.length) { + break; + } + + var itemdata = opt.$selected.data('contextMenu') || {}; + if (itemdata.$menu && opt.$selected.hasClass('context-menu-submenu')) { + opt.$selected = null; + itemdata.$selected = null; + itemdata.$menu.trigger('nextcommand'); + return; + } + break; + + case 35: // end + case 36: // home + if (opt.$selected && opt.$selected.find('input, textarea, select').length) { + return; + } else { + (opt.$selected && opt.$selected.parent() || opt.$menu) + .children(':not(.disabled, .not-selectable)')[e.keyCode == 36 ? 'first' : 'last']() + .trigger('contextmenu:focus'); + e.preventDefault(); + return; + } + break; + + case 13: // enter + handle.keyStop(e, opt); + if (opt.isInput) { + if (opt.$selected && !opt.$selected.is('textarea, select')) { + e.preventDefault(); + return; + } + break; + } + opt.$selected && opt.$selected.trigger('mouseup'); + return; + + case 32: // space + case 33: // page up + case 34: // page down + // prevent browser from scrolling down while menu is visible + handle.keyStop(e, opt); + return; + + case 27: // esc + handle.keyStop(e, opt); + opt.$menu.trigger('contextmenu:hide'); + return; + + default: // 0-9, a-z + var k = (String.fromCharCode(e.keyCode)).toUpperCase(); + if (opt.accesskeys[k]) { + // according to the specs accesskeys must be invoked immediately + opt.accesskeys[k].$node.trigger(opt.accesskeys[k].$menu + ? 'contextmenu:focus' + : 'mouseup' + ); + return; + } + break; + } + // pass event to selected item, + // stop propagation to avoid endless recursion + e.stopPropagation(); + opt.$selected && opt.$selected.trigger(e); + }, + + // select previous possible command in menu + prevItem: function(e) { + e.stopPropagation(); + var opt = $(this).data('contextMenu') || {}; + + // obtain currently selected menu + if (opt.$selected) { + var $s = opt.$selected; + opt = opt.$selected.parent().data('contextMenu') || {}; + opt.$selected = $s; + } + + var $children = opt.$menu.children(), + $prev = !opt.$selected || !opt.$selected.prev().length ? $children.last() : opt.$selected.prev(), + $round = $prev; + + // skip disabled + while ($prev.hasClass('disabled') || $prev.hasClass('not-selectable')) { + if ($prev.prev().length) { + $prev = $prev.prev(); + } else { + $prev = $children.last(); + } + if ($prev.is($round)) { + // break endless loop + return; + } + } + + // leave current + if (opt.$selected) { + handle.itemMouseleave.call(opt.$selected.get(0), e); + } + + // activate next + handle.itemMouseenter.call($prev.get(0), e); + + // focus input + var $input = $prev.find('input, textarea, select'); + if ($input.length) { + $input.focus(); + } + }, + // select next possible command in menu + nextItem: function(e) { + e.stopPropagation(); + var opt = $(this).data('contextMenu') || {}; + + // obtain currently selected menu + if (opt.$selected) { + var $s = opt.$selected; + opt = opt.$selected.parent().data('contextMenu') || {}; + opt.$selected = $s; + } + + var $children = opt.$menu.children(), + $next = !opt.$selected || !opt.$selected.next().length ? $children.first() : opt.$selected.next(), + $round = $next; + + // skip disabled + while ($next.hasClass('disabled') || $next.hasClass('not-selectable')) { + if ($next.next().length) { + $next = $next.next(); + } else { + $next = $children.first(); + } + if ($next.is($round)) { + // break endless loop + return; + } + } + + // leave current + if (opt.$selected) { + handle.itemMouseleave.call(opt.$selected.get(0), e); + } + + // activate next + handle.itemMouseenter.call($next.get(0), e); + + // focus input + var $input = $next.find('input, textarea, select'); + if ($input.length) { + $input.focus(); + } + }, + + // flag that we're inside an input so the key handler can act accordingly + focusInput: function(e) { + var $this = $(this).closest('.context-menu-item'), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + root.$selected = opt.$selected = $this; + root.isInput = opt.isInput = true; + }, + // flag that we're inside an input so the key handler can act accordingly + blurInput: function(e) { + var $this = $(this).closest('.context-menu-item'), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + root.isInput = opt.isInput = false; + }, + + // :hover on menu + menuMouseenter: function(e) { + var root = $(this).data().contextMenuRoot; + root.hovering = true; + }, + // :hover on menu + menuMouseleave: function(e) { + var root = $(this).data().contextMenuRoot; + if (root.$layer && root.$layer.is(e.relatedTarget)) { + root.hovering = false; + } + }, + + // :hover done manually so key handling is possible + itemMouseenter: function(e) { + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + root.hovering = true; + + // abort if we're re-entering + if (e && root.$layer && root.$layer.is(e.relatedTarget)) { + e.preventDefault(); + e.stopImmediatePropagation(); + } + + // make sure only one item is selected + (opt.$menu ? opt : root).$menu + .children('.hover').trigger('contextmenu:blur'); + + if ($this.hasClass('disabled') || $this.hasClass('not-selectable')) { + opt.$selected = null; + return; + } + + $this.trigger('contextmenu:focus'); + }, + // :hover done manually so key handling is possible + itemMouseleave: function(e) { + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + if (root !== opt && root.$layer && root.$layer.is(e.relatedTarget)) { + root.$selected && root.$selected.trigger('contextmenu:blur'); + e.preventDefault(); + e.stopImmediatePropagation(); + root.$selected = opt.$selected = opt.$node; + return; + } + + $this.trigger('contextmenu:blur'); + }, + // contextMenu item click + itemClick: function(e) { + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot, + key = data.contextMenuKey, + callback; + + // abort if the key is unknown or disabled or is a menu + if (!opt.items[key] || $this.is('.disabled, .context-menu-submenu, .context-menu-separator, .not-selectable')) { + return; + } + + e.preventDefault(); + e.stopImmediatePropagation(); + + if ($.isFunction(root.callbacks[key]) && Object.prototype.hasOwnProperty.call(root.callbacks, key)) { + // item-specific callback + callback = root.callbacks[key]; + } else if ($.isFunction(root.callback)) { + // default callback + callback = root.callback; + } else { + // no callback, no action + return; + } + + // hide menu if callback doesn't stop that + if (callback.call(root.$trigger, key, root) !== false) { + root.$menu.trigger('contextmenu:hide'); + } else if (root.$menu.parent().length) { + op.update.call(root.$trigger, root); + } + }, + // ignore click events on input elements + inputClick: function(e) { + e.stopImmediatePropagation(); + }, + + // hide + hideMenu: function(e, data) { + var root = $(this).data('contextMenuRoot'); + op.hide.call(root.$trigger, root, data && data.force); + }, + // focus + focusItem: function(e) { + e.stopPropagation(); + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + $this.addClass('hover') + .siblings('.hover').trigger('contextmenu:blur'); + + // remember selected + opt.$selected = root.$selected = $this; + + // position sub-menu - do after show so dumb $.ui.position can keep up + if (opt.$node) { + root.positionSubmenu.call(opt.$node, opt.$menu); + } + }, + // blur + blurItem: function(e) { + e.stopPropagation(); + var $this = $(this), + data = $this.data(), + opt = data.contextMenu, + root = data.contextMenuRoot; + + $this.removeClass('hover'); + opt.$selected = null; + } + }, + // operations + op = { + show: function(opt, x, y) { + var $trigger = $(this), + offset, + css = {}; + + // hide any open menus + $('#context-menu-layer').trigger('mousedown'); + + // backreference for callbacks + opt.$trigger = $trigger; + + // show event + if (opt.events.show.call($trigger, opt) === false) { + $currentTrigger = null; + return; + } + + // create or update context menu + op.update.call($trigger, opt); + + // position menu + opt.position.call($trigger, opt, x, y); + + // make sure we're in front + if (opt.zIndex) { + css.zIndex = zindex($trigger) + opt.zIndex; + } + + // add layer + op.layer.call(opt.$menu, opt, css.zIndex); + + // adjust sub-menu zIndexes + opt.$menu.find('ul').css('zIndex', css.zIndex + 1); + + // position and show context menu + opt.$menu.css( css )[opt.animation.show](opt.animation.duration, function() { + $trigger.trigger('contextmenu:visible'); + }); + // make options available and set state + $trigger + .data('contextMenu', opt) + .addClass("context-menu-active"); + + // register key handler + $(document).off('keydown.contextMenu').on('keydown.contextMenu', handle.key); + // register autoHide handler + if (opt.autoHide) { + // mouse position handler + $(document).on('mousemove.contextMenuAutoHide', function(e) { + // need to capture the offset on mousemove, + // since the page might've been scrolled since activation + var pos = $trigger.offset(); + pos.right = pos.left + $trigger.outerWidth(); + pos.bottom = pos.top + $trigger.outerHeight(); + + if (opt.$layer && !opt.hovering && (!(e.pageX >= pos.left && e.pageX <= pos.right) || !(e.pageY >= pos.top && e.pageY <= pos.bottom))) { + // if mouse in menu... + opt.$menu.trigger('contextmenu:hide'); + } + }); + } + }, + hide: function(opt, force) { + var $trigger = $(this); + if (!opt) { + opt = $trigger.data('contextMenu') || {}; + } + + // hide event + if (!force && opt.events && opt.events.hide.call($trigger, opt) === false) { + return; + } + + // remove options and revert state + $trigger + .removeData('contextMenu') + .removeClass("context-menu-active"); + + if (opt.$layer) { + // keep layer for a bit so the contextmenu event can be aborted properly by opera + setTimeout((function($layer) { + return function(){ + $layer.remove(); + }; + })(opt.$layer), 10); + + try { + delete opt.$layer; + } catch(e) { + opt.$layer = null; + } + } + + // remove handle + $currentTrigger = null; + // remove selected + opt.$menu.find('.hover').trigger('contextmenu:blur'); + opt.$selected = null; + // unregister key and mouse handlers + //$(document).off('.contextMenuAutoHide keydown.contextMenu'); // http://bugs.jquery.com/ticket/10705 + $(document).off('.contextMenuAutoHide').off('keydown.contextMenu'); + // hide menu + opt.$menu && opt.$menu[opt.animation.hide](opt.animation.duration, function (){ + // tear down dynamically built menu after animation is completed. + if (opt.build) { + opt.$menu.remove(); + $.each(opt, function(key, value) { + switch (key) { + case 'ns': + case 'selector': + case 'build': + case 'trigger': + return true; + + default: + opt[key] = undefined; + try { + delete opt[key]; + } catch (e) {} + return true; + } + }); + } + + setTimeout(function() { + $trigger.trigger('contextmenu:hidden'); + }, 10); + }); + }, + create: function(opt, root) { + if (root === undefined) { + root = opt; + } + // create contextMenu + opt.$menu = $('
    ').addClass(opt.className || "").data({ + 'contextMenu': opt, + 'contextMenuRoot': root + }); + + $.each(['callbacks', 'commands', 'inputs'], function(i,k){ + opt[k] = {}; + if (!root[k]) { + root[k] = {}; + } + }); + + root.accesskeys || (root.accesskeys = {}); + + // create contextMenu items + $.each(opt.items, function(key, item){ + var $t = $('
  • ').addClass(item.className || ""), + $label = null, + $input = null; + + // iOS needs to see a click-event bound to an element to actually + // have the TouchEvents infrastructure trigger the click event + $t.on('click', $.noop); + + item.$node = $t.data({ + 'contextMenu': opt, + 'contextMenuRoot': root, + 'contextMenuKey': key + }); + + // register accesskey + // NOTE: the accesskey attribute should be applicable to any element, but Safari5 and Chrome13 still can't do that + if (item.accesskey) { + var aks = splitAccesskey(item.accesskey); + for (var i=0, ak; ak = aks[i]; i++) { + if (!root.accesskeys[ak]) { + root.accesskeys[ak] = item; + item._name = item.name.replace(new RegExp('(' + ak + ')', 'i'), '$1'); + break; + } + } + } + + if (typeof item == "string") { + $t.addClass('context-menu-separator not-selectable'); + } else if (item.type && types[item.type]) { + // run custom type handler + types[item.type].call($t, item, opt, root); + // register commands + $.each([opt, root], function(i,k){ + k.commands[key] = item; + if ($.isFunction(item.callback)) { + k.callbacks[key] = item.callback; + } + }); + } else { + // add label for input + if (item.type == 'html') { + $t.addClass('context-menu-html not-selectable'); + } else if (item.type) { + $label = $('').appendTo($t); + $('').html(item._name || item.name).appendTo($label); + $t.addClass('context-menu-input'); + opt.hasTypes = true; + $.each([opt, root], function(i,k){ + k.commands[key] = item; + k.inputs[key] = item; + }); + } else if (item.items) { + item.type = 'sub'; + } + + switch (item.type) { + case 'text': + $input = $('') + .attr('name', 'context-menu-input-' + key) + .val(item.value || "") + .appendTo($label); + break; + + case 'textarea': + $input = $('') + .attr('name', 'context-menu-input-' + key) + .val(item.value || "") + .appendTo($label); + + if (item.height) { + $input.height(item.height); + } + break; + + case 'checkbox': + $input = $('') + .attr('name', 'context-menu-input-' + key) + .val(item.value || "") + .prop("checked", !!item.selected) + .prependTo($label); + break; + + case 'radio': + $input = $('') + .attr('name', 'context-menu-input-' + item.radio) + .val(item.value || "") + .prop("checked", !!item.selected) + .prependTo($label); + break; + + case 'select': + $input = $(' + if (item.type && item.type != 'sub' && item.type != 'html') { + $input + .on('focus', handle.focusInput) + .on('blur', handle.blurInput); + + if (item.events) { + $input.on(item.events, opt); + } + } + + // add icons + if (item.icon) { + $t.addClass("icon icon-" + item.icon); + } + } + + // cache contained elements + item.$input = $input; + item.$label = $label; + + // attach item to menu + $t.appendTo(opt.$menu); + + // Disable text selection + if (!opt.hasTypes && $.support.eventSelectstart) { + // browsers support user-select: none, + // IE has a special event for text-selection + // browsers supporting neither will not be preventing text-selection + $t.on('selectstart.disableTextSelect', handle.abortevent); + } + }); + // attach contextMenu to (to bypass any possible overflow:hidden issues on parents of the trigger element) + if (!opt.$node) { + opt.$menu.css('display', 'none').addClass('context-menu-root'); + } + opt.$menu.appendTo(opt.appendTo || document.body); + }, + resize: function($menu, nested) { + // determine widths of submenus, as CSS won't grow them automatically + // position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100; + // kinda sucks hard... + + // determine width of absolutely positioned element + $menu.css({position: 'absolute', display: 'block'}); + // don't apply yet, because that would break nested elements' widths + // add a pixel to circumvent word-break issue in IE9 - #80 + $menu.data('width', Math.ceil($menu.width()) + 1); + // reset styles so they allow nested elements to grow/shrink naturally + $menu.css({ + position: 'static', + minWidth: '0px', + maxWidth: '100000px' + }); + // identify width of nested menus + $menu.find('> li > ul').each(function() { + op.resize($(this), true); + }); + // reset and apply changes in the end because nested + // elements' widths wouldn't be calculatable otherwise + if (!nested) { + $menu.find('ul').andSelf().css({ + position: '', + display: '', + minWidth: '', + maxWidth: '' + }).width(function() { + return $(this).data('width'); + }); + } + }, + update: function(opt, root) { + var $trigger = this; + if (root === undefined) { + root = opt; + op.resize(opt.$menu); + } + // re-check disabled for each item + opt.$menu.children().each(function(){ + var $item = $(this), + key = $item.data('contextMenuKey'), + item = opt.items[key], + disabled = ($.isFunction(item.disabled) && item.disabled.call($trigger, key, root)) || item.disabled === true; + + // dis- / enable item + $item[disabled ? 'addClass' : 'removeClass']('disabled'); + + if (item.type) { + // dis- / enable input elements + $item.find('input, select, textarea').prop('disabled', disabled); + + // update input states + switch (item.type) { + case 'text': + case 'textarea': + item.$input.val(item.value || ""); + break; + + case 'checkbox': + case 'radio': + item.$input.val(item.value || "").prop('checked', !!item.selected); + break; + + case 'select': + item.$input.val(item.selected || ""); + break; + } + } + + if (item.$menu) { + // update sub-menu + op.update.call($trigger, item, root); + } + }); + }, + layer: function(opt, zIndex) { + // add transparent layer for click area + // filter and background for Internet Explorer, Issue #23 + var $layer = opt.$layer = $('
    ') + .css({height: $win.height(), width: $win.width(), display: 'block'}) + .data('contextMenuRoot', opt) + .insertBefore(this) + .on('contextmenu', handle.abortevent) + .on('mousedown', handle.layerClick); + + // IE6 doesn't know position:fixed; + if (!$.support.fixedPosition) { + $layer.css({ + 'position' : 'absolute', + 'height' : $(document).height() + }); + } + + return $layer; + } + }; + +// split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key +function splitAccesskey(val) { + var t = val.split(/\s+/), + keys = []; + + for (var i=0, k; k = t[i]; i++) { + k = k[0].toUpperCase(); // first character only + // theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it. + // a map to look up already used access keys would be nice + keys.push(k); + } + + return keys; +} + +// handle contextMenu triggers +$.fn.contextMenu = function(operation) { + if (operation === undefined) { + this.first().trigger('contextmenu'); + } else if (operation.x && operation.y) { + this.first().trigger($.Event("contextmenu", {pageX: operation.x, pageY: operation.y})); + } else if (operation === "hide") { + var $menu = this.data('contextMenu').$menu; + $menu && $menu.trigger('contextmenu:hide'); + } else if (operation === "destroy") { + $.contextMenu("destroy", {context: this}); + } else if ($.isPlainObject(operation)) { + operation.context = this; + $.contextMenu("create", operation); + } else if (operation) { + this.removeClass('context-menu-disabled'); + } else if (!operation) { + this.addClass('context-menu-disabled'); + } + + return this; +}; + +// manage contextMenu instances +$.contextMenu = function(operation, options) { + if (typeof operation != 'string') { + options = operation; + operation = 'create'; + } + + if (typeof options == 'string') { + options = {selector: options}; + } else if (options === undefined) { + options = {}; + } + + // merge with default options + var o = $.extend(true, {}, defaults, options || {}); + var $document = $(document); + var $context = $document; + var _hasContext = false; + + if (!o.context || !o.context.length) { + o.context = document; + } else { + // you never know what they throw at you... + $context = $(o.context).first(); + o.context = $context.get(0); + _hasContext = o.context !== document; + } + + switch (operation) { + case 'create': + // no selector no joy + if (!o.selector) { + throw new Error('No selector specified'); + } + // make sure internal classes are not bound to + if (o.selector.match(/.context-menu-(list|item|input)($|\s)/)) { + throw new Error('Cannot bind to selector "' + o.selector + '" as it contains a reserved className'); + } + if (!o.build && (!o.items || $.isEmptyObject(o.items))) { + throw new Error('No Items sepcified'); + } + counter ++; + o.ns = '.contextMenu' + counter; + if (!_hasContext) { + namespaces[o.selector] = o.ns; + } + menus[o.ns] = o; + + // default to right click + if (!o.trigger) { + o.trigger = 'right'; + } + + if (!initialized) { + // make sure item click is registered first + $document + .on({ + 'contextmenu:hide.contextMenu': handle.hideMenu, + 'prevcommand.contextMenu': handle.prevItem, + 'nextcommand.contextMenu': handle.nextItem, + 'contextmenu.contextMenu': handle.abortevent, + 'mouseenter.contextMenu': handle.menuMouseenter, + 'mouseleave.contextMenu': handle.menuMouseleave + }, '.context-menu-list') + .on('mouseup.contextMenu', '.context-menu-input', handle.inputClick) + .on({ + 'mouseup.contextMenu': handle.itemClick, + 'contextmenu:focus.contextMenu': handle.focusItem, + 'contextmenu:blur.contextMenu': handle.blurItem, + 'contextmenu.contextMenu': handle.abortevent, + 'mouseenter.contextMenu': handle.itemMouseenter, + 'mouseleave.contextMenu': handle.itemMouseleave + }, '.context-menu-item'); + + initialized = true; + } + + // engage native contextmenu event + $context + .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu); + + if (_hasContext) { + // add remove hook, just in case + $context.on('remove' + o.ns, function() { + $(this).contextMenu("destroy"); + }); + } + + switch (o.trigger) { + case 'hover': + $context + .on('mouseenter' + o.ns, o.selector, o, handle.mouseenter) + .on('mouseleave' + o.ns, o.selector, o, handle.mouseleave); + break; + + case 'left': + $context.on('click' + o.ns, o.selector, o, handle.click); + break; + /* + default: + // http://www.quirksmode.org/dom/events/contextmenu.html + $document + .on('mousedown' + o.ns, o.selector, o, handle.mousedown) + .on('mouseup' + o.ns, o.selector, o, handle.mouseup); + break; + */ + } + + // create menu + if (!o.build) { + op.create(o); + } + break; + + case 'destroy': + var $visibleMenu; + if (_hasContext) { + // get proper options + var context = o.context; + $.each(menus, function(ns, o) { + if (o.context !== context) { + return true; + } + + $visibleMenu = $('.context-menu-list').filter(':visible'); + if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is($(o.context).find(o.selector))) { + $visibleMenu.trigger('contextmenu:hide', {force: true}); + } + + try { + if (menus[o.ns].$menu) { + menus[o.ns].$menu.remove(); + } + + delete menus[o.ns]; + } catch(e) { + menus[o.ns] = null; + } + + $(o.context).off(o.ns); + + return true; + }); + } else if (!o.selector) { + $document.off('.contextMenu .contextMenuAutoHide'); + $.each(menus, function(ns, o) { + $(o.context).off(o.ns); + }); + + namespaces = {}; + menus = {}; + counter = 0; + initialized = false; + + $('#context-menu-layer, .context-menu-list').remove(); + } else if (namespaces[o.selector]) { + $visibleMenu = $('.context-menu-list').filter(':visible'); + if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is(o.selector)) { + $visibleMenu.trigger('contextmenu:hide', {force: true}); + } + + try { + if (menus[namespaces[o.selector]].$menu) { + menus[namespaces[o.selector]].$menu.remove(); + } + + delete menus[namespaces[o.selector]]; + } catch(e) { + menus[namespaces[o.selector]] = null; + } + + $document.off(namespaces[o.selector]); + } + break; + + case 'html5': + // if or are not handled by the browser, + // or options was a bool true, + // initialize $.contextMenu for them + if ((!$.support.htmlCommand && !$.support.htmlMenuitem) || (typeof options == "boolean" && options)) { + $('menu[type="context"]').each(function() { + if (this.id) { + $.contextMenu({ + selector: '[contextmenu=' + this.id +']', + items: $.contextMenu.fromMenu(this) + }); + } + }).css('display', 'none'); + } + break; + + default: + throw new Error('Unknown operation "' + operation + '"'); + } + + return this; +}; + +// import values into commands +$.contextMenu.setInputValues = function(opt, data) { + if (data === undefined) { + data = {}; + } + + $.each(opt.inputs, function(key, item) { + switch (item.type) { + case 'text': + case 'textarea': + item.value = data[key] || ""; + break; + + case 'checkbox': + item.selected = data[key] ? true : false; + break; + + case 'radio': + item.selected = (data[item.radio] || "") == item.value ? true : false; + break; + + case 'select': + item.selected = data[key] || ""; + break; + } + }); +}; + +// export values from commands +$.contextMenu.getInputValues = function(opt, data) { + if (data === undefined) { + data = {}; + } + + $.each(opt.inputs, function(key, item) { + switch (item.type) { + case 'text': + case 'textarea': + case 'select': + data[key] = item.$input.val(); + break; + + case 'checkbox': + data[key] = item.$input.prop('checked'); + break; + + case 'radio': + if (item.$input.prop('checked')) { + data[item.radio] = item.value; + } + break; + } + }); + + return data; +}; + +// find