1<!--
2Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
3This code may only be used under the BSD style license found at https://polymer.github.io/LICENSE.txt
4The complete set of authors may be found at https://polymer.github.io/AUTHORS.txt
5The complete set of contributors may be found at https://polymer.github.io/CONTRIBUTORS.txt
6Code distributed by Google as part of the polymer project is also
7subject to an additional IP rights grant found at https://polymer.github.io/PATENTS.txt
8-->
9
10<link rel="import" href="../polymer/polymer.html">
11<link rel="import" href="google-js-api.html">
12
13<!--
14Element for loading a specific client Google API with the JavaScript client library.
15
16For loading `gapi.client` libraries
17
18##### Example
19
20    <google-client-loader id="shortener"
21      name="urlshortener"
22      version="v1"></google-client-loader>
23
24    <script>
25      var shortener = document.getElementById('shortener');
26      shortener.addEventListener('google-api-load', function(event) {
27        var request = shortener.api.url.get({
28           shortUrl: 'http://goo.gl/fbsS'
29        });
30        request.execute(function(resp) {
31          console.log(resp);
32        });
33      });
34    </script>
35
36@demo
37-->
38
39<script>
40  (function() {
41    'use strict';
42
43    // Stores whether the API client is done loading.
44    var _clientLoaded = false;
45
46    // Loaders and loading statuses for all APIs, indexed by API name.
47    // This helps prevent multiple loading requests being fired at the same time
48    // by multiple google-api-loader elements.
49    var _statuses = {};
50    var _loaders = {};
51
52    Polymer({
53
54      is: 'google-client-loader',
55
56      /**
57       * Fired when the requested API is loaded. Override this name
58       * by setting `successEventName`.
59       * @event google-api-load
60       */
61
62      /**
63       * Fired if an error occurs while loading the requested API. Override this name
64       * by setting `errorEventName`.
65       * @event google-api-load-error
66       */
67
68      properties: {
69        /**
70         * Name of the API to load, e.g. 'urlshortener'.
71         *
72         * You can find the full list of APIs on the
73         * <a href="https://developers.google.com/apis-explorer"> Google APIs
74         * Explorer</a>.
75         */
76        name: String,
77
78        /**
79         * Version of the API to load, e.g. 'v1'.
80         */
81        version: String,
82
83        /**
84         * App Engine application ID for loading a Google Cloud Endpoints API.
85         */
86        appId: String,
87
88        /**
89         * Root URL where to load the API from, e.g. 'http://host/apis'.
90         * For App Engine dev server this would be something like:
91         * 'http://localhost:8080/_ah/api'.
92         * Overrides 'appId' if both are specified.
93         */
94        apiRoot: String,
95
96        /**
97         * Name of the event fired when API library is loaded.
98         */
99        successEventName: {
100          type: String,
101          value: 'google-api-load'
102        },
103
104        /**
105         * Name of the event fired when there is an error loading the library.
106         */
107        errorEventName: {
108          type: String,
109          value: 'google-api-load-error'
110        }
111      },
112
113      hostAttributes: {
114        hidden: true // remove from rendering tree.
115      },
116
117      // Used to fix events potentially being fired multiple times by
118      // iron-jsonp-library.
119      _waiting: false,
120
121      /**
122       * Returns the loaded API.
123       */
124      get api() {
125        if (window.gapi && window.gapi.client &&
126            window.gapi.client[this.name]) {
127          return window.gapi.client[this.name];
128        } else {
129          return undefined;
130        }
131      },
132
133      /**
134       * Wrapper for `gapi.auth`.
135       */
136      get auth() {
137        return gapi.auth;
138      },
139
140      ready: function() {
141        this._loader = document.createElement('google-js-api');
142        this.listen(this._loader, 'js-api-load', '_loadClient');
143      },
144
145      detached: function() {
146        this.unlisten(this._loader, 'js-api-load', '_loadClient');
147      },
148
149      _loadClient: function() {
150        gapi.load('client', this._doneLoadingClient.bind(this));
151      },
152
153      _handleLoadResponse: function(response) {
154        if (response && response.error) {
155          _statuses[this.name] = 'error';
156          this._fireError(response);
157        } else {
158          _statuses[this.name] = 'loaded';
159          this._fireSuccess();
160        }
161      },
162
163      _fireSuccess: function() {
164        this.fire(this.successEventName,
165            { 'name': this.name, 'version': this.version });
166      },
167
168      _fireError: function(response) {
169        if (response && response.error) {
170          this.fire(this.errorEventName, {
171            'name': this.name,
172            'version': this.version,
173            'error': response.error });
174        } else {
175          this.fire(this.errorEventName, {
176            'name': this.name,
177            'version': this.version });
178        }
179      },
180
181      _doneLoadingClient: function() {
182        _clientLoaded = true;
183        // Fix for API client load event being fired multiple times by
184        // iron-jsonp-library.
185        if (!this._waiting) {
186          this._loadApi();
187        }
188      },
189
190      _createSelfRemovingListener: function(eventName) {
191        var handler = function () {
192          _loaders[this.name].removeEventListener(eventName, handler);
193          this._loadApi();
194        }.bind(this);
195
196        return handler;
197      },
198
199      _loadApi: function() {
200        if (_clientLoaded && this.name && this.version) {
201          this._waiting = false;
202          // Is this API already loaded?
203          if (_statuses[this.name] == 'loaded') {
204            this._fireSuccess();
205          // Is a different google-api-loader already loading this API?
206          } else if (_statuses[this.name] == 'loading') {
207            this._waiting = true;
208            _loaders[this.name].addEventListener(this.successEventName,
209                this._createSelfRemovingListener(this.successEventName));
210            _loaders[this.name].addEventListener(this.errorEventName,
211                this._createSelfRemovingListener(this.errorEventName));
212          // Did we get an error when we tried to load this API before?
213          } else if (_statuses[this.name] == 'error') {
214            this._fireError(null);
215          // Otherwise, looks like we're loading a new API.
216          } else {
217            var root;
218            if (this.apiRoot) {
219              root = this.apiRoot;
220            } else if (this.appId) {
221              root = 'https://' + this.appId + '.appspot.com/_ah/api';
222            }
223            _statuses[this.name] = 'loading';
224            _loaders[this.name] = this;
225            gapi.client.load(this.name, this.version,
226                this._handleLoadResponse.bind(this), root);
227          }
228        }
229      }
230    });
231  })();
232</script>
233