[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('autocomplete-sources', function (Y, NAME) { 9 10 /** 11 Mixes support for JSONP and YQL result sources into AutoCompleteBase. 12 13 @module autocomplete 14 @submodule autocomplete-sources 15 **/ 16 17 var ACBase = Y.AutoCompleteBase, 18 Lang = Y.Lang, 19 20 _SOURCE_SUCCESS = '_sourceSuccess', 21 22 MAX_RESULTS = 'maxResults', 23 REQUEST_TEMPLATE = 'requestTemplate', 24 RESULT_LIST_LOCATOR = 'resultListLocator'; 25 26 // Add prototype properties and methods to AutoCompleteBase. 27 Y.mix(ACBase.prototype, { 28 /** 29 Regular expression used to determine whether a String source is a YQL query. 30 31 @property _YQL_SOURCE_REGEX 32 @type RegExp 33 @protected 34 @for AutoCompleteBase 35 **/ 36 _YQL_SOURCE_REGEX: /^(?:select|set|use)\s+/i, 37 38 /** 39 Runs before AutoCompleteBase's `_createObjectSource()` method and augments 40 it to support additional object-based source types. 41 42 @method _beforeCreateObjectSource 43 @param {String} source 44 @protected 45 @for AutoCompleteBase 46 **/ 47 _beforeCreateObjectSource: function (source) { 48 // If the object is a <select> node, use the options as the result 49 // source. 50 if (source instanceof Y.Node && 51 source.get('nodeName').toLowerCase() === 'select') { 52 53 return this._createSelectSource(source); 54 } 55 56 // If the object is a JSONPRequest instance, try to use it as a JSONP 57 // source. 58 if (Y.JSONPRequest && source instanceof Y.JSONPRequest) { 59 return this._createJSONPSource(source); 60 } 61 62 // Fall back to a basic object source. 63 return this._createObjectSource(source); 64 }, 65 66 /** 67 Creates a DataSource-like object that uses `Y.io` as a source. See the 68 `source` attribute for more details. 69 70 @method _createIOSource 71 @param {String} source URL. 72 @return {Object} DataSource-like object. 73 @protected 74 @for AutoCompleteBase 75 **/ 76 _createIOSource: function (source) { 77 var ioSource = {type: 'io'}, 78 that = this, 79 ioRequest, lastRequest, loading; 80 81 // Private internal _sendRequest method that will be assigned to 82 // ioSource.sendRequest once io-base and json-parse are available. 83 function _sendRequest(request) { 84 var cacheKey = request.request; 85 86 // Return immediately on a cached response. 87 if (that._cache && cacheKey in that._cache) { 88 that[_SOURCE_SUCCESS](that._cache[cacheKey], request); 89 return; 90 } 91 92 // Cancel any outstanding requests. 93 if (ioRequest && ioRequest.isInProgress()) { 94 ioRequest.abort(); 95 } 96 97 ioRequest = Y.io(that._getXHRUrl(source, request), { 98 on: { 99 success: function (tid, response) { 100 var data; 101 102 try { 103 data = Y.JSON.parse(response.responseText); 104 } catch (ex) { 105 Y.error('JSON parse error', ex); 106 } 107 108 if (data) { 109 that._cache && (that._cache[cacheKey] = data); 110 that[_SOURCE_SUCCESS](data, request); 111 } 112 } 113 } 114 }); 115 } 116 117 ioSource.sendRequest = function (request) { 118 // Keep track of the most recent request in case there are multiple 119 // requests while we're waiting for the IO module to load. Only the 120 // most recent request will be sent. 121 lastRequest = request; 122 123 if (loading) { return; } 124 125 loading = true; 126 127 // Lazy-load the io-base and json-parse modules if necessary, 128 // then overwrite the sendRequest method to bypass this check in 129 // the future. 130 Y.use('io-base', 'json-parse', function () { 131 ioSource.sendRequest = _sendRequest; 132 _sendRequest(lastRequest); 133 }); 134 }; 135 136 return ioSource; 137 }, 138 139 /** 140 Creates a DataSource-like object that uses the specified JSONPRequest 141 instance as a source. See the `source` attribute for more details. 142 143 @method _createJSONPSource 144 @param {JSONPRequest|String} source URL string or JSONPRequest instance. 145 @return {Object} DataSource-like object. 146 @protected 147 @for AutoCompleteBase 148 **/ 149 _createJSONPSource: function (source) { 150 var jsonpSource = {type: 'jsonp'}, 151 that = this, 152 lastRequest, loading; 153 154 function _sendRequest(request) { 155 var cacheKey = request.request, 156 query = request.query; 157 158 if (that._cache && cacheKey in that._cache) { 159 that[_SOURCE_SUCCESS](that._cache[cacheKey], request); 160 return; 161 } 162 163 // Hack alert: JSONPRequest currently doesn't support 164 // per-request callbacks, so we're reaching into the protected 165 // _config object to make it happen. 166 // 167 // This limitation is mentioned in the following JSONP 168 // enhancement ticket: 169 // 170 // http://yuilibrary.com/projects/yui3/ticket/2529371 171 source._config.on.success = function (data) { 172 that._cache && (that._cache[cacheKey] = data); 173 that[_SOURCE_SUCCESS](data, request); 174 }; 175 176 source.send(query); 177 } 178 179 jsonpSource.sendRequest = function (request) { 180 // Keep track of the most recent request in case there are multiple 181 // requests while we're waiting for the JSONP module to load. Only 182 // the most recent request will be sent. 183 lastRequest = request; 184 185 if (loading) { return; } 186 187 loading = true; 188 189 // Lazy-load the JSONP module if necessary, then overwrite the 190 // sendRequest method to bypass this check in the future. 191 Y.use('jsonp', function () { 192 // Turn the source into a JSONPRequest instance if it isn't 193 // one already. 194 if (!(source instanceof Y.JSONPRequest)) { 195 source = new Y.JSONPRequest(source, { 196 format: Y.bind(that._jsonpFormatter, that) 197 }); 198 } 199 200 jsonpSource.sendRequest = _sendRequest; 201 _sendRequest(lastRequest); 202 }); 203 }; 204 205 return jsonpSource; 206 }, 207 208 /** 209 Creates a DataSource-like object that uses the specified `<select>` node as 210 a source. 211 212 @method _createSelectSource 213 @param {Node} source YUI Node instance wrapping a `<select>` node. 214 @return {Object} DataSource-like object. 215 @protected 216 @for AutoCompleteBase 217 **/ 218 _createSelectSource: function (source) { 219 var that = this; 220 221 return { 222 type: 'select', 223 sendRequest: function (request) { 224 var options = []; 225 226 source.get('options').each(function (option) { 227 options.push({ 228 html : option.get('innerHTML'), 229 index : option.get('index'), 230 node : option, 231 selected: option.get('selected'), 232 text : option.get('text'), 233 value : option.get('value') 234 }); 235 }); 236 237 that[_SOURCE_SUCCESS](options, request); 238 } 239 }; 240 }, 241 242 /** 243 Creates a DataSource-like object that calls the specified URL or executes 244 the specified YQL query for results. If the string starts with "select ", 245 "use ", or "set " (case-insensitive), it's assumed to be a YQL query; 246 otherwise, it's assumed to be a URL (which may be absolute or relative). 247 URLs containing a "{callback}" placeholder are assumed to be JSONP URLs; all 248 others will use XHR. See the `source` attribute for more details. 249 250 @method _createStringSource 251 @param {String} source URL or YQL query. 252 @return {Object} DataSource-like object. 253 @protected 254 @for AutoCompleteBase 255 **/ 256 _createStringSource: function (source) { 257 if (this._YQL_SOURCE_REGEX.test(source)) { 258 // Looks like a YQL query. 259 return this._createYQLSource(source); 260 } else if (source.indexOf('{callback}') !== -1) { 261 // Contains a {callback} param and isn't a YQL query, so it must be 262 // JSONP. 263 return this._createJSONPSource(source); 264 } else { 265 // Not a YQL query or JSONP, so we'll assume it's an XHR URL. 266 return this._createIOSource(source); 267 } 268 }, 269 270 /** 271 Creates a DataSource-like object that uses the specified YQL query string to 272 create a YQL-based source. See the `source` attribute for details. If no 273 `resultListLocator` is defined, this method will set a best-guess locator 274 that might work for many typical YQL queries. 275 276 @method _createYQLSource 277 @param {String} source YQL query. 278 @return {Object} DataSource-like object. 279 @protected 280 @for AutoCompleteBase 281 **/ 282 _createYQLSource: function (source) { 283 var that = this, 284 yqlSource = {type: 'yql'}, 285 lastRequest, loading, yqlRequest; 286 287 if (!that.get(RESULT_LIST_LOCATOR)) { 288 that.set(RESULT_LIST_LOCATOR, that._defaultYQLLocator); 289 } 290 291 function _sendRequest(request) { 292 var query = request.query, 293 env = that.get('yqlEnv'), 294 maxResults = that.get(MAX_RESULTS), 295 callback, opts, yqlQuery; 296 297 yqlQuery = Lang.sub(source, { 298 maxResults: maxResults > 0 ? maxResults : 1000, 299 request : request.request, 300 query : query 301 }); 302 303 if (that._cache && yqlQuery in that._cache) { 304 that[_SOURCE_SUCCESS](that._cache[yqlQuery], request); 305 return; 306 } 307 308 callback = function (data) { 309 that._cache && (that._cache[yqlQuery] = data); 310 that[_SOURCE_SUCCESS](data, request); 311 }; 312 313 opts = {proto: that.get('yqlProtocol')}; 314 315 // Only create a new YQLRequest instance if this is the 316 // first request. For subsequent requests, we'll reuse the 317 // original instance. 318 if (yqlRequest) { 319 yqlRequest._callback = callback; 320 yqlRequest._opts = opts; 321 yqlRequest._params.q = yqlQuery; 322 323 if (env) { 324 yqlRequest._params.env = env; 325 } 326 } else { 327 yqlRequest = new Y.YQLRequest(yqlQuery, { 328 on: {success: callback}, 329 allowCache: false // temp workaround until JSONP has per-URL callback proxies 330 }, env ? {env: env} : null, opts); 331 } 332 333 yqlRequest.send(); 334 } 335 336 yqlSource.sendRequest = function (request) { 337 // Keep track of the most recent request in case there are multiple 338 // requests while we're waiting for the YQL module to load. Only the 339 // most recent request will be sent. 340 lastRequest = request; 341 342 if (!loading) { 343 // Lazy-load the YQL module if necessary, then overwrite the 344 // sendRequest method to bypass this check in the future. 345 loading = true; 346 347 Y.use('yql', function () { 348 yqlSource.sendRequest = _sendRequest; 349 _sendRequest(lastRequest); 350 }); 351 } 352 }; 353 354 return yqlSource; 355 }, 356 357 /** 358 Default resultListLocator used when a string-based YQL source is set and the 359 implementer hasn't already specified one. 360 361 @method _defaultYQLLocator 362 @param {Object} response YQL response object. 363 @return {Array} 364 @protected 365 @for AutoCompleteBase 366 **/ 367 _defaultYQLLocator: function (response) { 368 var results = response && response.query && response.query.results, 369 values; 370 371 if (results && Lang.isObject(results)) { 372 // If there's only a single value on YQL's results object, that 373 // value almost certainly contains the array of results we want. If 374 // there are 0 or 2+ values, then the values themselves are most 375 // likely the results we want. 376 values = Y.Object.values(results) || []; 377 results = values.length === 1 ? values[0] : values; 378 379 if (!Lang.isArray(results)) { 380 results = [results]; 381 } 382 } else { 383 results = []; 384 } 385 386 return results; 387 }, 388 389 /** 390 Returns a formatted XHR URL based on the specified base _url_, _query_, and 391 the current _requestTemplate_ if any. 392 393 @method _getXHRUrl 394 @param {String} url Base URL. 395 @param {Object} request Request object containing `query` and `request` 396 properties. 397 @return {String} Formatted URL. 398 @protected 399 @for AutoCompleteBase 400 **/ 401 _getXHRUrl: function (url, request) { 402 var maxResults = this.get(MAX_RESULTS); 403 404 if (request.query !== request.request) { 405 // Append the request template to the URL. 406 url += request.request; 407 } 408 409 return Lang.sub(url, { 410 maxResults: maxResults > 0 ? maxResults : 1000, 411 query : encodeURIComponent(request.query) 412 }); 413 }, 414 415 /** 416 URL formatter passed to `JSONPRequest` instances. 417 418 @method _jsonpFormatter 419 @param {String} url 420 @param {String} proxy 421 @param {String} query 422 @return {String} Formatted URL 423 @protected 424 @for AutoCompleteBase 425 **/ 426 _jsonpFormatter: function (url, proxy, query) { 427 var maxResults = this.get(MAX_RESULTS), 428 requestTemplate = this.get(REQUEST_TEMPLATE); 429 430 if (requestTemplate) { 431 url += requestTemplate(query); 432 } 433 434 return Lang.sub(url, { 435 callback : proxy, 436 maxResults: maxResults > 0 ? maxResults : 1000, 437 query : encodeURIComponent(query) 438 }); 439 } 440 }); 441 442 // Add attributes to AutoCompleteBase. 443 Y.mix(ACBase.ATTRS, { 444 /** 445 YQL environment file URL to load when the `source` is set to a YQL query. 446 Set this to `null` to use the default Open Data Tables environment file 447 (http://datatables.org/alltables.env). 448 449 @attribute yqlEnv 450 @type String 451 @default null 452 @for AutoCompleteBase 453 **/ 454 yqlEnv: { 455 value: null 456 }, 457 458 /** 459 URL protocol to use when the `source` is set to a YQL query. 460 461 @attribute yqlProtocol 462 @type String 463 @default 'http' 464 @for AutoCompleteBase 465 **/ 466 yqlProtocol: { 467 value: 'http' 468 } 469 }); 470 471 // Tell AutoCompleteBase about the new source types it can now support. 472 Y.mix(ACBase.SOURCE_TYPES, { 473 io : '_createIOSource', 474 jsonp : '_createJSONPSource', 475 object: '_beforeCreateObjectSource', // Run our version before the base version. 476 select: '_createSelectSource', 477 string: '_createStringSource', 478 yql : '_createYQLSource' 479 }, true); 480 481 482 }, '3.17.2', {"optional": ["io-base", "json-parse", "jsonp", "yql"], "requires": ["autocomplete-base"]});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |