├── .gitignore ├── LICENSE ├── LICENSE.Base64 ├── LICENSE.Dojo ├── LICENSE.Jasmine ├── LICENSE.ObjTree ├── LICENSE.json2 ├── README.md ├── SDataJavaScriptClientLib.sln ├── build ├── release.cmd ├── release.jsb2 └── release.sh ├── deploy ├── sdata-client-debug.js ├── sdata-client-dependencies-debug.js ├── sdata-client-dependencies.js └── sdata-client.js ├── libraries ├── Base64.js ├── ObjTree.js ├── dojo │ ├── DeferredList.js │ └── dojo.js ├── jasmine │ ├── MIT.LICENSE │ ├── jasmine-html.js │ ├── jasmine.css │ └── jasmine.js ├── json2.js ├── parseuri.js └── sage │ ├── class.js │ ├── deferred.js │ ├── event.js │ ├── evented.js │ └── sage.js ├── src ├── SDataAjax.js ├── SDataApplicationRequest.js ├── SDataBaseRequest.js ├── SDataBatchRequest.js ├── SDataNamedQueryRequest.js ├── SDataResourceCollectionRequest.js ├── SDataResourcePropertyRequest.js ├── SDataService.js ├── SDataServiceOperationRequest.js ├── SDataSingleResourceRequest.js ├── SDataSystemRequest.js ├── SDataTemplateResourceRequest.js └── SDataUri.js ├── tests ├── SDataBatchRequestTests.js ├── SDataResourceCollectionRequestTests.js ├── SDataServiceOperationRequestTests.js ├── SDataServiceTests.js ├── SDataSingleResourceRequestTests.js ├── SDataUriTests.js ├── TestBatch.xml ├── TestEntry.xml ├── TestEntryMixedPrefix.xml ├── TestEntryWithPrefix.xml ├── TestFeed.json ├── TestFeed.xml ├── TestFeedExplicit.xml ├── TestFeedSplit.xml ├── TestFeedWithPrefix.xml ├── TestServiceResponse.xml ├── Utility.js └── index.html └── tools └── JSBuilder ├── JSB2FileFormat.txt ├── JSBuilder2.jar └── Readme.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Db]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | deploy/src/ 28 | [Rr]elease*/ 29 | _ReSharper*/ 30 | [Tt]est[Rr]esult* 31 | .idea/ 32 | 33 | web.config -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | 3 | The SDataJavaScriptClientLib software and sample code, developed by Sage, 4 | is licensed under the Apache License, v2.0. 5 | Other software included in this distribution is licensed separately, 6 | as listed in the additional license files in the root folder. 7 | 8 | Apache License 9 | Version 2.0, January 2004 10 | http://www.apache.org/licenses/ 11 | 12 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 13 | 14 | 1. Definitions. 15 | 16 | "License" shall mean the terms and conditions for use, reproduction, 17 | and distribution as defined by Sections 1 through 9 of this document. 18 | 19 | "Licensor" shall mean the copyright owner or entity authorized by 20 | the copyright owner that is granting the License. 21 | 22 | "Legal Entity" shall mean the union of the acting entity and all 23 | other entities that control, are controlled by, or are under common 24 | control with that entity. For the purposes of this definition, 25 | "control" means (i) the power, direct or indirect, to cause the 26 | direction or management of such entity, whether by contract or 27 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 28 | outstanding shares, or (iii) beneficial ownership of such entity. 29 | 30 | "You" (or "Your") shall mean an individual or Legal Entity 31 | exercising permissions granted by this License. 32 | 33 | "Source" form shall mean the preferred form for making modifications, 34 | including but not limited to software source code, documentation 35 | source, and configuration files. 36 | 37 | "Object" form shall mean any form resulting from mechanical 38 | transformation or translation of a Source form, including but 39 | not limited to compiled object code, generated documentation, 40 | and conversions to other media types. 41 | 42 | "Work" shall mean the work of authorship, whether in Source or 43 | Object form, made available under the License, as indicated by a 44 | copyright notice that is included in or attached to the work 45 | (an example is provided in the Appendix below). 46 | 47 | "Derivative Works" shall mean any work, whether in Source or Object 48 | form, that is based on (or derived from) the Work and for which the 49 | editorial revisions, annotations, elaborations, or other modifications 50 | represent, as a whole, an original work of authorship. For the purposes 51 | of this License, Derivative Works shall not include works that remain 52 | separable from, or merely link (or bind by name) to the interfaces of, 53 | the Work and Derivative Works thereof. 54 | 55 | "Contribution" shall mean any work of authorship, including 56 | the original version of the Work and any modifications or additions 57 | to that Work or Derivative Works thereof, that is intentionally 58 | submitted to Licensor for inclusion in the Work by the copyright owner 59 | or by an individual or Legal Entity authorized to submit on behalf of 60 | the copyright owner. For the purposes of this definition, "submitted" 61 | means any form of electronic, verbal, or written communication sent 62 | to the Licensor or its representatives, including but not limited to 63 | communication on electronic mailing lists, source code control systems, 64 | and issue tracking systems that are managed by, or on behalf of, the 65 | Licensor for the purpose of discussing and improving the Work, but 66 | excluding communication that is conspicuously marked or otherwise 67 | designated in writing by the copyright owner as "Not a Contribution." 68 | 69 | "Contributor" shall mean Licensor and any individual or Legal Entity 70 | on behalf of whom a Contribution has been received by Licensor and 71 | subsequently incorporated within the Work. 72 | 73 | 2. Grant of Copyright License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | copyright license to reproduce, prepare Derivative Works of, 77 | publicly display, publicly perform, sublicense, and distribute the 78 | Work and such Derivative Works in Source or Object form. 79 | 80 | 3. Grant of Patent License. Subject to the terms and conditions of 81 | this License, each Contributor hereby grants to You a perpetual, 82 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 83 | (except as stated in this section) patent license to make, have made, 84 | use, offer to sell, sell, import, and otherwise transfer the Work, 85 | where such license applies only to those patent claims licensable 86 | by such Contributor that are necessarily infringed by their 87 | Contribution(s) alone or by combination of their Contribution(s) 88 | with the Work to which such Contribution(s) was submitted. If You 89 | institute patent litigation against any entity (including a 90 | cross-claim or counterclaim in a lawsuit) alleging that the Work 91 | or a Contribution incorporated within the Work constitutes direct 92 | or contributory patent infringement, then any patent licenses 93 | granted to You under this License for that Work shall terminate 94 | as of the date such litigation is filed. 95 | 96 | 4. Redistribution. You may reproduce and distribute copies of the 97 | Work or Derivative Works thereof in any medium, with or without 98 | modifications, and in Source or Object form, provided that You 99 | meet the following conditions: 100 | 101 | (a) You must give any other recipients of the Work or 102 | Derivative Works a copy of this License; and 103 | 104 | (b) You must cause any modified files to carry prominent notices 105 | stating that You changed the files; and 106 | 107 | (c) You must retain, in the Source form of any Derivative Works 108 | that You distribute, all copyright, patent, trademark, and 109 | attribution notices from the Source form of the Work, 110 | excluding those notices that do not pertain to any part of 111 | the Derivative Works; and 112 | 113 | (d) If the Work includes a "NOTICE" text file as part of its 114 | distribution, then any Derivative Works that You distribute must 115 | include a readable copy of the attribution notices contained 116 | within such NOTICE file, excluding those notices that do not 117 | pertain to any part of the Derivative Works, in at least one 118 | of the following places: within a NOTICE text file distributed 119 | as part of the Derivative Works; within the Source form or 120 | documentation, if provided along with the Derivative Works; or, 121 | within a display generated by the Derivative Works, if and 122 | wherever such third-party notices normally appear. The contents 123 | of the NOTICE file are for informational purposes only and 124 | do not modify the License. You may add Your own attribution 125 | notices within Derivative Works that You distribute, alongside 126 | or as an addendum to the NOTICE text from the Work, provided 127 | that such additional attribution notices cannot be construed 128 | as modifying the License. 129 | 130 | You may add Your own copyright statement to Your modifications and 131 | may provide additional or different license terms and conditions 132 | for use, reproduction, or distribution of Your modifications, or 133 | for any such Derivative Works as a whole, provided Your use, 134 | reproduction, and distribution of the Work otherwise complies with 135 | the conditions stated in this License. 136 | 137 | 5. Submission of Contributions. Unless You explicitly state otherwise, 138 | any Contribution intentionally submitted for inclusion in the Work 139 | by You to the Licensor shall be under the terms and conditions of 140 | this License, without any additional terms or conditions. 141 | Notwithstanding the above, nothing herein shall supersede or modify 142 | the terms of any separate license agreement you may have executed 143 | with Licensor regarding such Contributions. 144 | 145 | 6. Trademarks. This License does not grant permission to use the trade 146 | names, trademarks, service marks, or product names of the Licensor, 147 | except as required for reasonable and customary use in describing the 148 | origin of the Work and reproducing the content of the NOTICE file. 149 | 150 | 7. Disclaimer of Warranty. Unless required by applicable law or 151 | agreed to in writing, Licensor provides the Work (and each 152 | Contributor provides its Contributions) on an "AS IS" BASIS, 153 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 154 | implied, including, without limitation, any warranties or conditions 155 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 156 | PARTICULAR PURPOSE. You are solely responsible for determining the 157 | appropriateness of using or redistributing the Work and assume any 158 | risks associated with Your exercise of permissions under this License. 159 | 160 | 8. Limitation of Liability. In no event and under no legal theory, 161 | whether in tort (including negligence), contract, or otherwise, 162 | unless required by applicable law (such as deliberate and grossly 163 | negligent acts) or agreed to in writing, shall any Contributor be 164 | liable to You for damages, including any direct, indirect, special, 165 | incidental, or consequential damages of any character arising as a 166 | result of this License or out of the use or inability to use the 167 | Work (including but not limited to damages for loss of goodwill, 168 | work stoppage, computer failure or malfunction, or any and all 169 | other commercial damages or losses), even if such Contributor 170 | has been advised of the possibility of such damages. 171 | 172 | 9. Accepting Warranty or Additional Liability. While redistributing 173 | the Work or Derivative Works thereof, You may choose to offer, 174 | and charge a fee for, acceptance of support, warranty, indemnity, 175 | or other liability obligations and/or rights consistent with this 176 | License. However, in accepting such obligations, You may act only 177 | on Your own behalf and on Your sole responsibility, not on behalf 178 | of any other Contributor, and only if You agree to indemnify, 179 | defend, and hold each Contributor harmless for any liability 180 | incurred by, or claims asserted against, such Contributor by reason 181 | of your accepting any such warranty or additional liability. 182 | 183 | END OF TERMS AND CONDITIONS 184 | 185 | -------------------------------------------------------------------------------- /LICENSE.Base64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sage/SDataJavaScriptClientLib/70f236b2755c8642022a53b96668ad3e7065d8a3/LICENSE.Base64 -------------------------------------------------------------------------------- /LICENSE.Dojo: -------------------------------------------------------------------------------- 1 | Dojo is available under *either* the terms of the modified BSD license *or* the 2 | Academic Free License version 2.1. As a recipient of Dojo, you may choose which 3 | license to receive this code under (except as noted in per-module LICENSE 4 | files). Some modules may not be the copyright of the Dojo Foundation. These 5 | modules contain explicit declarations of copyright in both the LICENSE files in 6 | the directories in which they reside and in the code itself. No external 7 | contributions are allowed under licenses which are fundamentally incompatible 8 | with the AFL or BSD licenses that Dojo is distributed under. 9 | 10 | The text of the AFL and BSD licenses is reproduced below. 11 | 12 | ------------------------------------------------------------------------------- 13 | The "New" BSD License: 14 | ********************** 15 | 16 | Copyright (c) 2005-2010, The Dojo Foundation 17 | All rights reserved. 18 | 19 | Redistribution and use in source and binary forms, with or without 20 | modification, are permitted provided that the following conditions are met: 21 | 22 | * Redistributions of source code must retain the above copyright notice, this 23 | list of conditions and the following disclaimer. 24 | * Redistributions in binary form must reproduce the above copyright notice, 25 | this list of conditions and the following disclaimer in the documentation 26 | and/or other materials provided with the distribution. 27 | * Neither the name of the Dojo Foundation nor the names of its contributors 28 | may be used to endorse or promote products derived from this software 29 | without specific prior written permission. 30 | 31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 32 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 33 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 34 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 35 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 37 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 39 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | 42 | ------------------------------------------------------------------------------- 43 | The Academic Free License, v. 2.1: 44 | ********************************** 45 | 46 | This Academic Free License (the "License") applies to any original work of 47 | authorship (the "Original Work") whose owner (the "Licensor") has placed the 48 | following notice immediately following the copyright notice for the Original 49 | Work: 50 | 51 | Licensed under the Academic Free License version 2.1 52 | 53 | 1) Grant of Copyright License. Licensor hereby grants You a world-wide, 54 | royalty-free, non-exclusive, perpetual, sublicenseable license to do the 55 | following: 56 | 57 | a) to reproduce the Original Work in copies; 58 | 59 | b) to prepare derivative works ("Derivative Works") based upon the Original 60 | Work; 61 | 62 | c) to distribute copies of the Original Work and Derivative Works to the 63 | public; 64 | 65 | d) to perform the Original Work publicly; and 66 | 67 | e) to display the Original Work publicly. 68 | 69 | 2) Grant of Patent License. Licensor hereby grants You a world-wide, 70 | royalty-free, non-exclusive, perpetual, sublicenseable license, under patent 71 | claims owned or controlled by the Licensor that are embodied in the Original 72 | Work as furnished by the Licensor, to make, use, sell and offer for sale the 73 | Original Work and Derivative Works. 74 | 75 | 3) Grant of Source Code License. The term "Source Code" means the preferred 76 | form of the Original Work for making modifications to it and all available 77 | documentation describing how to modify the Original Work. Licensor hereby 78 | agrees to provide a machine-readable copy of the Source Code of the Original 79 | Work along with each copy of the Original Work that Licensor distributes. 80 | Licensor reserves the right to satisfy this obligation by placing a 81 | machine-readable copy of the Source Code in an information repository 82 | reasonably calculated to permit inexpensive and convenient access by You for as 83 | long as Licensor continues to distribute the Original Work, and by publishing 84 | the address of that information repository in a notice immediately following 85 | the copyright notice that applies to the Original Work. 86 | 87 | 4) Exclusions From License Grant. Neither the names of Licensor, nor the names 88 | of any contributors to the Original Work, nor any of their trademarks or 89 | service marks, may be used to endorse or promote products derived from this 90 | Original Work without express prior written permission of the Licensor. Nothing 91 | in this License shall be deemed to grant any rights to trademarks, copyrights, 92 | patents, trade secrets or any other intellectual property of Licensor except as 93 | expressly stated herein. No patent license is granted to make, use, sell or 94 | offer to sell embodiments of any patent claims other than the licensed claims 95 | defined in Section 2. No right is granted to the trademarks of Licensor even if 96 | such marks are included in the Original Work. Nothing in this License shall be 97 | interpreted to prohibit Licensor from licensing under different terms from this 98 | License any Original Work that Licensor otherwise would have a right to 99 | license. 100 | 101 | 5) This section intentionally omitted. 102 | 103 | 6) Attribution Rights. You must retain, in the Source Code of any Derivative 104 | Works that You create, all copyright, patent or trademark notices from the 105 | Source Code of the Original Work, as well as any notices of licensing and any 106 | descriptive text identified therein as an "Attribution Notice." You must cause 107 | the Source Code for any Derivative Works that You create to carry a prominent 108 | Attribution Notice reasonably calculated to inform recipients that You have 109 | modified the Original Work. 110 | 111 | 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that 112 | the copyright in and to the Original Work and the patent rights granted herein 113 | by Licensor are owned by the Licensor or are sublicensed to You under the terms 114 | of this License with the permission of the contributor(s) of those copyrights 115 | and patent rights. Except as expressly stated in the immediately proceeding 116 | sentence, the Original Work is provided under this License on an "AS IS" BASIS 117 | and WITHOUT WARRANTY, either express or implied, including, without limitation, 118 | the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR 119 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. 120 | This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No 121 | license to Original Work is granted hereunder except under this disclaimer. 122 | 123 | 8) Limitation of Liability. Under no circumstances and under no legal theory, 124 | whether in tort (including negligence), contract, or otherwise, shall the 125 | Licensor be liable to any person for any direct, indirect, special, incidental, 126 | or consequential damages of any character arising as a result of this License 127 | or the use of the Original Work including, without limitation, damages for loss 128 | of goodwill, work stoppage, computer failure or malfunction, or any and all 129 | other commercial damages or losses. This limitation of liability shall not 130 | apply to liability for death or personal injury resulting from Licensor's 131 | negligence to the extent applicable law prohibits such limitation. Some 132 | jurisdictions do not allow the exclusion or limitation of incidental or 133 | consequential damages, so this exclusion and limitation may not apply to You. 134 | 135 | 9) Acceptance and Termination. If You distribute copies of the Original Work or 136 | a Derivative Work, You must make a reasonable effort under the circumstances to 137 | obtain the express assent of recipients to the terms of this License. Nothing 138 | else but this License (or another written agreement between Licensor and You) 139 | grants You permission to create Derivative Works based upon the Original Work 140 | or to exercise any of the rights granted in Section 1 herein, and any attempt 141 | to do so except under the terms of this License (or another written agreement 142 | between Licensor and You) is expressly prohibited by U.S. copyright law, the 143 | equivalent laws of other countries, and by international treaty. Therefore, by 144 | exercising any of the rights granted to You in Section 1 herein, You indicate 145 | Your acceptance of this License and all of its terms and conditions. 146 | 147 | 10) Termination for Patent Action. This License shall terminate automatically 148 | and You may no longer exercise any of the rights granted to You by this License 149 | as of the date You commence an action, including a cross-claim or counterclaim, 150 | against Licensor or any licensee alleging that the Original Work infringes a 151 | patent. This termination provision shall not apply for an action alleging 152 | patent infringement by combinations of the Original Work with other software or 153 | hardware. 154 | 155 | 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this 156 | License may be brought only in the courts of a jurisdiction wherein the 157 | Licensor resides or in which Licensor conducts its primary business, and under 158 | the laws of that jurisdiction excluding its conflict-of-law provisions. The 159 | application of the United Nations Convention on Contracts for the International 160 | Sale of Goods is expressly excluded. Any use of the Original Work outside the 161 | scope of this License or after its termination shall be subject to the 162 | requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et 163 | seq., the equivalent laws of other countries, and international treaty. This 164 | section shall survive the termination of this License. 165 | 166 | 12) Attorneys Fees. In any action to enforce the terms of this License or 167 | seeking damages relating thereto, the prevailing party shall be entitled to 168 | recover its costs and expenses, including, without limitation, reasonable 169 | attorneys' fees and costs incurred in connection with such action, including 170 | any appeal of such action. This section shall survive the termination of this 171 | License. 172 | 173 | 13) Miscellaneous. This License represents the complete agreement concerning 174 | the subject matter hereof. If any provision of this License is held to be 175 | unenforceable, such provision shall be reformed only to the extent necessary to 176 | make it enforceable. 177 | 178 | 14) Definition of "You" in This License. "You" throughout this License, whether 179 | in upper or lower case, means an individual or a legal entity exercising rights 180 | under, and complying with all of the terms of, this License. For legal 181 | entities, "You" includes any entity that controls, is controlled by, or is 182 | under common control with you. For purposes of this definition, "control" means 183 | (i) the power, direct or indirect, to cause the direction or management of such 184 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 185 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of such 186 | entity. 187 | 188 | 15) Right to Use. You may use the Original Work in all ways not otherwise 189 | restricted or conditioned by this License or by law, and Licensor promises not 190 | to interfere with or be responsible for such uses by You. 191 | 192 | This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. 193 | Permission is hereby granted to copy and distribute this license without 194 | modification. This license may not be modified without the express written 195 | permission of its copyright owner. 196 | -------------------------------------------------------------------------------- /LICENSE.Jasmine: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2010 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE.ObjTree: -------------------------------------------------------------------------------- 1 | Yusuke Kawasaki http://www.kawa.net/ 2 | 3 | COPYRIGHT AND LICENSE 4 | 5 | Copyright (c) 2005-2006 Yusuke Kawasaki. All rights reserved. 6 | This program is free software; you can redistribute it and/or 7 | modify it under the Artistic license. Or whatever license I choose, 8 | which I will do instead of keeping this documentation like it is. 9 | -------------------------------------------------------------------------------- /LICENSE.json2: -------------------------------------------------------------------------------- 1 | http://www.JSON.org/json2.js 2 | 2010-03-20 3 | 4 | Public Domain. 5 | 6 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 7 | 8 | See http://www.JSON.org/js.html -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Information 2 | 3 | This repository contains a JavaScript library for consuming [SData](http://sdata.sage.com). 4 | 5 | ## Downloading 6 | 7 | * [minified](http://github.com/SageScottsdalePlatform/SDataJavaScriptClientLib/raw/master/deploy/sdata-client.js) 8 | * [debug](http://github.com/SageScottsdalePlatform/SDataJavaScriptClientLib/raw/master/deploy/sdata-client-debug.js) 9 | 10 | ## Building A Release Version 11 | 12 | ### Requirements 13 | 14 | * Windows 15 | * The Java Runtime (JRE) 16 | * The environment variable, `JAVA_HOME`, pointing to the JRE base path, eg: 17 | 18 | c:\Program Files (x86)\Java\jre6 19 | 20 | ### Steps 21 | 22 | 2. Open a command prompt and execute the following from the root repository folder, eg: 23 | 24 | build\release.cmd 25 | 3. The deployed product will be in a `deploy` folder in the root repository folder. 26 | 27 | ## Examples 28 | 29 | #### Example: Set up an SData service connection (to be used for rest of examples) 30 | var service = new Sage.SData.Client.SDataService({ 31 |     url: 'http://localhost/sdata/slx/dynamic/-/', 32 | userName: 'admin', 33 | password: '', 34 | json: true //if your SData provider supports JSON 35 | }); 36 | 37 | #### Example: Make a single resource request (Contact) 38 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 39 | .setResourceKind('contacts') 40 | .setResourceSelector("'CGHEA0000001'"); 41 |     42 | request.read({ 43 |     success: function(entry) { console.log(entry); } 44 | }); 45 | 46 | #### Example: Request a resource collection (Contacts) 47 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 48 |     .setResourceKind('contacts') 49 |     .setCount(5) 50 |     .setStartIndex(6); // 1 based, not 0 based (per spec) 51 |     52 | request.read({ 53 |     success: function(feed) { console.log(feed); } 54 | }); 55 | 56 | #### Example: Request all of the Contacts for a particular Account 57 | var request = new Sage.SData.Client.SDataResourcePropertyRequest(service) 58 |     .setResourceKind('accounts') 59 |     .setResourceSelector("'AGHEA0002669'") 60 |     .setResourceProperty('Contacts') 61 |     62 | // use `readFeed` since we are targeting a collection property 63 | request.readFeed({ 64 |     success: function(feed) { console.log(feed); } 65 | }); 66 | 67 | #### Example: Batch request (combine two account queries) 68 | var batch = new Sage.SData.Client.SDataBatchRequest(service) 69 |     .setResourceKind('accounts') 70 |     .using(function() { 71 |         new Sage.SData.Client.SDataSingleResourceRequest(service) 72 |             .setResourceKind('accounts') 73 |             .setResourceSelector("'AGHEA0002669'") 74 |             .read(); 75 |         76 |         new Sage.SData.Client.SDataSingleResourceRequest(service) 77 |             .setResourceKind('accounts') 78 |             .setResourceSelector("'AA2EK0013031'") 79 |             .read();        80 |     }); 81 |     82 | batch.commit({ 83 |     success: function(feed) { console.log(feed); } 84 | }); -------------------------------------------------------------------------------- /SDataJavaScriptClientLib.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "SDataJavaScriptClientLib", ".", "{BE48B649-21CD-4368-AFFC-71348E55D7B4}" 5 | ProjectSection(WebsiteProperties) = preProject 6 | TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.0" 7 | Debug.AspNetCompiler.VirtualPath = "/SDataJavaScriptClientLib" 8 | Debug.AspNetCompiler.PhysicalPath = "..\SDataJavaScriptClientLib\" 9 | Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\SDataJavaScriptClientLib\" 10 | Debug.AspNetCompiler.Updateable = "true" 11 | Debug.AspNetCompiler.ForceOverwrite = "true" 12 | Debug.AspNetCompiler.FixedNames = "false" 13 | Debug.AspNetCompiler.Debug = "True" 14 | Release.AspNetCompiler.VirtualPath = "/SDataJavaScriptClientLib" 15 | Release.AspNetCompiler.PhysicalPath = "..\SDataJavaScriptClientLib\" 16 | Release.AspNetCompiler.TargetPath = "PrecompiledWeb\SDataJavaScriptClientLib\" 17 | Release.AspNetCompiler.Updateable = "true" 18 | Release.AspNetCompiler.ForceOverwrite = "true" 19 | Release.AspNetCompiler.FixedNames = "false" 20 | Release.AspNetCompiler.Debug = "False" 21 | VWDPort = "52607" 22 | EndProjectSection 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {BE48B649-21CD-4368-AFFC-71348E55D7B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {BE48B649-21CD-4368-AFFC-71348E55D7B4}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | EndGlobalSection 32 | GlobalSection(SolutionProperties) = preSolution 33 | HideSolutionNode = FALSE 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /build/release.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | %JAVA_HOME%\bin\java -Dfile.encoding=UTF-8 -jar "tools/JSBuilder/JSBuilder2.jar" -v -p "build/release.jsb2" -d "." -------------------------------------------------------------------------------- /build/release.jsb2: -------------------------------------------------------------------------------- 1 | { 2 | projectName: 'SData JavaScript Client', 3 | licenseText: '', 4 | deployDir: 'deploy/', 5 | pkgs: [{ 6 | name: 'SData JavaScript Client', 7 | file: 'sdata-client.js', 8 | isDebug: true, 9 | fileIncludes: [{ 10 | text: 'SDataAjax.js', 11 | path: '../src/' 12 | },{ 13 | text: 'SDataBaseRequest.js', 14 | path: '../src/' 15 | },{ 16 | text: 'SDataApplicationRequest.js', 17 | path: '../src/' 18 | },{ 19 | text: 'SDataResourceCollectionRequest.js', 20 | path: '../src/' 21 | },{ 22 | text: 'SDataNamedQueryRequest.js', 23 | path: '../src/' 24 | },{ 25 | text: 'SDataSingleResourceRequest.js', 26 | path: '../src/' 27 | },{ 28 | text: 'SDataResourcePropertyRequest.js', 29 | path: '../src/' 30 | },{ 31 | text: 'SDataSystemRequest.js', 32 | path: '../src/' 33 | },{ 34 | text: 'SDataTemplateResourceRequest.js', 35 | path: '../src/' 36 | },{ 37 | text: 'SDataServiceOperationRequest.js', 38 | path: '../src/' 39 | },{ 40 | text: 'SDataBatchRequest.js', 41 | path: '../src/' 42 | },{ 43 | text: 'SDataUri.js', 44 | path: '../src/' 45 | },{ 46 | text: 'SDataService.js', 47 | path: '../src/' 48 | }] 49 | },{ 50 | name: 'SData JavaScript Client Dependencies', 51 | file: 'sdata-client-dependencies.js', 52 | isDebug: true, 53 | fileIncludes: [{ 54 | text: 'Base64.js', 55 | path: '../libraries/' 56 | },{ 57 | text: 'ObjTree.js', 58 | path: '../libraries/' 59 | },{ 60 | text: 'parseuri.js', 61 | path: '../libraries/' 62 | },{ 63 | text: 'sage.js', 64 | path: '../libraries/sage/' 65 | },{ 66 | text: 'class.js', 67 | path: '../libraries/sage/' 68 | },{ 69 | text: 'deferred.js', 70 | path: '../libraries/sage/' 71 | },{ 72 | text: 'event.js', 73 | path: '../libraries/sage/' 74 | },{ 75 | text: 'evented.js', 76 | path: '../libraries/sage/' 77 | }] 78 | }], 79 | resources: [] 80 | } -------------------------------------------------------------------------------- /build/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | java -Dfile.encoding=UTF-8 -jar "tools/JSBuilder/JSBuilder2.jar" -v -p "build/release.jsb2" -d "." -------------------------------------------------------------------------------- /deploy/sdata-client-dependencies.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | */ 4 | var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(c){var a="";var k,h,f,j,g,e,d;var b=0;c=Base64._utf8_encode(c);while(b>2;g=((k&3)<<4)|(h>>4);e=((h&15)<<2)|(f>>6);d=f&63;if(isNaN(h)){e=d=64}else{if(isNaN(f)){d=64}}a=a+this._keyStr.charAt(j)+this._keyStr.charAt(g)+this._keyStr.charAt(e)+this._keyStr.charAt(d)}return a},decode:function(c){var a="";var k,h,f;var j,g,e,d;var b=0;c=c.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(b>4);h=((g&15)<<4)|(e>>2);f=((e&3)<<6)|d;a=a+String.fromCharCode(k);if(e!=64){a=a+String.fromCharCode(h)}if(d!=64){a=a+String.fromCharCode(f)}}a=Base64._utf8_decode(a);return a},_utf8_encode:function(b){b=b.replace(/\r\n/g,"\n");var a="";for(var e=0;e127)&&(d<2048)){a+=String.fromCharCode((d>>6)|192);a+=String.fromCharCode((d&63)|128)}else{a+=String.fromCharCode((d>>12)|224);a+=String.fromCharCode(((d>>6)&63)|128);a+=String.fromCharCode((d&63)|128)}}}return a},_utf8_decode:function(a){var b="";var d=0;var e=c1=c2=0;while(d191)&&(e<224)){c2=a.charCodeAt(d+1);b+=String.fromCharCode(((e&31)<<6)|(c2&63));d+=2}else{c2=a.charCodeAt(d+1);c3=a.charCodeAt(d+2);b+=String.fromCharCode(((e&15)<<12)|((c2&63)<<6)|(c3&63));d+=3}}}return b}};if(typeof(XML)=="undefined"){XML=function(){}}XML.ObjTree=function(){return this};XML.ObjTree.VERSION="0.24";XML.ObjTree.prototype.xmlDecl='\n';XML.ObjTree.prototype.attr_prefix="-";XML.ObjTree.prototype.overrideMimeType="text/xml";XML.ObjTree.prototype.parseXML=function(c){var b;if(window.DOMParser){var a=new DOMParser();var d=a.parseFromString(c,"application/xml");if(!d){return}b=d.documentElement}else{if(window.ActiveXObject){a=new ActiveXObject("Microsoft.XMLDOM");a.async=false;a.loadXML(c);b=a.documentElement}}if(!b){return}return this.parseDOM(b)};XML.ObjTree.prototype.parseHTTP=function(b,j,h){var a={};for(var g in j){a[g]=j[g]}if(!a.method){if(typeof(a.postBody)=="undefined"&&typeof(a.postbody)=="undefined"&&typeof(a.parameters)=="undefined"){a.method="get"}else{a.method="post"}}if(h){a.asynchronous=true;var f=this;var c=h;var d=a.onComplete;a.onComplete=function(l){var k;if(l&&l.responseXML&&l.responseXML.documentElement){k=f.parseDOM(l.responseXML.documentElement)}else{if(l&&l.responseText){k=f.parseXML(l.responseText)}}c(k,l);if(d){d(l)}}}else{a.asynchronous=false}var i;if(typeof(HTTP)!="undefined"&&HTTP.Request){a.uri=b;var e=new HTTP.Request(a);if(e){i=e.transport}}else{if(typeof(Ajax)!="undefined"&&Ajax.Request){var e=new Ajax.Request(b,a);if(e){i=e.transport}}}if(h){return i}if(i&&i.responseXML&&i.responseXML.documentElement){return this.parseDOM(i.responseXML.documentElement)}else{if(i&&i.responseText){return this.parseXML(i.responseText)}}};XML.ObjTree.prototype.parseDOM=function(a){if(!a){return}this.__force_array={};if(this.force_array){for(var d=0;d"}else{if(typeof(h)=="object"&&h.constructor==Array){f[f.length]=this.array_to_xml(e,h)}else{if(typeof(h)=="object"){f[f.length]=this.hash_to_xml(e,h)}else{f[f.length]=this.scalar_to_xml(e,h)}}}}else{a[a.length]=" "+(e.substring(1))+'="'+(this.xml_escape(h))+'"'}}var g=a.join("");var d=f.join("");if(typeof(c)=="undefined"||c==null){}else{if(f.length>0){if(d.match(/\n/)){d="<"+c+g+">\n"+d+"\n"}else{d="<"+c+g+">"+d+"\n"}}else{d="<"+c+g+" />\n"}}return d};XML.ObjTree.prototype.array_to_xml=function(b,e){var a=[];for(var c=0;c"}else{if(typeof(d)=="object"&&d.constructor==Array){a[a.length]=this.array_to_xml(b,d)}else{if(typeof(d)=="object"){a[a.length]=this.hash_to_xml(b,d)}else{a[a.length]=this.scalar_to_xml(b,d)}}}}return a.join("")};XML.ObjTree.prototype.scalar_to_xml=function(a,b){if(a=="#text"){return this.xml_escape(b)}else{return"<"+a+">"+this.xml_escape(b)+"\n"}};XML.ObjTree.prototype.xml_escape=function(a){return String(a).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")};function parseUri(e){var d=parseUri.options,a=d.parser[d.strictMode?"strict":"loose"].exec(e),c={},b=14;while(b--){c[d.key[b]]=a[b]||""}c[d.q.name]={};c[d.key[12]].replace(d.q.parser,function(g,f,h){if(f){c[d.q.name][f]=h}});return c}parseUri.options={strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};Sage=(function(){var c=function(f,e,h){if(f&&h){for(var g in h){f[g]=h[g]}}if(f&&e){for(var g in e){f[g]=e[g]}}return f};var d=function(e,g){var h=e.split(".");var j=g||(h[0]!=="Sage"?this:window);for(var f=0;f0){p.firing=b;m=e.call(arguments,0);for(;n0},suspendEvents:function(g){this.eventsSuspended=c;if(g&&!this.eventQueue){this.eventQueue=[]}},resumeEvents:function(){var g=this,h=g.eventQueue||[];g.eventsSuspended=e;delete g.eventQueue;a(h,function(i){g.fireEvent.apply(g,i)})}});d.Evented.prototype.on=d.Evented.prototype.addListener;d.Evented.prototype.un=d.Evented.prototype.removeListener}(Sage))}; -------------------------------------------------------------------------------- /libraries/Base64.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Base64 encode / decode 4 | * http://www.webtoolkit.info/ 5 | * 6 | **/ 7 | 8 | var Base64 = { 9 | 10 | // private property 11 | _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 12 | 13 | // public method for encoding 14 | encode : function (input) { 15 | var output = ""; 16 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 17 | var i = 0; 18 | 19 | input = Base64._utf8_encode(input); 20 | 21 | while (i < input.length) { 22 | 23 | chr1 = input.charCodeAt(i++); 24 | chr2 = input.charCodeAt(i++); 25 | chr3 = input.charCodeAt(i++); 26 | 27 | enc1 = chr1 >> 2; 28 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 29 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 30 | enc4 = chr3 & 63; 31 | 32 | if (isNaN(chr2)) { 33 | enc3 = enc4 = 64; 34 | } else if (isNaN(chr3)) { 35 | enc4 = 64; 36 | } 37 | 38 | output = output + 39 | this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + 40 | this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4); 41 | 42 | } 43 | 44 | return output; 45 | }, 46 | 47 | // public method for decoding 48 | decode : function (input) { 49 | var output = ""; 50 | var chr1, chr2, chr3; 51 | var enc1, enc2, enc3, enc4; 52 | var i = 0; 53 | 54 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 55 | 56 | while (i < input.length) { 57 | 58 | enc1 = this._keyStr.indexOf(input.charAt(i++)); 59 | enc2 = this._keyStr.indexOf(input.charAt(i++)); 60 | enc3 = this._keyStr.indexOf(input.charAt(i++)); 61 | enc4 = this._keyStr.indexOf(input.charAt(i++)); 62 | 63 | chr1 = (enc1 << 2) | (enc2 >> 4); 64 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 65 | chr3 = ((enc3 & 3) << 6) | enc4; 66 | 67 | output = output + String.fromCharCode(chr1); 68 | 69 | if (enc3 != 64) { 70 | output = output + String.fromCharCode(chr2); 71 | } 72 | if (enc4 != 64) { 73 | output = output + String.fromCharCode(chr3); 74 | } 75 | 76 | } 77 | 78 | output = Base64._utf8_decode(output); 79 | 80 | return output; 81 | 82 | }, 83 | 84 | // private method for UTF-8 encoding 85 | _utf8_encode : function (string) { 86 | string = string.replace(/\r\n/g,"\n"); 87 | var utftext = ""; 88 | 89 | for (var n = 0; n < string.length; n++) { 90 | 91 | var c = string.charCodeAt(n); 92 | 93 | if (c < 128) { 94 | utftext += String.fromCharCode(c); 95 | } 96 | else if((c > 127) && (c < 2048)) { 97 | utftext += String.fromCharCode((c >> 6) | 192); 98 | utftext += String.fromCharCode((c & 63) | 128); 99 | } 100 | else { 101 | utftext += String.fromCharCode((c >> 12) | 224); 102 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 103 | utftext += String.fromCharCode((c & 63) | 128); 104 | } 105 | 106 | } 107 | 108 | return utftext; 109 | }, 110 | 111 | // private method for UTF-8 decoding 112 | _utf8_decode : function (utftext) { 113 | var string = ""; 114 | var i = 0; 115 | var c = c1 = c2 = 0; 116 | 117 | while ( i < utftext.length ) { 118 | 119 | c = utftext.charCodeAt(i); 120 | 121 | if (c < 128) { 122 | string += String.fromCharCode(c); 123 | i++; 124 | } 125 | else if((c > 191) && (c < 224)) { 126 | c2 = utftext.charCodeAt(i+1); 127 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 128 | i += 2; 129 | } 130 | else { 131 | c2 = utftext.charCodeAt(i+1); 132 | c3 = utftext.charCodeAt(i+2); 133 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); 134 | i += 3; 135 | } 136 | 137 | } 138 | 139 | return string; 140 | } 141 | 142 | }; -------------------------------------------------------------------------------- /libraries/dojo/DeferredList.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. 3 | Available via Academic Free License >= 2.1 OR the modified BSD license. 4 | see: http://dojotoolkit.org/license for details 5 | */ 6 | 7 | 8 | if(!dojo._hasResource["dojo.DeferredList"]){ 9 | dojo._hasResource["dojo.DeferredList"]=true; 10 | dojo.provide("dojo.DeferredList"); 11 | dojo.DeferredList=function(_1,_2,_3,_4,_5){ 12 | var _6=[]; 13 | dojo.Deferred.call(this); 14 | var _7=this; 15 | if(_1.length===0&&!_2){ 16 | this.resolve([0,[]]); 17 | } 18 | var _8=0; 19 | dojo.forEach(_1,function(_9,i){ 20 | _9.then(function(_a){ 21 | if(_2){ 22 | _7.resolve([i,_a]); 23 | }else{ 24 | _b(true,_a); 25 | } 26 | },function(_c){ 27 | if(_3){ 28 | _7.reject(_c); 29 | }else{ 30 | _b(false,_c); 31 | } 32 | if(_4){ 33 | return null; 34 | } 35 | throw _c; 36 | }); 37 | function _b(_d,_e){ 38 | _6[i]=[_d,_e]; 39 | _8++; 40 | if(_8===_1.length){ 41 | _7.resolve(_6); 42 | } 43 | }; 44 | }); 45 | }; 46 | dojo.DeferredList.prototype=new dojo.Deferred(); 47 | dojo.DeferredList.prototype.gatherResults=function(_f){ 48 | var d=new dojo.DeferredList(_f,false,true,false); 49 | d.addCallback(function(_10){ 50 | var ret=[]; 51 | dojo.forEach(_10,function(_11){ 52 | ret.push(_11[1]); 53 | }); 54 | return ret; 55 | }); 56 | return d; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /libraries/jasmine/MIT.LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2010 Pivotal Labs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /libraries/jasmine/jasmine-html.js: -------------------------------------------------------------------------------- 1 | jasmine.TrivialReporter = function(doc) { 2 | this.document = doc || document; 3 | this.suiteDivs = {}; 4 | this.logRunningSpecs = false; 5 | }; 6 | 7 | jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { 8 | var el = document.createElement(type); 9 | 10 | for (var i = 2; i < arguments.length; i++) { 11 | var child = arguments[i]; 12 | 13 | if (typeof child === 'string') { 14 | el.appendChild(document.createTextNode(child)); 15 | } else { 16 | if (child) { el.appendChild(child); } 17 | } 18 | } 19 | 20 | for (var attr in attrs) { 21 | if (attr == "className") { 22 | el[attr] = attrs[attr]; 23 | } else { 24 | el.setAttribute(attr, attrs[attr]); 25 | } 26 | } 27 | 28 | return el; 29 | }; 30 | 31 | jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { 32 | var showPassed, showSkipped; 33 | 34 | this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, 35 | this.createDom('div', { className: 'banner' }, 36 | this.createDom('div', { className: 'logo' }, 37 | this.createDom('a', { href: 'http://pivotal.github.com/jasmine/', target: "_blank" }, "Jasmine"), 38 | this.createDom('span', { className: 'version' }, runner.env.versionString())), 39 | this.createDom('div', { className: 'options' }, 40 | "Show ", 41 | showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), 42 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), 43 | showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), 44 | this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") 45 | ) 46 | ), 47 | 48 | this.runnerDiv = this.createDom('div', { className: 'runner running' }, 49 | this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), 50 | this.runnerMessageSpan = this.createDom('span', {}, "Running..."), 51 | this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) 52 | ); 53 | 54 | this.document.body.appendChild(this.outerDiv); 55 | 56 | var suites = runner.suites(); 57 | for (var i = 0; i < suites.length; i++) { 58 | var suite = suites[i]; 59 | var suiteDiv = this.createDom('div', { className: 'suite' }, 60 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), 61 | this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); 62 | this.suiteDivs[suite.id] = suiteDiv; 63 | var parentDiv = this.outerDiv; 64 | if (suite.parentSuite) { 65 | parentDiv = this.suiteDivs[suite.parentSuite.id]; 66 | } 67 | parentDiv.appendChild(suiteDiv); 68 | } 69 | 70 | this.startedAt = new Date(); 71 | 72 | var self = this; 73 | showPassed.onclick = function(evt) { 74 | if (showPassed.checked) { 75 | self.outerDiv.className += ' show-passed'; 76 | } else { 77 | self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); 78 | } 79 | }; 80 | 81 | showSkipped.onclick = function(evt) { 82 | if (showSkipped.checked) { 83 | self.outerDiv.className += ' show-skipped'; 84 | } else { 85 | self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); 86 | } 87 | }; 88 | }; 89 | 90 | jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { 91 | var results = runner.results(); 92 | var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; 93 | this.runnerDiv.setAttribute("class", className); 94 | //do it twice for IE 95 | this.runnerDiv.setAttribute("className", className); 96 | var specs = runner.specs(); 97 | var specCount = 0; 98 | for (var i = 0; i < specs.length; i++) { 99 | if (this.specFilter(specs[i])) { 100 | specCount++; 101 | } 102 | } 103 | var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); 104 | message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; 105 | this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); 106 | 107 | this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); 108 | }; 109 | 110 | jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { 111 | var results = suite.results(); 112 | var status = results.passed() ? 'passed' : 'failed'; 113 | if (results.totalCount == 0) { // todo: change this to check results.skipped 114 | status = 'skipped'; 115 | } 116 | this.suiteDivs[suite.id].className += " " + status; 117 | }; 118 | 119 | jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { 120 | if (this.logRunningSpecs) { 121 | this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); 122 | } 123 | }; 124 | 125 | jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { 126 | var results = spec.results(); 127 | var status = results.passed() ? 'passed' : 'failed'; 128 | if (results.skipped) { 129 | status = 'skipped'; 130 | } 131 | var specDiv = this.createDom('div', { className: 'spec ' + status }, 132 | this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), 133 | this.createDom('a', { 134 | className: 'description', 135 | href: '?spec=' + encodeURIComponent(spec.getFullName()), 136 | title: spec.getFullName() 137 | }, spec.description)); 138 | 139 | 140 | var resultItems = results.getItems(); 141 | var messagesDiv = this.createDom('div', { className: 'messages' }); 142 | for (var i = 0; i < resultItems.length; i++) { 143 | var result = resultItems[i]; 144 | 145 | if (result.type == 'log') { 146 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); 147 | } else if (result.type == 'expect' && result.passed && !result.passed()) { 148 | messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); 149 | 150 | if (result.trace.stack) { 151 | messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); 152 | } 153 | } 154 | } 155 | 156 | if (messagesDiv.childNodes.length > 0) { 157 | specDiv.appendChild(messagesDiv); 158 | } 159 | 160 | this.suiteDivs[spec.suite.id].appendChild(specDiv); 161 | }; 162 | 163 | jasmine.TrivialReporter.prototype.log = function() { 164 | var console = jasmine.getGlobal().console; 165 | if (console && console.log) { 166 | if (console.log.apply) { 167 | console.log.apply(console, arguments); 168 | } else { 169 | console.log(arguments); // ie fix: console.log.apply doesn't exist on ie 170 | } 171 | } 172 | }; 173 | 174 | jasmine.TrivialReporter.prototype.getLocation = function() { 175 | return this.document.location; 176 | }; 177 | 178 | jasmine.TrivialReporter.prototype.specFilter = function(spec) { 179 | var paramMap = {}; 180 | var params = this.getLocation().search.substring(1).split('&'); 181 | for (var i = 0; i < params.length; i++) { 182 | var p = params[i].split('='); 183 | paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); 184 | } 185 | 186 | if (!paramMap["spec"]) return true; 187 | return spec.getFullName().indexOf(paramMap["spec"]) == 0; 188 | }; 189 | -------------------------------------------------------------------------------- /libraries/jasmine/jasmine.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; 3 | } 4 | 5 | 6 | .jasmine_reporter a:visited, .jasmine_reporter a { 7 | color: #303; 8 | } 9 | 10 | .jasmine_reporter a:hover, .jasmine_reporter a:active { 11 | color: blue; 12 | } 13 | 14 | .run_spec { 15 | float:right; 16 | padding-right: 5px; 17 | font-size: .8em; 18 | text-decoration: none; 19 | } 20 | 21 | .jasmine_reporter { 22 | margin: 0 5px; 23 | } 24 | 25 | .banner { 26 | color: #303; 27 | background-color: #fef; 28 | padding: 5px; 29 | } 30 | 31 | .logo { 32 | float: left; 33 | font-size: 1.1em; 34 | padding-left: 5px; 35 | } 36 | 37 | .logo .version { 38 | font-size: .6em; 39 | padding-left: 1em; 40 | } 41 | 42 | .runner.running { 43 | background-color: yellow; 44 | } 45 | 46 | 47 | .options { 48 | text-align: right; 49 | font-size: .8em; 50 | } 51 | 52 | 53 | 54 | 55 | .suite { 56 | border: 1px outset gray; 57 | margin: 5px 0; 58 | padding-left: 1em; 59 | } 60 | 61 | .suite .suite { 62 | margin: 5px; 63 | } 64 | 65 | .suite.passed { 66 | background-color: #dfd; 67 | } 68 | 69 | .suite.failed { 70 | background-color: #fdd; 71 | } 72 | 73 | .spec { 74 | margin: 5px; 75 | padding-left: 1em; 76 | clear: both; 77 | } 78 | 79 | .spec.failed, .spec.passed, .spec.skipped { 80 | padding-bottom: 5px; 81 | border: 1px solid gray; 82 | } 83 | 84 | .spec.failed { 85 | background-color: #fbb; 86 | border-color: red; 87 | } 88 | 89 | .spec.passed { 90 | background-color: #bfb; 91 | border-color: green; 92 | } 93 | 94 | .spec.skipped { 95 | background-color: #bbb; 96 | } 97 | 98 | .messages { 99 | border-left: 1px dashed gray; 100 | padding-left: 1em; 101 | padding-right: 1em; 102 | } 103 | 104 | .passed { 105 | background-color: #cfc; 106 | display: none; 107 | } 108 | 109 | .failed { 110 | background-color: #fbb; 111 | } 112 | 113 | .skipped { 114 | color: #777; 115 | background-color: #eee; 116 | display: none; 117 | } 118 | 119 | 120 | /*.resultMessage {*/ 121 | /*white-space: pre;*/ 122 | /*}*/ 123 | 124 | .resultMessage span.result { 125 | display: block; 126 | line-height: 2em; 127 | color: black; 128 | } 129 | 130 | .resultMessage .mismatch { 131 | color: black; 132 | } 133 | 134 | .stackTrace { 135 | white-space: pre; 136 | font-size: .8em; 137 | margin-left: 10px; 138 | max-height: 5em; 139 | overflow: auto; 140 | border: 1px inset red; 141 | padding: 1em; 142 | background: #eef; 143 | } 144 | 145 | .finished-at { 146 | padding-left: 1em; 147 | font-size: .6em; 148 | } 149 | 150 | .show-passed .passed, 151 | .show-skipped .skipped { 152 | display: block; 153 | } 154 | 155 | 156 | #jasmine_content { 157 | position:fixed; 158 | right: 100%; 159 | } 160 | 161 | .runner { 162 | border: 1px solid gray; 163 | display: block; 164 | margin: 5px 0; 165 | padding: 2px 0 2px 10px; 166 | } 167 | -------------------------------------------------------------------------------- /libraries/json2.js: -------------------------------------------------------------------------------- 1 | /* 2 | http://www.JSON.org/json2.js 3 | 2010-03-20 4 | 5 | Public Domain. 6 | 7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 8 | 9 | See http://www.JSON.org/js.html 10 | 11 | 12 | This code should be minified before deployment. 13 | See http://javascript.crockford.com/jsmin.html 14 | 15 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO 16 | NOT CONTROL. 17 | 18 | 19 | This file creates a global JSON object containing two methods: stringify 20 | and parse. 21 | 22 | JSON.stringify(value, replacer, space) 23 | value any JavaScript value, usually an object or array. 24 | 25 | replacer an optional parameter that determines how object 26 | values are stringified for objects. It can be a 27 | function or an array of strings. 28 | 29 | space an optional parameter that specifies the indentation 30 | of nested structures. If it is omitted, the text will 31 | be packed without extra whitespace. If it is a number, 32 | it will specify the number of spaces to indent at each 33 | level. If it is a string (such as '\t' or ' '), 34 | it contains the characters used to indent at each level. 35 | 36 | This method produces a JSON text from a JavaScript value. 37 | 38 | When an object value is found, if the object contains a toJSON 39 | method, its toJSON method will be called and the result will be 40 | stringified. A toJSON method does not serialize: it returns the 41 | value represented by the name/value pair that should be serialized, 42 | or undefined if nothing should be serialized. The toJSON method 43 | will be passed the key associated with the value, and this will be 44 | bound to the value 45 | 46 | For example, this would serialize Dates as ISO strings. 47 | 48 | Date.prototype.toJSON = function (key) { 49 | function f(n) { 50 | // Format integers to have at least two digits. 51 | return n < 10 ? '0' + n : n; 52 | } 53 | 54 | return this.getUTCFullYear() + '-' + 55 | f(this.getUTCMonth() + 1) + '-' + 56 | f(this.getUTCDate()) + 'T' + 57 | f(this.getUTCHours()) + ':' + 58 | f(this.getUTCMinutes()) + ':' + 59 | f(this.getUTCSeconds()) + 'Z'; 60 | }; 61 | 62 | You can provide an optional replacer method. It will be passed the 63 | key and value of each member, with this bound to the containing 64 | object. The value that is returned from your method will be 65 | serialized. If your method returns undefined, then the member will 66 | be excluded from the serialization. 67 | 68 | If the replacer parameter is an array of strings, then it will be 69 | used to select the members to be serialized. It filters the results 70 | such that only members with keys listed in the replacer array are 71 | stringified. 72 | 73 | Values that do not have JSON representations, such as undefined or 74 | functions, will not be serialized. Such values in objects will be 75 | dropped; in arrays they will be replaced with null. You can use 76 | a replacer function to replace those with JSON values. 77 | JSON.stringify(undefined) returns undefined. 78 | 79 | The optional space parameter produces a stringification of the 80 | value that is filled with line breaks and indentation to make it 81 | easier to read. 82 | 83 | If the space parameter is a non-empty string, then that string will 84 | be used for indentation. If the space parameter is a number, then 85 | the indentation will be that many spaces. 86 | 87 | Example: 88 | 89 | text = JSON.stringify(['e', {pluribus: 'unum'}]); 90 | // text is '["e",{"pluribus":"unum"}]' 91 | 92 | 93 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); 94 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' 95 | 96 | text = JSON.stringify([new Date()], function (key, value) { 97 | return this[key] instanceof Date ? 98 | 'Date(' + this[key] + ')' : value; 99 | }); 100 | // text is '["Date(---current time---)"]' 101 | 102 | 103 | JSON.parse(text, reviver) 104 | This method parses a JSON text to produce an object or array. 105 | It can throw a SyntaxError exception. 106 | 107 | The optional reviver parameter is a function that can filter and 108 | transform the results. It receives each of the keys and values, 109 | and its return value is used instead of the original value. 110 | If it returns what it received, then the structure is not modified. 111 | If it returns undefined then the member is deleted. 112 | 113 | Example: 114 | 115 | // Parse the text. Values that look like ISO date strings will 116 | // be converted to Date objects. 117 | 118 | myData = JSON.parse(text, function (key, value) { 119 | var a; 120 | if (typeof value === 'string') { 121 | a = 122 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); 123 | if (a) { 124 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], 125 | +a[5], +a[6])); 126 | } 127 | } 128 | return value; 129 | }); 130 | 131 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { 132 | var d; 133 | if (typeof value === 'string' && 134 | value.slice(0, 5) === 'Date(' && 135 | value.slice(-1) === ')') { 136 | d = new Date(value.slice(5, -1)); 137 | if (d) { 138 | return d; 139 | } 140 | } 141 | return value; 142 | }); 143 | 144 | 145 | This is a reference implementation. You are free to copy, modify, or 146 | redistribute. 147 | */ 148 | 149 | /*jslint evil: true, strict: false */ 150 | 151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, 152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, 153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, 154 | lastIndex, length, parse, prototype, push, replace, slice, stringify, 155 | test, toJSON, toString, valueOf 156 | */ 157 | 158 | 159 | // Create a JSON object only if one does not already exist. We create the 160 | // methods in a closure to avoid creating global variables. 161 | 162 | if (!this.JSON) { 163 | this.JSON = {}; 164 | } 165 | 166 | (function () { 167 | 168 | function f(n) { 169 | // Format integers to have at least two digits. 170 | return n < 10 ? '0' + n : n; 171 | } 172 | 173 | if (typeof Date.prototype.toJSON !== 'function') { 174 | 175 | Date.prototype.toJSON = function (key) { 176 | 177 | return isFinite(this.valueOf()) ? 178 | this.getUTCFullYear() + '-' + 179 | f(this.getUTCMonth() + 1) + '-' + 180 | f(this.getUTCDate()) + 'T' + 181 | f(this.getUTCHours()) + ':' + 182 | f(this.getUTCMinutes()) + ':' + 183 | f(this.getUTCSeconds()) + 'Z' : null; 184 | }; 185 | 186 | String.prototype.toJSON = 187 | Number.prototype.toJSON = 188 | Boolean.prototype.toJSON = function (key) { 189 | return this.valueOf(); 190 | }; 191 | } 192 | 193 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 194 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 195 | gap, 196 | indent, 197 | meta = { // table of character substitutions 198 | '\b': '\\b', 199 | '\t': '\\t', 200 | '\n': '\\n', 201 | '\f': '\\f', 202 | '\r': '\\r', 203 | '"' : '\\"', 204 | '\\': '\\\\' 205 | }, 206 | rep; 207 | 208 | 209 | function quote(string) { 210 | 211 | // If the string contains no control characters, no quote characters, and no 212 | // backslash characters, then we can safely slap some quotes around it. 213 | // Otherwise we must also replace the offending characters with safe escape 214 | // sequences. 215 | 216 | escapable.lastIndex = 0; 217 | return escapable.test(string) ? 218 | '"' + string.replace(escapable, function (a) { 219 | var c = meta[a]; 220 | return typeof c === 'string' ? c : 221 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 222 | }) + '"' : 223 | '"' + string + '"'; 224 | } 225 | 226 | 227 | function str(key, holder) { 228 | 229 | // Produce a string from holder[key]. 230 | 231 | var i, // The loop counter. 232 | k, // The member key. 233 | v, // The member value. 234 | length, 235 | mind = gap, 236 | partial, 237 | value = holder[key]; 238 | 239 | // If the value has a toJSON method, call it to obtain a replacement value. 240 | 241 | if (value && typeof value === 'object' && 242 | typeof value.toJSON === 'function') { 243 | value = value.toJSON(key); 244 | } 245 | 246 | // If we were called with a replacer function, then call the replacer to 247 | // obtain a replacement value. 248 | 249 | if (typeof rep === 'function') { 250 | value = rep.call(holder, key, value); 251 | } 252 | 253 | // What happens next depends on the value's type. 254 | 255 | switch (typeof value) { 256 | case 'string': 257 | return quote(value); 258 | 259 | case 'number': 260 | 261 | // JSON numbers must be finite. Encode non-finite numbers as null. 262 | 263 | return isFinite(value) ? String(value) : 'null'; 264 | 265 | case 'boolean': 266 | case 'null': 267 | 268 | // If the value is a boolean or null, convert it to a string. Note: 269 | // typeof null does not produce 'null'. The case is included here in 270 | // the remote chance that this gets fixed someday. 271 | 272 | return String(value); 273 | 274 | // If the type is 'object', we might be dealing with an object or an array or 275 | // null. 276 | 277 | case 'object': 278 | 279 | // Due to a specification blunder in ECMAScript, typeof null is 'object', 280 | // so watch out for that case. 281 | 282 | if (!value) { 283 | return 'null'; 284 | } 285 | 286 | // Make an array to hold the partial results of stringifying this object value. 287 | 288 | gap += indent; 289 | partial = []; 290 | 291 | // Is the value an array? 292 | 293 | if (Object.prototype.toString.apply(value) === '[object Array]') { 294 | 295 | // The value is an array. Stringify every element. Use null as a placeholder 296 | // for non-JSON values. 297 | 298 | length = value.length; 299 | for (i = 0; i < length; i += 1) { 300 | partial[i] = str(i, value) || 'null'; 301 | } 302 | 303 | // Join all of the elements together, separated with commas, and wrap them in 304 | // brackets. 305 | 306 | v = partial.length === 0 ? '[]' : 307 | gap ? '[\n' + gap + 308 | partial.join(',\n' + gap) + '\n' + 309 | mind + ']' : 310 | '[' + partial.join(',') + ']'; 311 | gap = mind; 312 | return v; 313 | } 314 | 315 | // If the replacer is an array, use it to select the members to be stringified. 316 | 317 | if (rep && typeof rep === 'object') { 318 | length = rep.length; 319 | for (i = 0; i < length; i += 1) { 320 | k = rep[i]; 321 | if (typeof k === 'string') { 322 | v = str(k, value); 323 | if (v) { 324 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 325 | } 326 | } 327 | } 328 | } else { 329 | 330 | // Otherwise, iterate through all of the keys in the object. 331 | 332 | for (k in value) { 333 | if (Object.hasOwnProperty.call(value, k)) { 334 | v = str(k, value); 335 | if (v) { 336 | partial.push(quote(k) + (gap ? ': ' : ':') + v); 337 | } 338 | } 339 | } 340 | } 341 | 342 | // Join all of the member texts together, separated with commas, 343 | // and wrap them in braces. 344 | 345 | v = partial.length === 0 ? '{}' : 346 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + 347 | mind + '}' : '{' + partial.join(',') + '}'; 348 | gap = mind; 349 | return v; 350 | } 351 | } 352 | 353 | // If the JSON object does not yet have a stringify method, give it one. 354 | 355 | if (typeof JSON.stringify !== 'function') { 356 | JSON.stringify = function (value, replacer, space) { 357 | 358 | // The stringify method takes a value and an optional replacer, and an optional 359 | // space parameter, and returns a JSON text. The replacer can be a function 360 | // that can replace values, or an array of strings that will select the keys. 361 | // A default replacer method can be provided. Use of the space parameter can 362 | // produce text that is more easily readable. 363 | 364 | var i; 365 | gap = ''; 366 | indent = ''; 367 | 368 | // If the space parameter is a number, make an indent string containing that 369 | // many spaces. 370 | 371 | if (typeof space === 'number') { 372 | for (i = 0; i < space; i += 1) { 373 | indent += ' '; 374 | } 375 | 376 | // If the space parameter is a string, it will be used as the indent string. 377 | 378 | } else if (typeof space === 'string') { 379 | indent = space; 380 | } 381 | 382 | // If there is a replacer, it must be a function or an array. 383 | // Otherwise, throw an error. 384 | 385 | rep = replacer; 386 | if (replacer && typeof replacer !== 'function' && 387 | (typeof replacer !== 'object' || 388 | typeof replacer.length !== 'number')) { 389 | throw new Error('JSON.stringify'); 390 | } 391 | 392 | // Make a fake root object containing our value under the key of ''. 393 | // Return the result of stringifying the value. 394 | 395 | return str('', {'': value}); 396 | }; 397 | } 398 | 399 | 400 | // If the JSON object does not yet have a parse method, give it one. 401 | 402 | if (typeof JSON.parse !== 'function') { 403 | JSON.parse = function (text, reviver) { 404 | 405 | // The parse method takes a text and an optional reviver function, and returns 406 | // a JavaScript value if the text is a valid JSON text. 407 | 408 | var j; 409 | 410 | function walk(holder, key) { 411 | 412 | // The walk method is used to recursively walk the resulting structure so 413 | // that modifications can be made. 414 | 415 | var k, v, value = holder[key]; 416 | if (value && typeof value === 'object') { 417 | for (k in value) { 418 | if (Object.hasOwnProperty.call(value, k)) { 419 | v = walk(value, k); 420 | if (v !== undefined) { 421 | value[k] = v; 422 | } else { 423 | delete value[k]; 424 | } 425 | } 426 | } 427 | } 428 | return reviver.call(holder, key, value); 429 | } 430 | 431 | 432 | // Parsing happens in four stages. In the first stage, we replace certain 433 | // Unicode characters with escape sequences. JavaScript handles many characters 434 | // incorrectly, either silently deleting them, or treating them as line endings. 435 | 436 | text = String(text); 437 | cx.lastIndex = 0; 438 | if (cx.test(text)) { 439 | text = text.replace(cx, function (a) { 440 | return '\\u' + 441 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4); 442 | }); 443 | } 444 | 445 | // In the second stage, we run the text against regular expressions that look 446 | // for non-JSON patterns. We are especially concerned with '()' and 'new' 447 | // because they can cause invocation, and '=' because it can cause mutation. 448 | // But just to be safe, we want to reject all unexpected forms. 449 | 450 | // We split the second stage into 4 regexp operations in order to work around 451 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 452 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we 453 | // replace all simple value tokens with ']' characters. Third, we delete all 454 | // open brackets that follow a colon or comma or that begin the text. Finally, 455 | // we look to see that the remaining characters are only whitespace or ']' or 456 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. 457 | 458 | if (/^[\],:{}\s]*$/. 459 | test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). 460 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). 461 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { 462 | 463 | // In the third stage we use the eval function to compile the text into a 464 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity 465 | // in JavaScript: it can begin a block or an object literal. We wrap the text 466 | // in parens to eliminate the ambiguity. 467 | 468 | j = eval('(' + text + ')'); 469 | 470 | // In the optional fourth stage, we recursively walk the new structure, passing 471 | // each name/value pair to a reviver function for possible transformation. 472 | 473 | return typeof reviver === 'function' ? 474 | walk({'': j}, '') : j; 475 | } 476 | 477 | // If the text is not JSON parseable, then a SyntaxError is thrown. 478 | 479 | throw new SyntaxError('JSON.parse'); 480 | }; 481 | } 482 | }()); 483 | -------------------------------------------------------------------------------- /libraries/parseuri.js: -------------------------------------------------------------------------------- 1 | // parseUri 1.2.2 2 | // (c) Steven Levithan 3 | // MIT License 4 | 5 | function parseUri (str) { 6 | var o = parseUri.options, 7 | m = o.parser[o.strictMode ? "strict" : "loose"].exec(str), 8 | uri = {}, 9 | i = 14; 10 | 11 | while (i--) uri[o.key[i]] = m[i] || ""; 12 | 13 | uri[o.q.name] = {}; 14 | uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) { 15 | if ($1) uri[o.q.name][$1] = $2; 16 | }); 17 | 18 | return uri; 19 | }; 20 | 21 | parseUri.options = { 22 | strictMode: false, 23 | key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], 24 | q: { 25 | name: "queryKey", 26 | parser: /(?:^|&)([^&=]*)=?([^&]*)/g 27 | }, 28 | parser: { 29 | strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, 30 | loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /libraries/sage/class.js: -------------------------------------------------------------------------------- 1 | /* 2 | Make a new Class: 3 | var Person = Sage.Class.define({ 4 | constructor: function(str) { 5 | this.name = str; 6 | }, 7 | iAm: function() { 8 | return this.name; 9 | } 10 | }); 11 | 12 | To create a class which inherits from an already existing one 13 | just call the already-existing class' extend() method: ** 14 | var Knight = Person.extend({ 15 | iAm: function() { 16 | return 'Sir ' + this.base(); 17 | }, 18 | joust: function() { 19 | return 'Yaaaaaa!'; 20 | } 21 | }); 22 | Notice the Knight's iAm() method has access to it's 'super' 23 | via this.base(); 24 | 25 | ** differs from the Ext method of having to pass in the parent, 26 | ** ours defines the extend() method directly on every defined class 27 | */ 28 | /*global Sage $ alert*/ 29 | if(Sage) { 30 | (function(S) { 31 | var INITIALIZING = false, 32 | // straight outta base2 33 | OVERRIDE = /xyz/.test(function(){xyz;}) ? /\bbase\b/ : /.*/; 34 | 35 | // The base Class placeholder 36 | S.Class = function(){}; 37 | // Create a new Class that inherits from this class 38 | S.Class.define = function(prop) { 39 | var base = this.prototype; 40 | // Instantiate a base class (but only create the instance) 41 | INITIALIZING = true; 42 | var prototype = new this(); 43 | INITIALIZING = false; 44 | 45 | var wrap = function(name, fn) { 46 | return function() { 47 | var tmp = this.base; 48 | // Add a new .base() method that is the same method 49 | // but on the base class 50 | this.base = base[name]; 51 | // The method only need to be bound temporarily, so we 52 | // remove it when we're done executing 53 | var ret = fn.apply(this, arguments); 54 | this.base = tmp; 55 | return ret; 56 | }; 57 | }; 58 | 59 | // Copy the properties over onto the new prototype 60 | var hidden = ['constructor'], 61 | i = 0, 62 | name; 63 | 64 | for (name in prop) { 65 | // Check if we're overwriting an existing function 66 | prototype[name] = typeof prop[name] === "function" && 67 | typeof base[name] === "function" && 68 | OVERRIDE.test(prop[name]) ? wrap(name, prop[name]) : prop[name]; 69 | } 70 | 71 | while (name = hidden[i++]) 72 | if (prop[name] != base[name]) 73 | prototype[name] = typeof prop[name] === "function" && 74 | typeof base[name] === "function" && 75 | OVERRIDE.test(prop[name]) ? wrap(name, prop[name]) : prop[name]; 76 | 77 | // The dummy class constructor 78 | function Class() { 79 | // All construction is actually done in the initialize method 80 | if ( !INITIALIZING && this.constructor ) { 81 | this.constructor.apply(this, arguments); 82 | } 83 | } 84 | // Populate the constructed prototype object 85 | Class.prototype = prototype; 86 | // Enforce the constructor to be what we expect 87 | Class.constructor = Class; 88 | // And make this class 'define-able' 89 | Class.define = arguments.callee; 90 | Class.extend = Class.define; // sounds better for inherited classes 91 | return Class; 92 | }; 93 | }(Sage)); 94 | } -------------------------------------------------------------------------------- /libraries/sage/deferred.js: -------------------------------------------------------------------------------- 1 | /*global Sage $ alert*/ 2 | if(Sage) { 3 | (function(S) { 4 | // place the Deferred class into Sage.Utility 5 | S.namespace('Utility'); 6 | 7 | S.Utility.Deferred = function(fn, args, scope) { 8 | var that = this, id, 9 | c = function() { 10 | clearInterval(id); 11 | id = null; 12 | fn.apply(scope, args || []); 13 | }; 14 | that.delay = function(n) { 15 | that.cancel(); 16 | // an named interval that can be cancelled 17 | id = setInterval(c, n); 18 | }; 19 | that.cancel = function() { 20 | if(id) { 21 | clearInterval(id); 22 | id = null; 23 | } 24 | }; 25 | }; 26 | }(Sage)); 27 | } -------------------------------------------------------------------------------- /libraries/sage/event.js: -------------------------------------------------------------------------------- 1 | // Event class is instantiated by the Evented class. Probably no need 2 | // to call this directly 3 | 4 | /*global Sage $ alert*/ 5 | if(Sage) { 6 | (function(S) { 7 | var SLICE = Array.prototype.slice, 8 | TRUE = true, FALSE = false, 9 | WIN = S.config.win, 10 | TARGETED = function(f,o,scope) { 11 | return function() { 12 | if(o.target === arguments[0]){ 13 | f.apply(scope, SLICE.call(arguments, 0)); 14 | } 15 | }; 16 | }, 17 | BUFFERED = function(f,o,l,scope) { 18 | l.task = new S.Utility.Deferred(); 19 | return function(){ 20 | l.task.delay(o.buffer, f, scope, SLICE.call(arguments, 0)); 21 | }; 22 | }, 23 | SINGLE = function(f,ev,fn,scope) { 24 | return function(){ 25 | ev.removeListener(fn, scope); 26 | return f.apply(scope, arguments); 27 | }; 28 | }, 29 | DELAYED = function(f,o,l,scope) { 30 | return function() { 31 | var task = new S.Utility.Deferred(); 32 | if(!l.tasks) { 33 | l.tasks = []; 34 | } 35 | l.tasks.push(task); 36 | task.delay(o.delay || 10, f, scope, SLICE.call(arguments, 0)); 37 | }; 38 | }; 39 | // place the Event class in Utility 40 | S.namespace('Utility'); 41 | 42 | S.Utility.Event = Sage.Class.define({ 43 | constructor: function(obj, name) { 44 | this.name = name; 45 | this.obj = obj; 46 | this.listeners = []; 47 | }, 48 | addListener: function(fn, scope, options){ 49 | var that = this,l; 50 | scope = scope || that.obj; 51 | if(!that.isListening(fn, scope)) { 52 | l = that.createListener(fn, scope, options); 53 | if(that.firing) { 54 | that.listeners = that.listeners.slice(0); 55 | } 56 | that.listeners.push(l); 57 | } 58 | }, 59 | createListener: function(fn, scope, o) { 60 | o = o || {}; 61 | scope = scope || this.obj; 62 | var l = { 63 | fn: fn, 64 | scope: scope, 65 | options: o 66 | }, h = fn; 67 | if(o.target){ 68 | h = TARGETED(h, o, scope); 69 | } 70 | if(o.delay){ 71 | h = DELAYED(h, o, l, scope); 72 | } 73 | if(o.single){ 74 | h = SINGLE(h, this, fn, scope); 75 | } 76 | if(o.buffer){ 77 | h = BUFFERED(h, o, l, scope); 78 | } 79 | l.fireFn = h; 80 | return l; 81 | }, 82 | findListener: function(fn, scope){ 83 | var list = this.listeners, 84 | i = list.length,l; 85 | scope = scope || this.obj; 86 | while(i--) { 87 | l = list[i]; 88 | if(l) { 89 | if(l.fn === fn && l.scope === scope){ 90 | return i; 91 | } 92 | } 93 | } 94 | return -1; 95 | }, 96 | isListening: function(fn, scope){ 97 | return this.findListener(fn, scope) !== -1; 98 | }, 99 | removeListener: function(fn, scope){ 100 | var that = this, index, l, k, 101 | result = FALSE; 102 | if((index = that.findListener(fn, scope)) !== -1) { 103 | if (that.firing) { 104 | that.listeners = that.listeners.slice(0); 105 | } 106 | l = that.listeners[index]; 107 | if(l.task) { 108 | l.task.cancel(); 109 | delete l.task; 110 | } 111 | k = l.tasks && l.tasks.length; 112 | if(k) { 113 | while(k--) { 114 | l.tasks[k].cancel(); 115 | } 116 | delete l.tasks; 117 | } 118 | that.listeners.splice(index, 1); 119 | result = TRUE; 120 | } 121 | return result; 122 | }, 123 | // Iterate to stop any buffered/delayed events 124 | clearListeners: function() { 125 | var that = this, 126 | l = that.listeners, 127 | i = l.length; 128 | while(i--) { 129 | that.removeListener(l[i].fn, l[i].scope); 130 | } 131 | }, 132 | fire: function(){ 133 | var that = this, 134 | listeners = that.listeners, 135 | len = listeners.length, 136 | i = 0, l, args; 137 | if(len > 0) { 138 | that.firing = TRUE; 139 | args = SLICE.call(arguments, 0); 140 | for (; i < len; i++) { 141 | l = listeners[i]; 142 | if(l && l.fireFn.apply(l.scope || that.obj || 143 | WIN, args) === FALSE) { 144 | return (that.firing = FALSE); 145 | } 146 | } 147 | } 148 | that.firing = FALSE; 149 | return TRUE; 150 | } 151 | }); // end S.Event class 152 | }(Sage)); 153 | } -------------------------------------------------------------------------------- /libraries/sage/evented.js: -------------------------------------------------------------------------------- 1 | /* 2 | var Employee = Sage.Evented.extend({ 3 | constructor: function(c) { 4 | this.name = c.name; 5 | this.events = { 6 | quit: true 7 | }; 8 | this.base(c); 9 | } 10 | }); 11 | 12 | var Dev = new Employee({ 13 | name: "Rob", 14 | listeners: { 15 | quit: function() {console.log(this.name + ' has quit!'); } 16 | } 17 | }); 18 | */ 19 | 20 | /*global Sage $ alert*/ 21 | if(Sage) { 22 | (function(S) { 23 | var SLICE = Array.prototype.slice, 24 | TRUE = true, FALSE = false, 25 | // do not include these 26 | FILTER = /^(?:scope|delay|buffer|single)$/, 27 | EACH = S.each; 28 | 29 | S.Evented = S.Class.define({ 30 | constructor: function(config) { 31 | var that = this, 32 | e = that.events; 33 | if(config && config.listeners) { 34 | that.addListener(config.listeners); 35 | } 36 | that.events = e || {}; 37 | }, 38 | fireEvent: function() { 39 | var that = this, 40 | args = SLICE.call(arguments, 0), 41 | eventName = args[0].toLowerCase(), 42 | result = TRUE, 43 | current = this.events[eventName], 44 | b,c, 45 | q = that.eventQueue || []; 46 | // TODO: evaluate use of deferring events 47 | if (that.eventsSuspended === TRUE) { 48 | q.push(args); 49 | } 50 | if (typeof current === 'object') { 51 | if(current.bubble) { 52 | if(current.fire.apply(current, args.slice(1)) === FALSE) { 53 | return FALSE; 54 | } 55 | b = that.getBubbleTarget && that.getBubbleTarget(); 56 | if(b && b.enableBubble) { 57 | c = b.events[eventName]; 58 | if(!c || typeof c !== 'object' || !c.bubble) { 59 | b.enableBubble(eventName); 60 | } 61 | return b.fireEvent.apply(b, args); 62 | } 63 | } else { 64 | // remove the event name 65 | args.shift(); 66 | result = current.fire.apply(current, args); 67 | } 68 | } 69 | return result; 70 | }, 71 | addListener : function(eventName, fn, scope, o){ 72 | var that = this, e, oe, ce; 73 | if (typeof eventName === 'object') { 74 | o = eventName; 75 | for (e in o){ 76 | oe = o[e]; 77 | if (!FILTER.test(e)) { 78 | that.addListener(e, oe.fn || oe, oe.scope || 79 | o.scope, oe.fn ? oe : o); 80 | } 81 | } 82 | } else { 83 | eventName = eventName.toLowerCase(); 84 | ce = that.events[eventName] || TRUE; 85 | if (typeof ce === 'boolean') { 86 | that.events[eventName] = ce = new S.Utility.Event(that, eventName); 87 | } 88 | ce.addListener(fn, scope, typeof o === 'object' ? o : {}); 89 | } 90 | }, 91 | removeListener : function(eventName, fn, scope) { 92 | var ce = this.events[eventName.toLowerCase()]; 93 | if (typeof ce === 'object') { 94 | ce.removeListener(fn, scope); 95 | } 96 | }, 97 | purgeListeners : function(){ 98 | var events = this.events,evt,key; 99 | for(key in events) { 100 | evt = events[key]; 101 | if(typeof evt === 'object') { 102 | evt.clearListeners(); 103 | } 104 | } 105 | }, 106 | addEvents : function(o){ 107 | var that = this, arg, i; 108 | that.events = that.events || {}; 109 | if (typeof o === 'string') { 110 | arg = arguments; 111 | i = arg.length; 112 | while(i--) { 113 | that.events[arg[i]] = that.events[arg[i]] || TRUE; 114 | } 115 | } else { 116 | Sage.apply(that.events, o); 117 | } 118 | }, 119 | hasListener : function(eventName){ 120 | var e = this.events[eventName.toLowerCase()]; 121 | return typeof e === 'object' && e.listeners.length > 0; 122 | }, 123 | suspendEvents : function(queueSuspended){ 124 | this.eventsSuspended = TRUE; 125 | if(queueSuspended && !this.eventQueue){ 126 | this.eventQueue = []; 127 | } 128 | }, 129 | resumeEvents : function(){ 130 | var that = this, 131 | queued = that.eventQueue || []; 132 | that.eventsSuspended = FALSE; 133 | delete that.eventQueue; 134 | // use jquery's each method 135 | EACH(queued, function(e) { 136 | that.fireEvent.apply(that, e); 137 | }); 138 | } 139 | }); //end S.Evented 140 | 141 | S.Evented.prototype.on = S.Evented.prototype.addListener; 142 | S.Evented.prototype.un = S.Evented.prototype.removeListener; 143 | }(Sage)); 144 | } -------------------------------------------------------------------------------- /libraries/sage/sage.js: -------------------------------------------------------------------------------- 1 | // The Top-Level Namespace 2 | /*global Sage $ alert*/ 3 | Sage = (function() { 4 | var apply = function(a, b, c) 5 | { 6 | if (a && c) for (var n in c) a[n] = c[n]; 7 | if (a && b) for (var n in b) a[n] = b[n]; 8 | return a; 9 | }; 10 | var namespace = function(name, scope) 11 | { 12 | var parts = name.split('.'); 13 | var o = scope || (parts[0] !== 'Sage' ? this : window); 14 | for (var i = 0; i < parts.length; i++) o = (o[parts[i]] = o[parts[i]] || {__namespace: true}); 15 | return o; 16 | }; 17 | var iter = function(o, cb, scope) 18 | { 19 | if (isArray(o)) 20 | { 21 | var l = o.length; 22 | for (var i = 0; i < l; i++) 23 | cb.call(scope || o[i], i, o[i]); 24 | } 25 | else 26 | for (var n in o) 27 | if (o.hasOwnProperty(n)) 28 | cb.call(scope || o[n], n, o[n]); 29 | }; 30 | var isArray = function(o) 31 | { 32 | return Object.prototype.toString.call(o) == '[object Array]'; 33 | }; 34 | return { 35 | config: { 36 | win: window || {}, 37 | doc: document 38 | }, 39 | apply: apply, 40 | namespace: namespace, 41 | each: iter, 42 | isArray: isArray, 43 | __namespace: true 44 | }; 45 | }()); -------------------------------------------------------------------------------- /src/SDataAjax.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | A = Sage.namespace('Sage.SData.Client.Ajax'); 19 | 20 | var successful = function(code) 21 | { 22 | return ((code >= 200 && code < 300) || code === 304); 23 | }; 24 | 25 | var onReadyStateChange = function(xhr, o) 26 | { 27 | if (xhr.readyState == 4) 28 | { 29 | if (successful(xhr.status)) 30 | { 31 | if (o.success) 32 | o.success.call(o.scope || this, xhr, o); 33 | } 34 | else if (xhr.status === 0) 35 | { 36 | var isAbortedRequest = false; 37 | try 38 | { 39 | // FF will throw an exception on access of statusText on an aborted request 40 | isAbortedRequest = (xhr.statusText === ''); 41 | } 42 | catch (exception) 43 | { 44 | isAbortedRequest = true; 45 | } 46 | 47 | if (isAbortedRequest) 48 | { 49 | var handler = o.aborted || o.failure; 50 | if (handler) 51 | handler.call(o.scope || this, xhr, o); 52 | } 53 | else 54 | { 55 | if (o.failure) 56 | o.failure.call(o.scope || this, xhr, o); 57 | } 58 | } 59 | else 60 | { 61 | if (o.failure) 62 | o.failure.call(o.scope || this, xhr, o); 63 | } 64 | } 65 | }; 66 | 67 | var bindOnReadyStateChange = function(xhr, o) { 68 | xhr.onreadystatechange = function() { 69 | onReadyStateChange.call(xhr, xhr, o); 70 | }; 71 | }; 72 | 73 | var buildParameters = function(params) { 74 | var query = []; 75 | for (var n in params) 76 | { 77 | query.push( 78 | encodeURIComponent(n) + 79 | '=' + 80 | encodeURIComponent(params[n]) 81 | ); 82 | } 83 | return query.join('&'); 84 | }; 85 | 86 | Sage.apply(Sage.SData.Client.Ajax, { 87 | request: function(o) { 88 | var o = S.apply({}, o); 89 | 90 | o.params = S.apply({}, o.params); 91 | o.headers = S.apply({}, o.headers); 92 | 93 | if (o.cache !== true) 94 | o.params[o.cacheParam || '_t'] = (new Date()).getTime(); 95 | 96 | o.method = o.method || 'GET'; 97 | 98 | var parameters = buildParameters(o.params); 99 | if (parameters) 100 | o.url = o.url + (/\?/.test(o.url) ? '&' : '?') + parameters; 101 | 102 | var xhr = new XMLHttpRequest(); 103 | 104 | if (o.user) 105 | xhr.open(o.method, o.url, o.async !== false, o.user, o.password); 106 | else 107 | xhr.open(o.method, o.url, o.async !== false); 108 | 109 | if (o.withCredentials) xhr.withCredentials = true; 110 | 111 | try 112 | { 113 | xhr.setRequestHeader('Accept', o.accept || '*/*'); 114 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 115 | 116 | if (o.contentType) 117 | xhr.setRequestHeader('Content-Type', o.contentType); 118 | 119 | for (var n in o.headers) 120 | xhr.setRequestHeader(n, o.headers[n]); 121 | } 122 | catch (headerException) 123 | { 124 | } 125 | 126 | if (o.async !== false) 127 | { 128 | bindOnReadyStateChange(xhr, o); 129 | 130 | xhr.send(o.body || null); 131 | } 132 | else 133 | { 134 | xhr.send(o.body || null); 135 | 136 | onReadyStateChange(xhr, o); 137 | } 138 | 139 | return xhr; 140 | }, 141 | cancel: function(xhr) { 142 | xhr.abort(); 143 | } 144 | }); 145 | })(); 146 | -------------------------------------------------------------------------------- /src/SDataApplicationRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataApplicationRequest = Sage.SData.Client.SDataBaseRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | 24 | if (this.service) 25 | { 26 | this.uri.setProduct(this.service.getApplicationName() ? this.service.getApplicationName() : '-'); 27 | this.uri.setContract(this.service.getContractName() ? this.service.getContractName() : '-'); 28 | this.uri.setCompanyDataset(this.service.getDataSet() ? this.service.getDataSet() : '-'); 29 | } 30 | }, 31 | clone: function() { 32 | return new Sage.SData.Client.SDataApplicationRequest(this.service) 33 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 34 | }, 35 | getApplicationName: function() { 36 | return this.uri.getProduct(); 37 | }, 38 | setApplicationName: function(value) { 39 | this.uri.setProduct(value); 40 | return this; 41 | }, 42 | getContractName: function() { 43 | return this.uri.getContract(); 44 | }, 45 | setContractName: function(value) { 46 | this.uri.setContract(value); 47 | return this; 48 | }, 49 | getDataSet: function() { 50 | return this.uri.getCompanyDataset(); 51 | }, 52 | setDataSet: function(value) { 53 | this.uri.setCompanyDataset(value); 54 | return this; 55 | }, 56 | getResourceKind: function() { 57 | return this.uri.getCollectionType(); 58 | }, 59 | setResourceKind: function(value) { 60 | this.uri.setCollectionType(value); 61 | return this; 62 | } 63 | }); 64 | })(); 65 | 66 | -------------------------------------------------------------------------------- /src/SDataBaseRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataBaseRequest = Sage.Class.define({ 21 | service: null, 22 | uri: null, 23 | completeHeaders: null, 24 | extendedHeaders: null, 25 | constructor: function(service) { 26 | this.base.apply(this, arguments); 27 | 28 | this.service = service; 29 | 30 | this.completeHeaders = {}; 31 | this.extendedHeaders = {}; 32 | this.uri = new Sage.SData.Client.SDataUri(); 33 | 34 | if (this.service) 35 | { 36 | this.uri.setVersion(this.service.getVersion()); 37 | this.uri.setIncludeContent(this.service.getIncludeContent()); 38 | this.uri.setServer(this.service.getVirtualDirectory() ? this.service.getVirtualDirectory() : 'sdata'); 39 | this.uri.setScheme(this.service.getProtocol()); 40 | this.uri.setHost(this.service.getServerName()); 41 | this.uri.setPort(this.service.getPort()); 42 | } 43 | }, 44 | clone: function() { 45 | return new Sage.SData.Client.SDataBaseRequest(this.service) 46 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 47 | }, 48 | setRequestHeader: function(name, value) { 49 | this.completeHeaders[name] = value; 50 | }, 51 | /** 52 | * Sets an extension for a request header to be handled appropriately by the service. For example, extending 53 | * the `Accept` header, will append the values to the existing `Accept` headers value. 54 | * 55 | * @param name 56 | * @param value 57 | */ 58 | extendRequestHeader: function(name, value) { 59 | this.extendedHeaders[name] = value; 60 | }, 61 | clearRequestHeader: function(name) { 62 | delete this.completeHeaders[name]; 63 | delete this.extendedHeaders[name]; 64 | }, 65 | getAccept: function() { 66 | return this.extendedHeaders['Accept']; 67 | }, 68 | setAccept: function(value) { 69 | this.extendRequestHeader('Accept', value); 70 | return this; 71 | }, 72 | getService: function() { 73 | /// 74 | return this.service; 75 | }, 76 | getUri: function() { 77 | /// 78 | return this.uri; 79 | }, 80 | setUri: function(value) { 81 | this.uri = value; 82 | return this; 83 | }, 84 | getServerName: function() { 85 | return this.uri.getHost(); 86 | }, 87 | setServerName: function(value) { 88 | this.uri.setHost(value); 89 | return this; 90 | }, 91 | getVirtualDirectory: function() { 92 | return this.uri.getServer(); 93 | }, 94 | setVirtualDirectory: function(value) { 95 | this.uri.setServer(value); 96 | return this; 97 | }, 98 | getProtocol: function() { 99 | return this.uri.getScheme(); 100 | }, 101 | setProtocol: function(value) { 102 | this.uri.setScheme(value); 103 | return this; 104 | }, 105 | getPort: function() { 106 | return this.uri.getPort(); 107 | }, 108 | setPort: function(value) { 109 | this.uri.setPort(value); 110 | return this; 111 | }, 112 | getQueryArgs: function() { 113 | return this.uri.getQueryArgs(); 114 | }, 115 | setQueryArgs: function(value, replace) { 116 | this.uri.setQueryArgs(value, replace); 117 | return this; 118 | }, 119 | getQueryArg: function(key) { 120 | return this.uri.getQueryArg(key); 121 | }, 122 | setQueryArg: function(key, value) { 123 | this.uri.setQueryArg(key, value); 124 | return this; 125 | }, 126 | build: function(excludeQuery) { 127 | return this.uri.build(excludeQuery); 128 | }, 129 | toString: function(excludeQuery) { 130 | return this.build(excludeQuery); 131 | } 132 | }); 133 | })(); 134 | -------------------------------------------------------------------------------- /src/SDataBatchRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataBatchRequest = Sage.SData.Client.SDataApplicationRequest.extend({ 21 | items: null, 22 | constructor: function() { 23 | this.base.apply(this, arguments); 24 | 25 | this.items = []; 26 | this.uri.setPathSegment( 27 | Sage.SData.Client.SDataUri.ResourcePropertyIndex, 28 | Sage.SData.Client.SDataUri.BatchSegment 29 | ); 30 | }, 31 | clone: function() { 32 | return new Sage.SData.Client.SDataBatchRequest(this.service) 33 | .setUri(new Sage.SData.Client.SDataUri(this.uri)) 34 | .setItems(this.items.slice(0)); 35 | }, 36 | getItems: function() { 37 | return this.items; 38 | }, 39 | setItems: function(value) { 40 | this.items = value; 41 | return this; 42 | }, 43 | using: function(fn, scope) { 44 | if (this.service) 45 | this.service.registerBatchScope(this); 46 | else 47 | throw "A service must be associated with the batch request."; 48 | 49 | try 50 | { 51 | fn.call(scope || this, this); 52 | } 53 | catch (e) 54 | { 55 | this.service.clearBatchScope(this); 56 | throw e; 57 | } 58 | 59 | this.service.clearBatchScope(this); 60 | 61 | return this; 62 | }, 63 | add: function(item) { 64 | this.items.push(item); 65 | }, 66 | commit: function(options) { 67 | this.service.commitBatch(this, options); 68 | } 69 | }); 70 | })(); -------------------------------------------------------------------------------- /src/SDataNamedQueryRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataNamedQueryRequest = Sage.SData.Client.SDataResourceCollectionRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | 24 | this.uri.setPathSegment( 25 | C.SDataUri.ResourcePropertyIndex, 26 | C.SDataUri.NamedQuerySegment 27 | ); 28 | }, 29 | clone: function() { 30 | return new Sage.SData.Client.SDataNamedQueryRequest(this.service) 31 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 32 | }, 33 | getQueryName: function() { 34 | return this.uri.getPathSegment(C.SDataUri.ResourcePropertyIndex + 1); 35 | }, 36 | setQueryName: function(value) { 37 | this.uri.setPathSegment( 38 | C.SDataUri.ResourcePropertyIndex + 1, 39 | value 40 | ); 41 | return this; 42 | } 43 | }); 44 | })(); 45 | -------------------------------------------------------------------------------- /src/SDataResourceCollectionRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataResourceCollectionRequest = Sage.SData.Client.SDataApplicationRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | }, 24 | clone: function() { 25 | return new Sage.SData.Client.SDataResourceCollectionRequest(this.service) 26 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 27 | }, 28 | getCount: function() { 29 | return this.uri.getCount(); 30 | }, 31 | setCount: function(value) { 32 | this.uri.setCount(value); 33 | return this; 34 | }, 35 | getStartIndex: function() { 36 | return this.uri.getStartIndex(); 37 | }, 38 | setStartIndex: function(value) { 39 | this.uri.setStartIndex(value); 40 | return this; 41 | }, 42 | read: function(options) { 43 | return this.service.readFeed(this, options); 44 | } 45 | }); 46 | })(); 47 | -------------------------------------------------------------------------------- /src/SDataResourcePropertyRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataResourcePropertyRequest = Sage.SData.Client.SDataSingleResourceRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | }, 24 | clone: function() { 25 | return new Sage.SData.Client.SDataResourcePropertyRequest(this.service) 26 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 27 | }, 28 | readFeed: function(options) { 29 | return this.service.readFeed(this, options); 30 | }, 31 | getResourceProperty: function() { 32 | return this.uri.getPathSegment(Sage.SData.Client.SDataUri.ResourcePropertyIndex); 33 | }, 34 | setResourceProperty: function(value) { 35 | this.uri.setPathSegment(Sage.SData.Client.SDataUri.ResourcePropertyIndex, value); 36 | return this; 37 | } 38 | }); 39 | })(); 40 | -------------------------------------------------------------------------------- /src/SDataServiceOperationRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataServiceOperationRequest = Sage.SData.Client.SDataApplicationRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | 24 | this.uri.setPathSegment( 25 | C.SDataUri.ResourcePropertyIndex, 26 | C.SDataUri.ServiceMethodSegment 27 | ); 28 | }, 29 | clone: function() { 30 | return new Sage.SData.Client.SDataServiceOperationRequest(this.service) 31 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 32 | }, 33 | execute: function(entry, options) { 34 | return this.service.executeServiceOperation(this, entry, options); 35 | }, 36 | getOperationName: function() { 37 | return this.uri.getPathSegment(C.SDataUri.ResourcePropertyIndex + 1); 38 | }, 39 | setOperationName: function(name) { 40 | this.uri.setPathSegment(C.SDataUri.ResourcePropertyIndex + 1, name); 41 | return this; 42 | } 43 | }); 44 | })(); 45 | -------------------------------------------------------------------------------- /src/SDataSingleResourceRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataSingleResourceRequest = Sage.SData.Client.SDataApplicationRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | }, 24 | clone: function() { 25 | return new Sage.SData.Client.SDataSingleResourceRequest(this.service) 26 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 27 | }, 28 | read: function(options) { 29 | return this.service.readEntry(this, options); 30 | }, 31 | update: function(entry, options) { 32 | return this.service.updateEntry(this, entry, options); 33 | }, 34 | create: function(entry, options) { 35 | return this.service.createEntry(this, entry, options); 36 | }, 37 | 'delete': function(entry, options) { 38 | return this.service.deleteEntry(this, entry, options); 39 | }, 40 | getResourceSelector: function() { 41 | return this.uri.getCollectionPredicate(); 42 | }, 43 | setResourceSelector: function(value) { 44 | this.uri.setCollectionPredicate(value); 45 | return this; 46 | } 47 | }); 48 | })(); 49 | -------------------------------------------------------------------------------- /src/SDataSystemRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataSystemRequest = Sage.SData.Client.SDataBaseRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | 24 | this.uri.setPathSegment( 25 | Sage.SData.Client.SDataUri.ProductPathIndex, 26 | Sage.SData.Client.SDataUri.SystemSegment 27 | ); 28 | }, 29 | clone: function() { 30 | return new Sage.SData.Client.SDataSystemRequest(this.service) 31 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 32 | }, 33 | getCategory: function() { 34 | this.uri.getPathSegment(Sage.SData.Client.SDataUri.ContractTypePathIndex); 35 | }, 36 | setCategory: function(value) { 37 | this.uri.setPathSegment(Sage.SData.Client.SDataUri.ContractTypePathIndex, value); 38 | return this; 39 | }, 40 | read: function(options) { 41 | return this.service.readFeed(this, options); 42 | } 43 | }); 44 | })(); 45 | -------------------------------------------------------------------------------- /src/SDataTemplateResourceRequest.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'); 19 | 20 | Sage.SData.Client.SDataTemplateResourceRequest = Sage.SData.Client.SDataApplicationRequest.extend({ 21 | constructor: function() { 22 | this.base.apply(this, arguments); 23 | 24 | this.uri.setPathSegment( 25 | Sage.SData.Client.SDataUri.ResourcePropertyIndex, 26 | Sage.SData.Client.SDataUri.TemplateSegment 27 | ); 28 | }, 29 | clone: function() { 30 | return new Sage.SData.Client.SDataTemplateResourceRequest(this.service) 31 | .setUri(new Sage.SData.Client.SDataUri(this.uri)); 32 | }, 33 | read: function(options) { 34 | return this.service.readEntry(this, options); 35 | } 36 | }); 37 | })(); 38 | -------------------------------------------------------------------------------- /src/SDataUri.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010, Sage Software, Inc. All rights reserved. 2 | * 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | (function(){ 17 | var S = Sage, 18 | C = Sage.namespace('Sage.SData.Client'), 19 | trueRE = /^true$/i; 20 | 21 | Sage.SData.Client.SDataUri = Sage.Class.define({ 22 | scheme: 'http', 23 | host: '', 24 | server: '', 25 | port: -1, 26 | version: null, 27 | queryArgs: null, 28 | pathSegments: null, 29 | constructor: function(uri) { 30 | /// 31 | 32 | this.base.apply(this, arguments); 33 | 34 | S.apply(this, uri); 35 | 36 | /* create copies; segments only needs a shallow copy, as elements are replaced, not modified. */ 37 | this.queryArgs = S.apply({}, uri && uri.queryArgs); 38 | this.pathSegments = (uri && uri.pathSegments && uri.pathSegments.slice(0)) || []; 39 | this.version = (uri && uri.version && S.apply({}, uri.version)) || { major: 1, minor: 0 }; 40 | }, 41 | clone: function() { 42 | return new Sage.SData.Client.SDataUri(this); 43 | }, 44 | getVersion: function() { 45 | return this.version; 46 | }, 47 | setVersion: function(value) { 48 | this.version = S.apply({ 49 | major: 0, 50 | minor: 0 51 | }, value); 52 | 53 | return this; 54 | }, 55 | getScheme: function() { 56 | /// The scheme component of the URI. 57 | return this.scheme; 58 | }, 59 | setScheme: function(value) { 60 | /// The new scheme for the URI 61 | this.scheme = value; 62 | 63 | return this; 64 | }, 65 | getHost: function() { 66 | /// The host component of the URI. 67 | return this.host; 68 | }, 69 | setHost: function(value) { 70 | /// The new host for the URI 71 | this.host = value; 72 | 73 | return this; 74 | }, 75 | getPort: function() { 76 | /// The port component of the URI. 77 | return this.port; 78 | }, 79 | setPort: function(value) { 80 | /// The new port for the URI 81 | this.port = value; 82 | 83 | return this; 84 | }, 85 | getServer: function() { 86 | /// 87 | /// Access the SData "server" component of the URI. This is the first path segment in the URI. 88 | /// 89 | /// i.e. [scheme]://[host]/[server] 90 | /// 91 | /// The SData "server" component of URI. 92 | return this.server; 93 | }, 94 | setServer: function(value) { 95 | /// The new SData "server" for the URI 96 | this.server = value; 97 | 98 | return this; 99 | }, 100 | getQueryArgs: function() { 101 | /// The query arguments of the URI. 102 | return this.queryArgs; 103 | }, 104 | setQueryArgs: function(value, replace) { 105 | /// 106 | /// The query arguments that will either be merged with the existing values, or replace 107 | /// them entirely. 108 | /// 109 | /// True if you want to replace the existing query arguments. 110 | this.queryArgs = replace ? value : S.apply(this.queryArgs, value); 111 | 112 | return this; 113 | }, 114 | getQueryArg: function(key) { 115 | /// Returns the requested query argument. 116 | /// The name of the query argument to be returned. 117 | /// The value of the requested query argument. 118 | return this.queryArgs[key]; 119 | }, 120 | setQueryArg: function(key, value) { 121 | /// Sets a requested query argument. 122 | /// The name of the query argument to be set. 123 | /// The new value for the query argument. 124 | this.queryArgs[key] = value; 125 | 126 | return this; 127 | }, 128 | getPathSegments: function() { 129 | /// The path segments of the URI. 130 | return this.pathSegments; 131 | }, 132 | setPathSegments: function(value) { 133 | this.pathSegments = value; 134 | 135 | return this; 136 | }, 137 | getPathSegment: function(i) { 138 | return this.pathSegments.length > i 139 | ? this.pathSegments[i] 140 | : false; 141 | }, 142 | setPathSegment: function(i, value, predicate) { 143 | /* can clear the segment */ 144 | if (!value && !predicate) 145 | { 146 | this.pathSegments[i] = null; 147 | } 148 | /* merge object onto segment */ 149 | else if (typeof value === 'object') 150 | { 151 | this.pathSegments[i] = S.apply({}, value, this.pathSegments[i]); 152 | } 153 | /* merge values onto segment */ 154 | else 155 | { 156 | var segment = {}; 157 | 158 | if (value) segment['text'] = value; 159 | if (predicate) segment['predicate'] = predicate; 160 | 161 | this.pathSegments[i] = S.apply({}, segment, this.pathSegments[i]); 162 | } 163 | 164 | return this; 165 | }, 166 | getStartIndex: function() { 167 | return this.queryArgs[C.SDataUri.QueryArgNames.StartIndex] 168 | ? parseInt(this.queryArgs[C.SDataUri.QueryArgNames.StartIndex]) 169 | : -1; 170 | }, 171 | setStartIndex: function(value) { 172 | this.queryArgs[C.SDataUri.QueryArgNames.StartIndex] = value; 173 | 174 | return this; 175 | }, 176 | getCount: function() { 177 | return this.queryArgs[C.SDataUri.QueryArgNames.Count] 178 | ? parseInt(this.queryArgs[C.SDataUri.QueryArgNames.Count]) 179 | : -1; 180 | }, 181 | setCount: function(value) { 182 | this.queryArgs[C.SDataUri.QueryArgNames.Count] = value; 183 | 184 | return this; 185 | }, 186 | getIncludeContent: function() { 187 | var name = this.version.major >= 1 188 | ? C.SDataUri.QueryArgNames.IncludeContent 189 | : C.SDataUri.QueryArgNames.LegacyIncludeContent; 190 | 191 | return trueRE.test(this.queryArgs[name]); 192 | }, 193 | setIncludeContent: function(value) { 194 | var name = this.version.major >= 1 195 | ? C.SDataUri.QueryArgNames.IncludeContent 196 | : C.SDataUri.QueryArgNames.LegacyIncludeContent; 197 | 198 | this.queryArgs[name] = "" + value; 199 | 200 | return this; 201 | }, 202 | appendPath: function(value) { 203 | var segment = typeof value === 'string' ? {text: value} : value; 204 | 205 | this.pathSegments.push(segment); 206 | 207 | return this; 208 | }, 209 | toString: function(excludeQuery) { 210 | return this.build(excludeQuery); 211 | }, 212 | build: function(excludeQuery) { 213 | var url = []; 214 | 215 | url.push(this.getScheme() || C.SDataUri.Http); 216 | url.push(C.SDataUri.SchemeSuffix); 217 | url.push(C.SDataUri.PathSegmentPrefix); 218 | url.push(C.SDataUri.PathSegmentPrefix); 219 | url.push(this.getHost()); 220 | 221 | if (this.getPort() > 0) url.push(C.SDataUri.PortPrefix, this.getPort()); 222 | 223 | url.push(C.SDataUri.PathSegmentPrefix); 224 | 225 | var segments = this.getPathSegments(); 226 | var path = []; 227 | 228 | var server = this.getServer(); 229 | if (server && server.length > 0) 230 | path = path.concat(server.split('/')); 231 | 232 | for (var i = 0; i < segments.length; i++) 233 | { 234 | var segment = segments[i]; 235 | if (segment && segment['text']) 236 | { 237 | if (segment['predicate']) 238 | path.push(encodeURIComponent(segment['text'] + '(' + segment['predicate'] + ')')); 239 | else 240 | path.push(encodeURIComponent(segment['text'])); 241 | } 242 | } 243 | 244 | url.push(path.join(C.SDataUri.PathSegmentPrefix)); 245 | 246 | if (excludeQuery) return url.join(''); 247 | 248 | var queryArgs = this.getQueryArgs(); 249 | var query = []; 250 | 251 | for (var key in queryArgs) 252 | { 253 | query.push( 254 | encodeURIComponent(key) + 255 | C.SDataUri.QueryArgValuePrefix + 256 | encodeURIComponent(queryArgs[key]) 257 | ); 258 | } 259 | 260 | if (query.length > 0) 261 | { 262 | url.push(C.SDataUri.QueryPrefix); 263 | url.push(query.join(C.SDataUri.QueryArgPrefix)); 264 | } 265 | 266 | return url.join(''); 267 | }, 268 | getProduct: function() { 269 | return this.getPathSegment(C.SDataUri.ProductPathIndex); 270 | }, 271 | setProduct: function(val) { 272 | return this.setPathSegment(C.SDataUri.ProductPathIndex, val); 273 | }, 274 | getContract: function() { 275 | return this.getPathSegment(C.SDataUri.ContractTypePathIndex); 276 | }, 277 | setContract: function(val) { 278 | return this.setPathSegment(C.SDataUri.ContractTypePathIndex, val); 279 | }, 280 | getCompanyDataset: function() { 281 | return this.getPathSegment(C.SDataUri.CompanyDatasetPathIndex); 282 | }, 283 | setCompanyDataset: function(val) { 284 | return this.setPathSegment(C.SDataUri.CompanyDatasetPathIndex, val); 285 | }, 286 | getCollectionType: function() { 287 | return this.getPathSegment(C.SDataUri.CollectionTypePathIndex); 288 | }, 289 | setCollectionType: function(val) { 290 | return this.setPathSegment(C.SDataUri.CollectionTypePathIndex, val); 291 | }, 292 | getCollectionPredicate: function() { 293 | var segment = this.getPathSegment(C.SDataUri.CollectionTypePathIndex); 294 | return (segment && segment['predicate']) || false; 295 | }, 296 | setCollectionPredicate: function(value) { 297 | return this.setPathSegment(C.SDataUri.CollectionTypePathIndex, { 298 | predicate: value 299 | }); 300 | } 301 | }); 302 | 303 | Sage.apply(Sage.SData.Client.SDataUri, { 304 | Http: 'http', 305 | Https: 'https', 306 | PathSegmentPrefix: '/', 307 | PortPrefix: ':', 308 | QueryArgPrefix: '&', 309 | QueryArgValuePrefix: '=', 310 | QueryPrefix: '?', 311 | SchemeSuffix: ':', 312 | UnspecifiedPort: -1, 313 | UriName: 'uri', 314 | QueryArgNames: { 315 | Count: 'count', 316 | Exclude: 'exclude', 317 | Format: 'format', 318 | Include: 'include', 319 | IncludeContent: '_includeContent', 320 | LegacyIncludeContent: 'includeContent', 321 | IncludeSchema: 'includeSchema', 322 | Language: 'language', 323 | OrderBy: 'orderby', 324 | Precedence: 'precedence', 325 | ReturnDelta: 'returnDelta', 326 | Search: 'search', 327 | Select: 'select', 328 | StartIndex: 'startIndex', 329 | Thumbnail: 'thumbnail', 330 | TrackingID: 'trackingID', 331 | Where: 'where' 332 | }, 333 | ProductPathIndex: 0, 334 | ContractTypePathIndex: 1, 335 | CompanyDatasetPathIndex: 2, 336 | CollectionTypePathIndex: 3, 337 | ResourcePropertyIndex: 4, 338 | ServiceMethodSegment: '$service', 339 | TemplateSegment: '$template', 340 | SystemSegment: '$system', 341 | NamedQuerySegment: '$queries', 342 | BatchSegment: '$batch' 343 | }); 344 | })(); 345 | -------------------------------------------------------------------------------- /tests/SDataBatchRequestTests.js: -------------------------------------------------------------------------------- 1 | describe('SDataBatchRequest', function() { 2 | var service, 3 | xml = new XML.ObjTree(), 4 | withResponseContent = function(name) { 5 | spyOn(Sage.SData.Client.Ajax, 'request').andCallFake(function(options) { 6 | options.success.call(options.scope || this, { 7 | responseText: Resources.get(name) 8 | }); 9 | }); 10 | }; 11 | 12 | beforeEach(function() { 13 | service = new Sage.SData.Client.SDataService({ 14 | serverName: 'localhost', 15 | virtualDirectory: 'sdata', 16 | applicationName: 'aw', 17 | contractName: 'dynamic' 18 | }); 19 | }); 20 | 21 | it('can build url for batch', function() { 22 | var request = new Sage.SData.Client.SDataBatchRequest(service) 23 | .setResourceKind('employees'); 24 | 25 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees/%24batch?_includeContent=false"); 26 | }); 27 | 28 | it('can add requests to batch', function() { 29 | var batch = new Sage.SData.Client.SDataBatchRequest(service), 30 | employeeA = {}, 31 | employeeB = {}; 32 | 33 | batch.using(function() { 34 | new Sage.SData.Client.SDataSingleResourceRequest(service) 35 | .setResourceKind('employees') 36 | .setResourceSelector('1') 37 | .update(employeeA); 38 | 39 | new Sage.SData.Client.SDataSingleResourceRequest(service) 40 | .setResourceKind('employees') 41 | .setResourceSelector('2') 42 | .update(employeeB); 43 | }); 44 | 45 | expect(batch.items.length).toEqual(2); 46 | expect(batch.items[0].url).toEqual("http://localhost/sdata/aw/dynamic/-/employees(1)?_includeContent=false"); 47 | expect(batch.items[1].url).toEqual("http://localhost/sdata/aw/dynamic/-/employees(2)?_includeContent=false"); 48 | }); 49 | 50 | it('can format feed for batch request', function() { 51 | spyOn(Sage.SData.Client.Ajax, 'request'); 52 | 53 | var batch = new Sage.SData.Client.SDataBatchRequest(service) 54 | .setResourceKind('employees'); 55 | 56 | var employeeA = { 57 | '$name': 'Employee', 58 | '$etag': 'abc', 59 | 'Name': 'one' 60 | }, 61 | employeeB = { 62 | '$name': 'Employee', 63 | '$etag': 'def', 64 | 'Name': 'two' 65 | }; 66 | 67 | batch.using(function() { 68 | new Sage.SData.Client.SDataSingleResourceRequest(service) 69 | .setResourceKind('employees') 70 | .setResourceSelector('1') 71 | .update(employeeA); 72 | 73 | new Sage.SData.Client.SDataSingleResourceRequest(service) 74 | .setResourceKind('employees') 75 | .setResourceSelector('2') 76 | .update(employeeB); 77 | }); 78 | 79 | batch.commit(); 80 | 81 | (function(formatted) { 82 | expect(formatted).toHaveProperty('feed'); 83 | expect(formatted).toHaveProperty('feed.entry'); 84 | expect(formatted).toHaveProperty('feed.entry.length', 2); 85 | expect(formatted).toHaveProperty('feed.entry.0.id', 'http://localhost/sdata/aw/dynamic/-/employees(1)?_includeContent=false'); 86 | expect(formatted).toHaveProperty('feed.entry.1.id', 'http://localhost/sdata/aw/dynamic/-/employees(2)?_includeContent=false'); 87 | })(xml.parseXML(Sage.SData.Client.Ajax.request.mostRecentCall.args[0].body)); 88 | }); 89 | 90 | it('can commit batch request', function() { 91 | 92 | withResponseContent('TestBatch.xml'); 93 | 94 | var success = jasmine.createSpy(), 95 | failure = jasmine.createSpy(); 96 | 97 | var batch = new Sage.SData.Client.SDataBatchRequest(service), 98 | employeeA = {}, 99 | employeeB = {}; 100 | 101 | batch.using(function() { 102 | new Sage.SData.Client.SDataSingleResourceRequest(service) 103 | .setResourceKind('employees') 104 | .setResourceSelector('1') 105 | .update(employeeA); 106 | 107 | new Sage.SData.Client.SDataSingleResourceRequest(service) 108 | .setResourceKind('employees') 109 | .setResourceSelector('2') 110 | .update(employeeB); 111 | }); 112 | 113 | batch.commit({ 114 | success: success, 115 | failure: failure 116 | }); 117 | 118 | expect(success).toHaveBeenCalled(); 119 | expect(failure).not.toHaveBeenCalled(); 120 | }); 121 | }); -------------------------------------------------------------------------------- /tests/SDataResourceCollectionRequestTests.js: -------------------------------------------------------------------------------- 1 | describe('SDataResourceCollectionRequest', function() { 2 | var service, 3 | withResponseContent = function(name) { 4 | spyOn(Sage.SData.Client.Ajax, 'request').andCallFake(function(options) { 5 | options.success.call(options.scope || this, { 6 | responseText: Resources.get(name) 7 | }); 8 | }); 9 | }; 10 | 11 | beforeEach(function() { 12 | service = new Sage.SData.Client.SDataService({ 13 | serverName: 'localhost', 14 | virtualDirectory: 'sdata', 15 | applicationName: 'aw', 16 | contractName: 'dynamic' 17 | }); 18 | }); 19 | 20 | it('can build url with paging', function() { 21 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 22 | .setResourceKind('employees') 23 | .setStartIndex(1) 24 | .setCount(100); 25 | 26 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees?_includeContent=false&startIndex=1&count=100"); 27 | }); 28 | 29 | it('can build url with query', function() { 30 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 31 | .setResourceKind('employees') 32 | .setQueryArg('where', 'gender eq m'); 33 | 34 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees?_includeContent=false&where=gender%20eq%20m"); 35 | }); 36 | 37 | it('can read atom feed with non-prefixed properties', function() { 38 | 39 | withResponseContent('TestFeed.xml'); 40 | 41 | var success = jasmine.createSpy(), 42 | failure = jasmine.createSpy(); 43 | 44 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 45 | .setResourceKind('employees'); 46 | 47 | request.read({ 48 | success: success, 49 | failure: failure 50 | }); 51 | 52 | expect(success).toHaveBeenCalled(); 53 | expect(failure).not.toHaveBeenCalled(); 54 | 55 | (function(feed) { 56 | expect(feed).toExist(); 57 | expect(feed).toHaveProperty('$totalResults', 2); 58 | expect(feed).toHaveProperty('$resources'); 59 | expect(feed).toHaveProperty('$resources.length', 2); 60 | expect(feed).toHaveProperty('$resources.0.ContactId', '1209'); 61 | })(success.mostRecentCall.args[0]); 62 | }); 63 | 64 | it('can read explicitly namespaced atom feed', function() { 65 | 66 | withResponseContent('TestFeedExplicit.xml'); 67 | 68 | var success = jasmine.createSpy(), 69 | failure = jasmine.createSpy(); 70 | 71 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 72 | .setResourceKind('employees'); 73 | 74 | request.read({ 75 | success: success, 76 | failure: failure 77 | }); 78 | 79 | expect(success).toHaveBeenCalled(); 80 | expect(failure).not.toHaveBeenCalled(); 81 | 82 | (function(feed) { 83 | expect(feed).toExist(); 84 | expect(feed).toHaveProperty('$totalResults', 2); 85 | expect(feed).toHaveProperty('$resources'); 86 | expect(feed).toHaveProperty('$resources.length', 2); 87 | expect(feed).toHaveProperty('$resources.0.ContactId', '1209'); 88 | })(success.mostRecentCall.args[0]); 89 | }); 90 | 91 | it('can read atom feed with prefixed properties', function() { 92 | 93 | withResponseContent('TestFeedWithPrefix.xml'); 94 | 95 | var success = jasmine.createSpy(), 96 | failure = jasmine.createSpy(); 97 | 98 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 99 | .setResourceKind('employees'); 100 | 101 | request.read({ 102 | success: success, 103 | failure: failure 104 | }); 105 | 106 | expect(success).toHaveBeenCalled(); 107 | expect(failure).not.toHaveBeenCalled(); 108 | 109 | (function(feed) { 110 | expect(feed).toExist(); 111 | expect(feed).toHaveProperty('$resources'); 112 | expect(feed).toHaveProperty('$resources.length', 2); 113 | expect(feed).toHaveProperty('$resources.0.ContactId', '1209'); 114 | })(success.mostRecentCall.args[0]); 115 | }); 116 | 117 | it('can read json feed', function() { 118 | 119 | withResponseContent('TestFeed.json'); 120 | 121 | var success = jasmine.createSpy(), 122 | failure = jasmine.createSpy(); 123 | 124 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 125 | .setResourceKind('employees'); 126 | 127 | service.enableJson(); 128 | 129 | request.read({ 130 | success: success, 131 | failure: failure 132 | }); 133 | 134 | expect(success).toHaveBeenCalled(); 135 | expect(failure).not.toHaveBeenCalled(); 136 | 137 | (function(feed) { 138 | expect(feed).toExist(); 139 | expect(feed).toHaveProperty('$resources'); 140 | expect(feed).toHaveProperty('$resources.length', 2); 141 | expect(feed).toHaveProperty('$resources.0.ContactId', '1209'); 142 | })(success.mostRecentCall.args[0]); 143 | }); 144 | 145 | it('uses correct accept header for atom', function() { 146 | spyOn(Sage.SData.Client.Ajax, 'request'); 147 | 148 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 149 | .setResourceKind('employees'); 150 | 151 | request.read(); 152 | 153 | (function(options) { 154 | expect(options).toHaveProperty('headers'); 155 | expect(options).toHaveProperty('headers.Accept', 'application/atom+xml;type=feed,*/*'); 156 | })(Sage.SData.Client.Ajax.request.mostRecentCall.args[0]); 157 | }); 158 | 159 | it('uses correct accept header for json', function() { 160 | spyOn(Sage.SData.Client.Ajax, 'request'); 161 | 162 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 163 | .setResourceKind('employees'); 164 | 165 | service.enableJson(); 166 | 167 | request.read(); 168 | 169 | (function(options) { 170 | expect(options).toHaveProperty('headers'); 171 | expect(options).toHaveProperty('headers.Accept', 'application/json,*/*'); 172 | })(Sage.SData.Client.Ajax.request.mostRecentCall.args[0]); 173 | }); 174 | }); -------------------------------------------------------------------------------- /tests/SDataServiceOperationRequestTests.js: -------------------------------------------------------------------------------- 1 | describe('SDataServiceOperationRequest', function() { 2 | var service, 3 | xml = new XML.ObjTree(), 4 | withResponseContent = function(name) { 5 | spyOn(Sage.SData.Client.Ajax, 'request').andCallFake(function(options) { 6 | options.success.call(options.scope || this, { 7 | responseText: Resources.get(name) 8 | }); 9 | }); 10 | }; 11 | 12 | beforeEach(function() { 13 | service = new Sage.SData.Client.SDataService({ 14 | serverName: 'localhost', 15 | virtualDirectory: 'sdata', 16 | applicationName: 'aw', 17 | contractName: 'dynamic' 18 | }); 19 | }); 20 | 21 | it('can build url with service operation', function() { 22 | var request = new Sage.SData.Client.SDataServiceOperationRequest(service) 23 | .setResourceKind('tasks') 24 | .setOperationName('CompleteTask'); 25 | 26 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/-/tasks/%24service/CompleteTask?_includeContent=false"); 27 | }); 28 | 29 | it('can format atom entry for service operation call', function() { 30 | spyOn(Sage.SData.Client.Ajax, 'request'); 31 | 32 | var request = new Sage.SData.Client.SDataServiceOperationRequest(service) 33 | .setResourceKind('tasks') 34 | .setOperationName('CompleteTask'); 35 | 36 | var entry = { 37 | '$name': 'TaskComplete', 38 | 'request': { 39 | 'TaskId': 1 40 | } 41 | }; 42 | 43 | request.execute(entry); 44 | 45 | (function(formatted) { 46 | expect(formatted).toHaveProperty('entry'); 47 | expect(formatted).toHaveProperty('entry.sdata:payload'); 48 | expect(formatted).toHaveProperty('entry.sdata:payload.TaskComplete'); 49 | expect(formatted).toHaveProperty('entry.sdata:payload.TaskComplete.request'); 50 | expect(formatted).toHaveProperty('entry.sdata:payload.TaskComplete.request.TaskId', '1'); 51 | })(xml.parseXML(Sage.SData.Client.Ajax.request.mostRecentCall.args[0].body)); 52 | }); 53 | 54 | it('can execute service operation call', function() { 55 | 56 | withResponseContent('TestServiceResponse.xml'); 57 | 58 | var success = jasmine.createSpy(), 59 | failure = jasmine.createSpy(); 60 | 61 | var request = new Sage.SData.Client.SDataServiceOperationRequest(service) 62 | .setResourceKind('tasks') 63 | .setOperationName('CompleteTask'); 64 | 65 | var entry = { 66 | '$name': 'TaskComplete', 67 | 'request': { 68 | 'TaskId': 1 69 | } 70 | }; 71 | 72 | request.execute(entry, { 73 | success: success, 74 | failure: failure 75 | }); 76 | 77 | expect(success).toHaveBeenCalled(); 78 | expect(failure).not.toHaveBeenCalled(); 79 | 80 | (function(entry) { 81 | expect(entry).toExist(); 82 | expect(entry).toHaveProperty('response'); 83 | expect(entry).toHaveProperty('response.Result'); 84 | expect(entry).toHaveProperty('response.Result.Description', 'Confirm Meeting'); 85 | })(success.mostRecentCall.args[0]); 86 | }); 87 | }); 88 | -------------------------------------------------------------------------------- /tests/SDataServiceTests.js: -------------------------------------------------------------------------------- 1 | describe('SDataService', function() { 2 | it('can set available url properties via constructor', function() { 3 | var service = new Sage.SData.Client.SDataService({ 4 | protocol: 'https', 5 | serverName: 'localhost', 6 | port: 8080, 7 | virtualDirectory: 'sdata', 8 | applicationName: 'aw', 9 | contractName: 'dynamic', 10 | dataSet: 'alpha', 11 | includeContent: true 12 | }); 13 | 14 | expect(service.uri.build()).toEqual("https://localhost:8080/sdata/aw/dynamic/alpha?_includeContent=true"); 15 | }); 16 | 17 | it('can set available url properties via url passed to constructor', function() { 18 | var service = new Sage.SData.Client.SDataService("https://localhost:8080/sdata/aw/dynamic/alpha"); 19 | 20 | expect(service.uri.build()).toEqual("https://localhost:8080/sdata/aw/dynamic/alpha"); 21 | }); 22 | 23 | it('can set credentials via arguments passed to constructor', function() { 24 | var service = new Sage.SData.Client.SDataService("https://localhost:8080/sdata/aw/dynamic/alpha", "admin", "password"); 25 | 26 | expect(service.uri.build()).toEqual("https://localhost:8080/sdata/aw/dynamic/alpha"); 27 | expect(service.getUserName()).toEqual("admin"); 28 | expect(service.getPassword()).toEqual("password"); 29 | }); 30 | 31 | it('can mix and match url properties via object passed to constructor', function() { 32 | var service = new Sage.SData.Client.SDataService({ 33 | url: "https://localhost:8080/sdata/aw/dynamic/alpha", 34 | applicationName: "sample", 35 | dataSet: "omega", 36 | userName: "user", 37 | password: "password" 38 | }, "admin"); 39 | 40 | expect(service.uri.build()).toEqual("https://localhost:8080/sdata/sample/dynamic/omega"); 41 | expect(service.getUserName()).toEqual("admin"); 42 | expect(service.getPassword()).toEqual("password"); 43 | }); 44 | 45 | it('does provide data set segment to requests', function() { 46 | var service = new Sage.SData.Client.SDataService({ 47 | serverName: 'localhost', 48 | virtualDirectory: 'sdata', 49 | applicationName: 'aw', 50 | contractName: 'dynamic', 51 | dataSet: 'alpha' 52 | }); 53 | 54 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 55 | .setResourceKind('employees'); 56 | 57 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/alpha/employees?_includeContent=false") 58 | }); 59 | 60 | it('supports extension of the accept header', function() { 61 | spyOn(Sage.SData.Client.Ajax, 'request'); 62 | 63 | var service = new Sage.SData.Client.SDataService({ 64 | serverName: 'localhost', 65 | virtualDirectory: 'sdata', 66 | applicationName: 'aw', 67 | contractName: 'dynamic' 68 | }); 69 | 70 | var request = new Sage.SData.Client.SDataResourceCollectionRequest(service) 71 | .setResourceKind('employees') 72 | .setAccept('view=other'); 73 | 74 | request.read(); 75 | 76 | (function(options) { 77 | expect(options).toHaveProperty('headers'); 78 | expect(options).toHaveProperty('headers.Accept', 'application/atom+xml;type=feed;view=other,*/*;view=other'); 79 | })(Sage.SData.Client.Ajax.request.mostRecentCall.args[0]); 80 | }); 81 | }); -------------------------------------------------------------------------------- /tests/SDataSingleResourceRequestTests.js: -------------------------------------------------------------------------------- 1 | describe('SDataSingleResourceRequest', function() { 2 | var service, 3 | xml = new XML.ObjTree(), 4 | withResponseContent = function(name) { 5 | spyOn(Sage.SData.Client.Ajax, 'request').andCallFake(function(options) { 6 | options.success.call(options.scope || this, { 7 | responseText: Resources.get(name) 8 | }); 9 | }); 10 | }; 11 | 12 | beforeEach(function() { 13 | service = new Sage.SData.Client.SDataService({ 14 | serverName: 'localhost', 15 | virtualDirectory: 'sdata', 16 | applicationName: 'aw', 17 | contractName: 'dynamic' 18 | }); 19 | }); 20 | 21 | it('can build url with simple selector', function() { 22 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 23 | .setResourceKind('employees') 24 | .setResourceSelector('1'); 25 | 26 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees(1)?_includeContent=false"); 27 | }); 28 | 29 | it('can build url with complex selector', function() { 30 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 31 | .setResourceKind('employees') 32 | .setResourceSelector("id eq '1234'"); 33 | 34 | expect(request.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees(id%20eq%20'1234')?_includeContent=false"); 35 | }); 36 | 37 | it('can read atom entry with prefixed properties', function() { 38 | 39 | withResponseContent('TestEntryWithPrefix.xml'); 40 | 41 | var success = jasmine.createSpy(), 42 | failure = jasmine.createSpy(); 43 | 44 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 45 | .setResourceKind('employees') 46 | .setResourceSelector('1'); 47 | 48 | request.read({ 49 | success: success, 50 | failure: failure 51 | }); 52 | 53 | expect(success).toHaveBeenCalled(); 54 | expect(failure).not.toHaveBeenCalled(); 55 | 56 | (function(entry) { 57 | expect(entry).toExist(); 58 | expect(entry).toHaveProperty('NationalIdNumber'); 59 | expect(entry).toHaveProperty('DirectReports'); 60 | expect(entry).toHaveProperty('DirectReports.$resources'); 61 | expect(entry).toHaveProperty('DirectReports.$resources.length', 2); 62 | expect(entry).toHaveProperty('DirectReports.$resources.0.NationalIdNumber', '14417808'); 63 | })(success.mostRecentCall.args[0]); 64 | }); 65 | 66 | it('can read atom entry with mixed properties', function() { 67 | 68 | withResponseContent('TestEntryMixedPrefix.xml'); 69 | 70 | var success = jasmine.createSpy(), 71 | failure = jasmine.createSpy(); 72 | 73 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 74 | .setResourceKind('employees') 75 | .setResourceSelector('1'); 76 | 77 | request.read({ 78 | success: success, 79 | failure: failure 80 | }); 81 | 82 | expect(success).toHaveBeenCalled(); 83 | expect(failure).not.toHaveBeenCalled(); 84 | 85 | (function(entry) { 86 | expect(entry).toExist(); 87 | expect(entry).toHaveProperty('NationalIdNumber'); 88 | expect(entry).toHaveProperty('DirectReports'); 89 | expect(entry).toHaveProperty('DirectReports.$resources'); 90 | expect(entry).toHaveProperty('DirectReports.$resources.length', 2); 91 | expect(entry).toHaveProperty('DirectReports.$resources.0.NationalIdNumber', '14417808'); 92 | })(success.mostRecentCall.args[0]); 93 | }); 94 | 95 | it('can read atom entry with non-prefixed properties', function() { 96 | 97 | withResponseContent('TestEntry.xml'); 98 | 99 | var success = jasmine.createSpy(), 100 | failure = jasmine.createSpy(); 101 | 102 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 103 | .setResourceKind('employees') 104 | .setResourceSelector('1'); 105 | 106 | request.read({ 107 | success: success, 108 | failure: failure 109 | }); 110 | 111 | expect(success).toHaveBeenCalled(); 112 | expect(failure).not.toHaveBeenCalled(); 113 | 114 | (function(entry) { 115 | expect(entry).toExist(); 116 | expect(entry).toHaveProperty('NationalIdNumber'); 117 | expect(entry).toHaveProperty('DirectReports'); 118 | expect(entry).toHaveProperty('DirectReports.$resources'); 119 | expect(entry).toHaveProperty('DirectReports.$resources.length', 2); 120 | expect(entry).toHaveProperty('DirectReports.$resources.0.NationalIdNumber', '14417808'); 121 | })(success.mostRecentCall.args[0]); 122 | }); 123 | 124 | it('uses correct accept header for atom', function() { 125 | spyOn(Sage.SData.Client.Ajax, 'request'); 126 | 127 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 128 | .setResourceKind('employees') 129 | .setResourceSelector('1'); 130 | 131 | request.read(); 132 | 133 | (function(options) { 134 | expect(options).toHaveProperty('headers'); 135 | expect(options).toHaveProperty('headers.Accept', 'application/atom+xml;type=entry,*/*'); 136 | })(Sage.SData.Client.Ajax.request.mostRecentCall.args[0]); 137 | }); 138 | 139 | it('uses correct accept header for json', function() { 140 | spyOn(Sage.SData.Client.Ajax, 'request'); 141 | 142 | var request = new Sage.SData.Client.SDataSingleResourceRequest(service) 143 | .setResourceKind('employees') 144 | .setResourceSelector('1'); 145 | 146 | service.enableJson(); 147 | 148 | request.read(); 149 | 150 | (function(options) { 151 | expect(options).toHaveProperty('headers'); 152 | expect(options).toHaveProperty('headers.Accept', 'application/json,*/*'); 153 | })(Sage.SData.Client.Ajax.request.mostRecentCall.args[0]); 154 | }); 155 | }); 156 | -------------------------------------------------------------------------------- /tests/SDataUriTests.js: -------------------------------------------------------------------------------- 1 | describe('SDataUri', function() { 2 | it('can build url', function() { 3 | var uri = new Sage.SData.Client.SDataUri() 4 | .setHost('localhost') 5 | .setServer('sdata') 6 | .setProduct('aw') 7 | .setContract('dynamic') 8 | .setCompanyDataset('-') 9 | .setCollectionType('employees'); 10 | 11 | expect(uri.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees"); 12 | }); 13 | 14 | it('can build url with included content', function() { 15 | var uri = new Sage.SData.Client.SDataUri() 16 | .setHost('localhost') 17 | .setServer('sdata') 18 | .setProduct('aw') 19 | .setContract('dynamic') 20 | .setCompanyDataset('-') 21 | .setCollectionType('employees') 22 | .setIncludeContent(true); 23 | 24 | expect(uri.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees?_includeContent=true"); 25 | }); 26 | 27 | it('can append path segment', function() { 28 | var uri = new Sage.SData.Client.SDataUri() 29 | .setHost('localhost') 30 | .setServer('sdata') 31 | .setProduct('aw') 32 | .setContract('dynamic') 33 | .setCompanyDataset('-'); 34 | 35 | uri.appendPath('employees'); 36 | 37 | expect(uri.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees"); 38 | }); 39 | 40 | it('can set path segment predicate', function() { 41 | var uri = new Sage.SData.Client.SDataUri() 42 | .setHost('localhost') 43 | .setServer('sdata') 44 | .setProduct('aw') 45 | .setContract('dynamic') 46 | .setCompanyDataset('-') 47 | .setCollectionType('employees'); 48 | 49 | uri.setCollectionPredicate('1'); 50 | 51 | expect(uri.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees(1)"); 52 | }); 53 | 54 | it('can clone url', function() { 55 | var uri = new Sage.SData.Client.SDataUri() 56 | .setHost('localhost') 57 | .setServer('sdata') 58 | .setProduct('aw') 59 | .setContract('dynamic') 60 | .setCompanyDataset('-') 61 | .setCollectionType('employees'); 62 | 63 | var copy = new Sage.SData.Client.SDataUri(uri); 64 | 65 | expect(uri.build()).toEqual(copy.build()); 66 | }); 67 | 68 | it('does not modify original url when cloned', function() { 69 | var uri = new Sage.SData.Client.SDataUri() 70 | .setHost('localhost') 71 | .setServer('sdata') 72 | .setProduct('aw') 73 | .setContract('dynamic') 74 | .setCompanyDataset('-'); 75 | 76 | var copy = new Sage.SData.Client.SDataUri(uri); 77 | 78 | uri.appendPath('employees'); 79 | uri.setQueryArg('one', 'two'); 80 | 81 | copy.appendPath('tasks'); 82 | copy.setQueryArg('three', 'four'); 83 | 84 | expect(uri.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees?one=two"); 85 | expect(copy.build()).toEqual("http://localhost/sdata/aw/dynamic/-/tasks?three=four"); 86 | }); 87 | 88 | it('chooses correct include content argument for different versions', function() { 89 | var uriA = new Sage.SData.Client.SDataUri() 90 | .setHost('localhost') 91 | .setServer('sdata') 92 | .setProduct('aw') 93 | .setContract('dynamic') 94 | .setCompanyDataset('-') 95 | .setCollectionType('employees') 96 | .setVersion({major: 1, minor: 0}) 97 | .setIncludeContent(false); 98 | 99 | var uriB = new Sage.SData.Client.SDataUri() 100 | .setHost('localhost') 101 | .setServer('sdata') 102 | .setProduct('aw') 103 | .setContract('dynamic') 104 | .setCompanyDataset('-') 105 | .setCollectionType('employees') 106 | .setVersion({major: 0, minor: 9}) 107 | .setIncludeContent(false); 108 | 109 | expect(uriA.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees?_includeContent=false"); 110 | expect(uriB.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees?includeContent=false"); 111 | }); 112 | 113 | it('uses http when no scheme is specified', function() { 114 | var uri = new Sage.SData.Client.SDataUri() 115 | .setScheme(false) 116 | .setHost('localhost') 117 | .setServer('sdata') 118 | .setProduct('aw') 119 | .setContract('dynamic') 120 | .setCompanyDataset('-') 121 | .setCollectionType('employees'); 122 | 123 | expect(uri.build()).toEqual("http://localhost/sdata/aw/dynamic/-/employees"); 124 | }); 125 | 126 | it('can specify port', function() { 127 | var uri = new Sage.SData.Client.SDataUri() 128 | .setHost('localhost') 129 | .setPort(8080) 130 | .setServer('sdata') 131 | .setProduct('aw') 132 | .setContract('dynamic') 133 | .setCompanyDataset('-') 134 | .setCollectionType('employees'); 135 | 136 | expect(uri.build()).toEqual("http://localhost:8080/sdata/aw/dynamic/-/employees"); 137 | }); 138 | 139 | it('can set resource selector then resource kind', function() { 140 | var uri = new Sage.SData.Client.SDataUri() 141 | .setHost('localhost') 142 | .setPort(8080) 143 | .setServer('sdata') 144 | .setProduct('aw') 145 | .setContract('dynamic') 146 | .setCompanyDataset('-'); 147 | 148 | uri.setCollectionPredicate('1'); 149 | uri.setCollectionType('employees'); 150 | 151 | expect(uri.build()).toEqual("http://localhost:8080/sdata/aw/dynamic/-/employees(1)"); 152 | }); 153 | 154 | it('can set resource kind then resource selector', function() { 155 | var uri = new Sage.SData.Client.SDataUri() 156 | .setHost('localhost') 157 | .setPort(8080) 158 | .setServer('sdata') 159 | .setProduct('aw') 160 | .setContract('dynamic') 161 | .setCompanyDataset('-'); 162 | 163 | uri.setCollectionType('employees'); 164 | uri.setCollectionPredicate('1'); 165 | 166 | expect(uri.build()).toEqual("http://localhost:8080/sdata/aw/dynamic/-/employees(1)"); 167 | }); 168 | 169 | it('can clear path segment', function() { 170 | var uri = new Sage.SData.Client.SDataUri() 171 | .setHost('localhost') 172 | .setPort(8080) 173 | .setServer('sdata') 174 | .setProduct('aw') 175 | .setContract('dynamic') 176 | .setCompanyDataset('-') 177 | .setCollectionType('employees'); 178 | 179 | uri.setPathSegment(Sage.SData.Client.SDataUri.CollectionTypePathIndex, null); 180 | 181 | expect(uri.build()).toEqual("http://localhost:8080/sdata/aw/dynamic/-"); 182 | }); 183 | }); -------------------------------------------------------------------------------- /tests/TestBatch.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sage/SDataJavaScriptClientLib/70f236b2755c8642022a53b96668ad3e7065d8a3/tests/TestBatch.xml -------------------------------------------------------------------------------- /tests/TestEntry.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 7 | 8 | 9 | 10 | 11 | 0001-01-01T00:00:00+00:00 12 | 13 | 14 | Production Technician - WC60 15 | 14417807 16 | 1209 17 | adventure-works\guy1 18 | 16 19 | 1972-05-15T00:00:00+00:00 20 | False 21 | False 22 | 1996-07-31T00:00:00+00:00 23 | False 24 | 21 25 | 30 26 | True 27 | aae1d04a-c237-4974-b4d5-935247737718 28 | 2004-07-31T00:00:00+00:00 29 | 30 | 31 | Production Technician - WC61 32 | 14417808 33 | 34 | 35 | Production Technician - WC62 36 | 14417809 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tests/TestEntryMixedPrefix.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 8 | 9 | 10 | 11 | 12 | 0001-01-01T00:00:00+00:00 13 | 14 | 15 | Production Technician - WC60 16 | 14417807 17 | 1209 18 | adventure-works\guy1 19 | 16 20 | 1972-05-15T00:00:00+00:00 21 | False 22 | False 23 | 1996-07-31T00:00:00+00:00 24 | False 25 | 21 26 | 30 27 | True 28 | aae1d04a-c237-4974-b4d5-935247737718 29 | 2004-07-31T00:00:00+00:00 30 | 31 | 32 | Production Technician - WC61 33 | 14417808 34 | 35 | 36 | Production Technician - WC62 37 | 14417809 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/TestEntryWithPrefix.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 8 | 9 | 10 | 11 | 12 | 0001-01-01T00:00:00+00:00 13 | 14 | 15 | Production Technician - WC60 16 | 14417807 17 | 1209 18 | adventure-works\guy1 19 | 16 20 | 1972-05-15T00:00:00+00:00 21 | False 22 | False 23 | 1996-07-31T00:00:00+00:00 24 | False 25 | 21 26 | 30 27 | True 28 | aae1d04a-c237-4974-b4d5-935247737718 29 | 2004-07-31T00:00:00+00:00 30 | 31 | 32 | Production Technician - WC61 33 | 14417808 34 | 35 | 36 | Production Technician - WC62 37 | 14417809 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/TestFeed.json: -------------------------------------------------------------------------------- 1 | { 2 | "$totalResults": 2, 3 | "$startIndex": 1, 4 | "$itemsPerPage": 10, 5 | "$link": { 6 | }, 7 | "$resources": [ 8 | { 9 | "$descriptor": "14417807", 10 | "$etag": null, 11 | "$httpStatus": null, 12 | "$name": "Employee", 13 | "$key": null, 14 | "$url": null, 15 | "$uuid": null, 16 | "Title": "Production Technician - WC60", 17 | "NationalIdNumber": "14417807", 18 | "ContactId": "1209", 19 | "LoginId": "adventure-works\\guy1", 20 | "ManagerId": "16", 21 | "BirthDate": "1972-05-15T00:00:00+00:00", 22 | "MaritalStatus": "False", 23 | "Gender": "False", 24 | "HireDate": "1996-07-31T00:00:00+00:00", 25 | "Salariedflag": "False", 26 | "VacationHours": "21", 27 | "SickleaveHours": "30", 28 | "Currentflag": "True", 29 | "RowGuid": "aae1d04a-c237-4974-b4d5-935247737718", 30 | "ModifiedDate": "2004-07-31T00:00:00+00:00" 31 | }, 32 | { 33 | "$descriptor": "253022876", 34 | "$etag": null, 35 | "$httpStatus": null, 36 | "$name": "Employee", 37 | "$key": null, 38 | "$url": null, 39 | "$uuid": null, 40 | "Title": "Marketing Assistant", 41 | "NationalIdNumber": "253022876", 42 | "ContactId": "1030", 43 | "LoginId": "adventure-works\\kevin0", 44 | "ManagerId": "6", 45 | "BirthDate": "1977-06-03T00:00:00+00:00", 46 | "MaritalStatus": "False", 47 | "Gender": "False", 48 | "HireDate": "1997-02-26T00:00:00+00:00", 49 | "Salariedflag": "False", 50 | "VacationHours": "42", 51 | "SickleaveHours": "41", 52 | "Currentflag": "True", 53 | "RowGuid": "1b480240-95c0-410f-a717-eb29943c8886", 54 | "ModifiedDate": "2004-07-31T00:00:00+00:00" 55 | } 56 | ] 57 | } -------------------------------------------------------------------------------- /tests/TestFeed.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | aw 10 | 11 | 12 | 13 | 14 | Sage Dynamic Integration Adapter 15 | 16 | 17 | Provides a feed containing Employee details 18 | Sage | employees 19 | 2 20 | 1 21 | 10 22 | 23 | 24 | aw 25 | 26 | 27 | 28 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 29 | 30 | 31 | 32 | 33 | 0001-01-01T00:00:00+00:00 34 | 35 | 14417807 36 | 0001-01-01T00:00:00+00:00 37 | 38 | 39 | Production Technician - WC60 40 | 14417807 41 | 1209 42 | adventure-works\guy1 43 | 16 44 | 1972-05-15T00:00:00+00:00 45 | False 46 | False 47 | 1996-07-31T00:00:00+00:00 48 | False 49 | 21 50 | 30 51 | True 52 | aae1d04a-c237-4974-b4d5-935247737718 53 | 2004-07-31T00:00:00+00:00 54 | 55 | 56 | 57 | 58 | 59 | aw 60 | 61 | 62 | 63 | http://localhost:8001/sdata/aw/dynamic/-/employees(2) 64 | 65 | 66 | 67 | 68 | 0001-01-01T00:00:00+00:00 69 | 70 | 253022876 71 | 0001-01-01T00:00:00+00:00 72 | 73 | 74 | Marketing Assistant 75 | 253022876 76 | 1030 77 | adventure-works\kevin0 78 | 6 79 | 1977-06-03T00:00:00+00:00 80 | False 81 | False 82 | 1997-02-26T00:00:00+00:00 83 | False 84 | 42 85 | 41 86 | True 87 | 1b480240-95c0-410f-a717-eb29943c8886 88 | 2004-07-31T00:00:00+00:00 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /tests/TestFeedExplicit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | aw 5 | 6 | 7 | 8 | 9 | Sage Dynamic Integration Adapter 10 | 11 | 12 | Provides a feed containing Employee details 13 | Sage | employees 14 | 2 15 | 1 16 | 10 17 | 18 | 19 | aw 20 | 21 | 22 | 23 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 24 | 25 | 26 | 27 | 28 | 0001-01-01T00:00:00+00:00 29 | 30 | 14417807 31 | 0001-01-01T00:00:00+00:00 32 | 33 | 34 | Production Technician - WC60 35 | 14417807 36 | 1209 37 | adventure-works\guy1 38 | 16 39 | 1972-05-15T00:00:00+00:00 40 | False 41 | False 42 | 1996-07-31T00:00:00+00:00 43 | False 44 | 21 45 | 30 46 | True 47 | aae1d04a-c237-4974-b4d5-935247737718 48 | 2004-07-31T00:00:00+00:00 49 | 50 | 51 | 52 | 53 | 54 | aw 55 | 56 | 57 | 58 | http://localhost:8001/sdata/aw/dynamic/-/employees(2) 59 | 60 | 61 | 62 | 63 | 0001-01-01T00:00:00+00:00 64 | 65 | 253022876 66 | 0001-01-01T00:00:00+00:00 67 | 68 | 69 | Marketing Assistant 70 | 253022876 71 | 1030 72 | adventure-works\kevin0 73 | 6 74 | 1977-06-03T00:00:00+00:00 75 | False 76 | False 77 | 1997-02-26T00:00:00+00:00 78 | False 79 | 42 80 | 41 81 | True 82 | 1b480240-95c0-410f-a717-eb29943c8886 83 | 2004-07-31T00:00:00+00:00 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /tests/TestFeedSplit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | aw 9 | 10 | 11 | 12 | 13 | Sage Dynamic Integration Adapter 14 | 15 | 16 | Provides a feed containing Employee details 17 | Sage | employees 18 | 2 19 | 1 20 | 10 21 | 22 | 23 | aw 24 | 25 | 26 | 27 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 28 | 29 | 30 | 31 | 32 | 0001-01-01T00:00:00+00:00 33 | 34 | 35 | Production Technician - WC60 36 | 37 | 38 | 39 | 14417807 40 | 0001-01-01T00:00:00+00:00 41 | 42 | 43 | 14417807 44 | 1209 45 | adventure-works\guy1 46 | 16 47 | 1972-05-15T00:00:00+00:00 48 | False 49 | False 50 | 1996-07-31T00:00:00+00:00 51 | False 52 | 21 53 | 30 54 | True 55 | aae1d04a-c237-4974-b4d5-935247737718 56 | 2004-07-31T00:00:00+00:00 57 | 58 | 59 | 60 | 61 | 62 | aw 63 | 64 | 65 | 66 | http://localhost:8001/sdata/aw/dynamic/-/employees(2) 67 | 68 | 69 | 70 | 71 | 0001-01-01T00:00:00+00:00 72 | 73 | 74 | Marketing Assistant 75 | 76 | 77 | 78 | 253022876 79 | 0001-01-01T00:00:00+00:00 80 | 81 | 82 | 253022876 83 | 1030 84 | adventure-works\kevin0 85 | 6 86 | 1977-06-03T00:00:00+00:00 87 | False 88 | False 89 | 1997-02-26T00:00:00+00:00 90 | False 91 | 42 92 | 41 93 | True 94 | 1b480240-95c0-410f-a717-eb29943c8886 95 | 2004-07-31T00:00:00+00:00 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /tests/TestFeedWithPrefix.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | aw 10 | 11 | 12 | 13 | 14 | Sage Dynamic Integration Adapter 15 | 16 | 17 | Provides a feed containing Employee details 18 | Sage | employees 19 | 2 20 | 1 21 | 10 22 | 23 | 24 | aw 25 | 26 | 27 | 28 | http://localhost:8001/sdata/aw/dynamic/-/employees(1) 29 | 30 | 31 | 32 | 33 | 0001-01-01T00:00:00+00:00 34 | 35 | 14417807 36 | 0001-01-01T00:00:00+00:00 37 | 38 | 39 | Production Technician - WC60 40 | 14417807 41 | 1209 42 | adventure-works\guy1 43 | 16 44 | 1972-05-15T00:00:00+00:00 45 | False 46 | False 47 | 1996-07-31T00:00:00+00:00 48 | False 49 | 21 50 | 30 51 | True 52 | aae1d04a-c237-4974-b4d5-935247737718 53 | 2004-07-31T00:00:00+00:00 54 | 55 | 56 | 57 | 58 | 59 | aw 60 | 61 | 62 | 63 | http://localhost:8001/sdata/aw/dynamic/-/employees(2) 64 | 65 | 66 | 67 | 68 | 0001-01-01T00:00:00+00:00 69 | 70 | 253022876 71 | 0001-01-01T00:00:00+00:00 72 | 73 | 74 | Marketing Assistant 75 | 253022876 76 | 1030 77 | adventure-works\kevin0 78 | 6 79 | 1977-06-03T00:00:00+00:00 80 | False 81 | False 82 | 1997-02-26T00:00:00+00:00 83 | False 84 | 42 85 | 41 86 | True 87 | 1b480240-95c0-410f-a717-eb29943c8886 88 | 2004-07-31T00:00:00+00:00 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /tests/TestServiceResponse.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | aw 15 | 16 | 200 17 | 18 | 19 | 20 | 21 | 22 | 2011-03-16T19:41:09+00:00 23 | Confirm Meeting 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /tests/Utility.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var nameToPathCache = {}; 3 | var nameToPath = function(name) { 4 | if (typeof name !== 'string' || name === '.' || name === '') return []; // '', for compatibility 5 | if (nameToPathCache[name]) return nameToPathCache[name]; 6 | var parts = name.split('.'); 7 | var path = []; 8 | for (var i = 0; i < parts.length; i++) 9 | { 10 | var match = parts[i].match(/([a-zA-Z0-9_$]+)\[([^\]]+)\]/); 11 | if (match) 12 | { 13 | path.push(match[1]); 14 | if (/^\d+$/.test(match[2])) 15 | path.push(parseInt(match[2])); 16 | else 17 | path.push(match[2]); 18 | } 19 | else 20 | { 21 | path.push(parts[i]); 22 | } 23 | } 24 | return (nameToPathCache[name] = path.reverse()); 25 | }, 26 | getValue =function(o, name, defaultValue) { 27 | var path = nameToPath(name).slice(0); 28 | var current = o; 29 | while (current && path.length > 0) 30 | { 31 | var key = path.pop(); 32 | if (typeof current[key] !== 'undefined') 33 | current = current[key]; 34 | else 35 | return typeof defaultValue !== 'undefined' ? defaultValue : null; 36 | } 37 | return current; 38 | }; 39 | 40 | beforeEach(function() { 41 | this.addMatchers({ 42 | toHaveProperty: function(name, value) { 43 | var empty = {}, 44 | actual = getValue(this.actual, name, empty); 45 | return value === undefined 46 | ? actual !== empty 47 | : actual == value; 48 | }, 49 | toExist: function() { 50 | return !!this.actual; 51 | } 52 | }); 53 | }); 54 | })(); -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | SDataJavaScriptClientLib Test Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /tools/JSBuilder/JSB2FileFormat.txt: -------------------------------------------------------------------------------- 1 | JSB2 File Format is a JSON encoded configuration file for managing JS & CSS 2 | project builds. 3 | 4 | The top-level keys are: 5 | - projectName: String describing the project 6 | - deployDir: String specifying directory to create within the homeDir 7 | specified on the commandline 8 | - licenseText: String specifying the header of all .js and .css, use \n for 9 | newlines. 10 | - pkgs: An array of package descriptors 11 | - resources: An array of resource descriptors 12 | 13 | Package Descriptors: 14 | - name: String describing the package 15 | - file: String specifying the file to create 16 | - isDebug: Boolean describing whether to generate debug builds 17 | This configuration is currently UNUSED. Debug and compressed 18 | versions will ALWAYS be generated. 19 | - fileIncludes: An array of files descriptors which need to be included in this 20 | package. 21 | - pkgDeps: An array of the package descriptor file strings that this 22 | package depends on. The behavior of this configuration relies 23 | on the includeDeps configuration. 24 | - includeDeps: Boolean describing whether or not to include dependencies in the 25 | outputted file. Defaults to false. 26 | 27 | File Descriptors: 28 | - text: String describing the file to be included 29 | - path: String describing the directory of file to be included 30 | 31 | 32 | Resource Descriptors: 33 | - src: String describing the folder to move resources from 34 | - dest: String describing the folder to move resources to 35 | - filters: String to create a RegEx which specifies how to filter the 36 | files which are copied from src to dest. All .svn and hidden 37 | files will automatically be excluded. Note that all \'s must 38 | be encoded \\. 39 | 40 | Filter Examples: 41 | - ".*" A filter to copy all files 42 | - ".*[\\.js|\\.css]" A filter to copy all js and css files. 43 | 44 | -------------------------------------------------------------------------------- /tools/JSBuilder/JSBuilder2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sage/SDataJavaScriptClientLib/70f236b2755c8642022a53b96668ad3e7065d8a3/tools/JSBuilder/JSBuilder2.jar -------------------------------------------------------------------------------- /tools/JSBuilder/Readme.txt: -------------------------------------------------------------------------------- 1 | JSBuilder2 is a JavaScript and CSS project build tool. 2 | For additional information, see http://extjs.com/products/jsbuilder/ 3 | 4 | JSBuilder version 2.0.0 5 | 6 | Available arguments: 7 | --projectFile -p (REQUIRED) Location of a jsb2 project file 8 | --homeDir -d (REQUIRED) Home directory to build the project to 9 | --verbose -v (OPTIONAL) Output detailed information about what is being built 10 | --debugSuffix -s (OPTIONAL) Suffix to append to JS debug targets, defaults to 'debug' 11 | --help -h (OPTIONAL) Prints this help display. 12 | 13 | Example Usage: 14 | 15 | Windows 16 | java -jar JSBuilder2.jar --projectFile C:\Apps\www\ext3svn\ext.jsb2 --homeDir C:\Apps\www\deploy\ 17 | 18 | Linux and OS X 19 | java -jar JSBuilder2.jar --projectFile /home/aaron/www/trunk/ext.jsb2 --homeDir /home/aaron/www/deploy/ 20 | 21 | JSBuilder uses the following libraries 22 | -------------------------------------- 23 | YUI Compressor licensed under BSD License 24 | http://developer.yahoo.com/yui/compressor/ 25 | http://developer.yahoo.com/yui/license.html 26 | 27 | Mozilla's Rhino Project licensed under Mozilla's MPL 28 | http://www.mozilla.org/rhino/ 29 | http://www.mozilla.org/MPL/ 30 | 31 | JArgs licensed under BSD License 32 | http://jargs.sourceforge.net/ 33 | 34 | JSON in Java licensed under the JSON License 35 | http://www.json.org/java/index.html 36 | http://www.json.org/license.html 37 | --------------------------------------------------------------------------------