[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/autocomplete-sources/ -> autocomplete-sources-debug.js (source)

   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"]});


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1