1 /**
  2  * @fileOverview
  3  * @author <a href="https://www.labkey.org">LabKey</a> (<a href="mailto:info@labkey.com">info@labkey.com</a>)
  4  * @license Copyright (c) 2008-2016 LabKey Corporation
  5  * <p/>
  6  * Licensed under the Apache License, Version 2.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at
  9  * <p/>
 10  * http://www.apache.org/licenses/LICENSE-2.0
 11  * <p/>
 12  * Unless required by applicable law or agreed to in writing, software
 13  * distributed under the License is distributed on an "AS IS" BASIS,
 14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing permissions and
 16  * limitations under the License.
 17  * <p/>
 18  */
 19 (function($) {
 20 
 21     /**
 22      * @description WebPart class to render a web part into an existing page element.  If you wish to render a Query web part, please
 23      * use the {@link LABKEY.QueryWebPart} class instead.
 24      * @class Web Part class to render a web part into an existing page element.  If you wish to render a Query web part, please
 25      * use the {@link LABKEY.QueryWebPart} class instead.
 26      *            <p>Additional Documentation:
 27      *              <ul>
 28      *                  <li><a href= "https://www.labkey.org/Documentation/wiki-page.view?name=webPartConfig">
 29      Web Part Configuration Properties</a></li>
 30      *                  <li><a href= "https://www.labkey.org/Documentation/wiki-page.view?name=webPartInventoryWikiSimple">
 31      List of LabKey Web Parts</a></li>
 32      *                  <li><a href="https://www.labkey.org/Documentation/wiki-page.view?name=javascriptTutorial">LabKey JavaScript API Tutorial</a> and
 33      *                      <a href="https://www.labkey.org/home/Study/demo/wiki-page.view?name=reagentRequest">Demo</a></li>
 34      *              </ul>
 35      *           </p>
 36      *
 37      * @constructor
 38      * @param {Object} config Describes configuration properties for this class.
 39      * @param {String} config.partName Name of the web part ("Wiki", "Lists", etc.), as listed in the
 40      "Add Web Part" drop-down menu on the portal page of the container.
 41      * @param {String} config.renderTo ID of the element in which the web part should be rendered.
 42      Typically this is a div.
 43      * @param {String} [config.frame] The type of frame to wrap around the web part's content. This can
 44      be any one of the following:
 45      <ul>
 46      <li><b>portal</b>: (Default) Includes the standard portal frame around the web part content
 47      <li><b>title</b>: Includes a lighter frame around the web part content (title with line underneath)
 48      <li><b>left-nav</b>: Similar to the title frame, but enforces a thinner width.
 49      <li><b>div</b>: Includes the content in a simple <div> tag. Use the config.bodyClass parameter to set a CSS class for the div.
 50      <li><b>dialog</b>: Includes the content in a frame that looks similar to a dialog box.
 51      <li><b>none</b>: Includes no frame around the web part content
 52      </ul>
 53      * @param {String} [config.bodyClass] The name of a CSS class available in the current page. This class name will be applied to the tag that
 54      contains the web part's body content.
 55      * @param {String} [config.title] Overrides the web part's default title.
 56      *                  Note that titles are not displayed when config.frame is set to "none".
 57      * @param {String} [config.titleHref] Overrides the hyperlink href around the web part's title.
 58      *                  Note that titles are not displayed when config.frame is set to "none".
 59      * @param {Object} [config.partConfig] Object containing name/value pairs that will be sent to the server as configuration
 60      *               	parameters for the web part. Each web part defines its own set of config parameters. See the
 61      * 					<a href= https://www.labkey.org/Documentation/wiki-page.view?name=webPartConfig>
 62      Web Part Configuration Properties</a> page for further information on these name/value pairs.
 63      * @param {boolean} [config.suppressRenderErrors] If true, no alert will appear if there is a problem rendering the QueryWebpart. This is most often encountered if page configuration changes between the time when a request was made and the content loads. Defaults to false.
 64      * @param {Function} [config.success] Callback function that will be executed after the web part content as been inserted into the page.
 65      * @param {Function} [config.failure] Callback function that will be executed if an error occurs. This function
 66      *                  should have two parameters: response and partConfig. The response parameter is the XMLHttpResponse
 67      *                  object, which can be used to determine the error code and obtain the error text if desired.
 68      *                  The partConfig parameter will contain all the parameters sent to the server.
 69      * @param {String} [config.containerPath] The container path in which this web part is defined. If not supplied,
 70      *                  the current container path will be used.
 71      * @param {Object} [config.scope] A scope object to use when calling the successCallback or errorCallback functions (defaults to this).
 72      * @example Example for a Wiki web part:<pre name="code" class="xml">
 73      <div id='wikiTestDiv'/>
 74      <script type="text/javascript">
 75      var wikiWebPartRenderer = new LABKEY.WebPart({
 76 		partName: 'Wiki',
 77 		renderTo: 'wikiTestDiv',
 78 		partConfig: {name: 'home'}
 79 		})
 80      wikiWebPartRenderer.render();
 81      </script>  </pre></code>
 82      * @example Example for a Report web part, from the Reagent Request <a href="https://www.labkey.org/Documentation/wiki-page.view?name=reagentRequestConfirmation">Tutorial</a> and <a href="https://www.labkey.org/home/Study/demo/wiki-page.view?name=Confirmation">Demo</a>: <pre name="code" class="xml">
 83      <div id='reportDiv'>Loading...</div>
 84      <script type="text/javascript">
 85      // This snippet draws a histogram of the current user's requests.
 86      // A partConfig parameter identifies the R report ('db:151')
 87      // used to draw the histogram.  partConfig also
 88      // supplies a filter ('query.UerID~eq') to ensure that
 89      // R uses data for only the current user.  Lastly, partConfig
 90      // provides R with an arbitrary URL parameter ('displayName')
 91      // to indicate the displayName of the user.
 92 
 93      var reportWebPartRenderer = new LABKEY.WebPart({
 94          partName: 'Report',
 95          renderTo: 'reportDiv',
 96          containerPath: '/home/Study/demo/guestaccess',
 97          frame: 'title',
 98          partConfig: {
 99                      title: 'Reagent Request Histogram',
100                      reportId: 'db:151',
101                      showSection: 'histogram',
102                      'query.UserID~eq' : LABKEY.Security.currentUser.id,
103                      displayName: LABKEY.Security.currentUser.displayName
104      }});
105      reportWebPartRenderer.render();
106      </script> </pre></code>
107      */
108     LABKEY.WebPart = function(config)
109     {
110         //private data
111         var _renderTo = config.renderTo;
112         var _partName = config.partName;
113         var _frame = config.frame;
114         var _bodyClass = config.bodyClass;
115         var _title = config.title;
116         var _titleHref = config.titleHref;
117         var _partConfig = config.partConfig;
118         var _errorCallback = LABKEY.Utils.getOnFailure(config);
119         var _success = LABKEY.Utils.getOnSuccess(config);
120         var _containerPath = config.containerPath;
121         var _scope = config.scope || this;
122         var _suppressRenderErrors = config.supressRenderErrors;
123         var _partUrl = config.partUrl || LABKEY.ActionURL.buildURL('project', 'getWebPart', _containerPath);
124 
125         //validate config
126         if (!_partName)
127         {
128             LABKEY.Utils.alert("Configuration Error", "You must supply the name of the desired web part in the partName config property.");
129             return;
130         }
131         if (!_renderTo)
132         {
133             LABKEY.Utils.alert("Configuration Error", "You must supply the name of the target element in the renderTo config property.");
134             return;
135         }
136 
137         // private methods:
138         var handleLoadError = function(response)
139         {
140             var msg = "Error getting the web part: ";
141             if (response.status == 0)
142             {
143                 return;
144             }
145             if(response.status >= 500 && response.status < 600)
146             {
147                 var json = LABKEY.Utils.decode(response.responseText);
148                 if(json)
149                     msg += json.exception;
150             }
151             else
152                 msg += response.statusText;
153 
154             LABKEY.Utils.alert("Error", msg);
155         };
156 
157         var renderPart = function(response, partConfig)
158         {
159             // beforeRender callback to allow for editing of the response
160             // if 'false' is returned then rendering will be stopped.
161             if (partConfig.params.beforeRender)
162             {
163                 var r = partConfig.params.beforeRender.call(_scope, response);
164                 if (r === false)
165                     return;
166                 else if (r)
167                     response = r;
168             }
169 
170             // render the part inside the target element
171             if (_renderTo)
172             {
173                 var targetElem = $('#' + _renderTo);
174                 if (targetElem.length > 0)
175                 {
176                     LABKEY.Utils.loadAjaxContent(response, targetElem, _success, _scope);
177                 }
178                 else
179                 {
180                     if (!_suppressRenderErrors)
181                         LABKEY.Utils.alert("Rendering Error", "The element '" + _renderTo + "' does not exist in the document!");
182                 }
183             }
184             else
185             {
186                 if (!_suppressRenderErrors)
187                     LABKEY.Utils.alert("Rendering Error", "The target element name was not set!");
188             }
189         };
190 
191         // public methods:
192         /** @scope LABKEY.WebPart.prototype */
193         return {
194             /**
195              * Renders the WebPart to the div element specified in the configuration settings.
196              * @returns A transaction id for the async request that can be used to cancel the request
197              * (see <a href="http://dev.sencha.com/deploy/dev/docs/?class=Ext.Ajax" target="_blank">Ext.Ajax.abort()</a>).
198              */
199             render : function()
200             {
201                 if (!_partConfig)
202                     _partConfig = {};
203 
204                 _partConfig["webpart.name"] = _partName;
205                 if (_frame)
206                     _partConfig["webpart.frame"] = _frame;
207                 if (_bodyClass)
208                     _partConfig["webpart.bodyClass"] = _bodyClass;
209                 if (_title)
210                     _partConfig["webpart.title"] = _title;
211                 if (_titleHref)
212                     _partConfig["webpart.titleHref"] = _titleHref;
213                 if (_partConfig.returnUrl) {
214                     _partConfig.returnUrl = encodeURI(_partConfig.returnUrl);
215                 }
216                 else if (_partConfig.returnURL) {
217                     if (LABKEY.experimental.strictReturnUrl)
218                         throw new Error("Use 'returnUrl' instead of 'returnURL'");
219                     _partConfig.returnUrl = encodeURI(_partConfig.returnURL);
220                 }
221 
222                 if (!_errorCallback)
223                     _errorCallback = handleLoadError;
224 
225                 // forward query string parameters (for Query web parts)
226                 var config = $.extend(true, {}, LABKEY.ActionURL.getParameters(), _partConfig);
227 
228                 // Ext uses a param called _dc to defeat caching, and it may be
229                 // on the URL if the Query web part has done a sort or filter
230                 // strip it if it's there so it's not included twice (Ext always appends one)
231                 delete config["_dc"];
232 
233                 return LABKEY.Ajax.request({
234                     url: _partUrl,
235                     success: renderPart,
236                     failure: _errorCallback,
237                     method: 'GET',
238                     params: config
239                 });
240             }
241         };
242     };
243 
244     /**
245      * This is a static method to generate a report webpart.  It is equivalent to LABKEY.WebPart with partName='Report'; however,
246      * it simplifies the configuration
247      * @param config The config object
248      * @param {String} config.renderTo The Id of the element in which the web part should be rendered.
249      * @param {String} [config.reportId] The Id of the report to load.  This can be used in place of schemaName/queryName/reportName
250      * @param {String} [config.schemaName] The name of the schema where the report is associated.
251      * @param {String} [config.queryName] The name of the query where the report is attached.
252      * @param {String} [config.reportName] The name of the report to be loaded.
253      * @param {String} [config.title] The title that will appear above the report webpart
254      * @param {Object} [config.webPartConfig] A optional config object used to create the LABKEY.WebPart.  Any config options supported by WebPart can be used here.
255      * @param {Object} [config.reportProperties] An optional config object with additional report-specific properties.  This is equal to partConfig from LABKEY.Webpart
256      * @return A LABKEY.WebPart instance
257      * @example
258      <div id='testDiv'/>
259      <div id='testDiv2'/>
260      <script type="text/javascript">
261      //a report can be loaded using its name, schema and query
262      var reportWebpart = LABKEY.WebPart.createReportWebpart({
263          schemaName: 'laboratory',
264          queryName: 'DNA_Oligos',
265          reportName: 'My Report',
266          renderTo: 'testDiv',
267          webPartConfig: {
268             title: 'Example Report',
269             suppressRenderErrors: true
270          },
271          reportProperties: {
272             'query.name~eq': 'Primer2'
273          }
274      });
275      reportWebpart.render();
276 
277      //the report can also be loaded using its Id
278      var reportWebpartUsingId = LABKEY.WebPart.createReportWebpart({
279          reportId: 'module:laboratory/schemas/laboratory/DNA_Oligos/Query.report.xml',
280          renderTo: 'testDiv2',
281          webPartConfig: {
282             title: 'Example Report',
283             suppressRenderErrors: true
284          },
285          reportProperties: {
286             'query.name~eq': 'Primer2'
287          }
288      }).render();
289      </script>  </pre></code>
290      */
291     LABKEY.WebPart.createReportWebpart = function(config)
292     {
293         var wpConfig = $.extend({}, config.webPartConfig);
294         wpConfig.partName = 'Report';
295 
296         // for convenience, support these wp properties in config
297         $.each(['renderTo', 'success', 'failure'], function(index, prop)
298         {
299             if (LABKEY.Utils.isDefined(config[prop]))
300             {
301                 wpConfig[prop] = config[prop];
302             }
303         });
304 
305         // then merge the partConfig options. we document specific Report-specific options for clarity to the user
306         wpConfig.partConfig = $.extend({}, config.reportProperties);
307         $.each(['reportId', 'reportName', 'schemaName', 'queryName', 'title'], function(index, prop)
308         {
309             if (LABKEY.Utils.isDefined(config[prop]))
310             {
311                 wpConfig.partConfig[prop] = config[prop];
312             }
313         });
314 
315         return new LABKEY.WebPart(wpConfig);
316     };
317 
318 })(jQuery);
319 
320