UNPKG

asia-weex-vue-render4light

Version:

Web renderer for weex project written in Vue DSL.

341 lines (304 loc) 9.68 kB
/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* global lib, XMLHttpRequest */ /* deps: httpurl */ 'use strict' let utils import 'httpurl' import qs from 'query-string' let jsonpCnt = 0 const ERROR_STATE = -1 function _jsonp (config, callback, progressCallback) { const cbName = config.jsonpCallbackName || 'jsonp_' + (++jsonpCnt) let url let timeouttimer; if (!config.url) { console.error('[h5-render] config.url should be set in _jsonp for \'fetch\' API.') } global[cbName] = (function (cb) { if(timeouttimer){ clearTimeout(timeouttimer); timeouttimer = null; } return function (response) { callback({ status: 200, ok: true, statusText: 'OK', data: response }) delete global[cb] } })(cbName) const script = document.createElement('script') try { url = lib.httpurl(config.url) } catch (err) { console.error('[h5-render] invalid config.url in _jsonp for \'fetch\' API: ' + config.url) } url.params.callback = cbName script.type = 'text/javascript' script.src = url.toString() // script.onerror is not working on IE or safari. // but they are not considered here. script.onerror = (function (cb) { return function (err) { console.error('[h5-render] unexpected error in _jsonp for \'fetch\' API', err) callback({ status: ERROR_STATE, ok: false, statusText: '', data: '' }) delete global[cb] } })(cbName) const head = document.getElementsByTagName('head')[0] head.insertBefore(script, null) if (config.timeout) { timeouttimer = setTimeout(function () { script.onerror(); },config.timeout) } } function _xhr (config, callback, progressCallback) { const xhr = new XMLHttpRequest() xhr.responseType = config.type xhr.open(config.method, config.url, true) // cors cookie support if (config.withCredentials === true) { xhr.withCredentials = true } const headers = config.headers || {} for (const k in headers) { xhr.setRequestHeader(k, headers[k]) } xhr.onload = function (res) { callback({ status: xhr.status, ok: xhr.status >= 200 && xhr.status < 300, statusText: xhr.statusText, data: xhr.response, headers: xhr.getAllResponseHeaders().split('\n') .reduce(function (obj, headerStr) { const headerArr = headerStr.match(/(.+): (.+)/) if (headerArr) { obj[headerArr[1]] = headerArr[2] } return obj }, {}) }) } if (progressCallback) { xhr.onprogress = function (e) { progressCallback({ readyState: xhr.readyState, status: xhr.status, length: e.loaded, total: e.total, statusText: xhr.statusText, headers: xhr.getAllResponseHeaders().split('\n') .reduce(function (obj, headerStr) { const headerArr = headerStr.match(/(.+): (.+)/) if (headerArr) { obj[headerArr[1]] = headerArr[2] } return obj }, {}) }) } } xhr.onerror = function (err) { console.error('[h5-render] unexpected error in _xhr for \'fetch\' API', err) callback({ status: ERROR_STATE, ok: false, statusText: '', data: '' }) } xhr.timeout = config.timeout xhr.send(config.body || null) } const stream = { /** * sendHttp * @deprecated * Note: This API is deprecated. Please use stream.fetch instead. * send a http request through XHR. * @param {obj} params * - method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH', * - url: url requested * @param {string} callbackId */ sendHttp: function (param, callbackId) { if (typeof param === 'string') { try { param = JSON.parse(param) } catch (e) { return } } if (typeof param !== 'object' || !param.url) { return console.error( '[h5-render] invalid config or invalid config.url for sendHttp API') } const sender = this.sender const method = param.method || 'GET' const xhr = new XMLHttpRequest() xhr.open(method, param.url, true) xhr.onload = function () { sender.performCallback(callbackId, this.responseText) } xhr.onerror = function (error) { return console.error('[h5-render] unexpected error in sendHttp API', error) // sender.performCallback( // callbackId, // new Error('unexpected error in sendHttp API') // ) } xhr.send() }, /** * fetch * use stream.fetch to request for a json file, a plain text file or * a arraybuffer for a file stream. (You can use Blob and FileReader * API implemented by most modern browsers to read a arraybuffer.) * @param {object} options config options * - method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH' * - headers {obj} * - url {string} * - mode {string} 'cors' | 'no-cors' | 'same-origin' | 'navigate' * - withCredentials {boolean} * - body * - type {string} 'json' | 'jsonp' | 'text' * @param {string} callbackId * @param {string} progressCallbackId */ fetch: function (options, callbackId, progressCallbackId) { const DEFAULT_METHOD = 'GET' const DEFAULT_MODE = 'cors' const DEFAULT_TYPE = 'text' const methodOptions = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'PATCH'] const modeOptions = ['cors', 'no-cors', 'same-origin', 'navigate'] const typeOptions = ['text', 'json', 'jsonp', 'arraybuffer'] // const fallback = false // fallback from 'fetch' API to XHR. const sender = this.sender const config = utils.extend({}, options) // validate options.method if (typeof config.method === 'undefined') { config.method = DEFAULT_METHOD console.warn('[h5-render] options.method for \'fetch\' API has been set to ' + 'default value \'' + config.method + '\'') } else if (methodOptions.indexOf((config.method + '') .toUpperCase()) === -1) { return console.error('[h5-render] options.method \'' + config.method + '\' for \'fetch\' API should be one of ' + methodOptions + '.') } // validate options.url if (!config.url) { return console.error('[h5-render] options.url should be set for \'fetch\' API.') } // validate body content for method 'GET'. if (config.method.toUpperCase() === 'GET') { let body = config.body if (utils.isPlainObject(body)) { body = qs.stringify(body) } let url = config.url let hashIdx = url.indexOf('#') hashIdx <= -1 && (hashIdx = url.length) let hash = url.substr(hashIdx) if (hash && hash[0] === '#') { hash = hash.substr(1) } url = url.substring(0, hashIdx) if (body) { url += (config.url.indexOf('?') <= -1 ? '?' : '&') + body } url += '#' + hash config.url = url } // validate options.mode if (typeof config.mode === 'undefined') { config.mode = DEFAULT_MODE } else if (modeOptions.indexOf((config.mode + '').toLowerCase()) === -1) { return console.error('[h5-render] options.mode \'' + config.mode + '\' for \'fetch\' API should be one of ' + modeOptions + '.') } // validate options.type if (typeof config.type === 'undefined') { config.type = DEFAULT_TYPE console.warn('[h5-render] options.type for \'fetch\' API has been set to ' + 'default value \'' + config.type + '\'.') } else if (typeOptions.indexOf((config.type + '').toLowerCase()) === -1) { return console.error('[h5-render] options.type \'' + config.type + '\' for \'fetch\' API should be one of ' + typeOptions + '.') } // validate options.headers config.headers = config.headers || {} if (!utils.isPlainObject(config.headers)) { return console.error('[h5-render] options.headers should be a plain object') } // validate options.timeout config.timeout = parseInt(config.timeout, 10) || 2500 const _callArgs = [config, function (res) { sender.performCallback(callbackId, res) }] if (progressCallbackId) { _callArgs.push(function (res) { // Set 'keepAlive' to true for sending continuous callbacks sender.performCallback(progressCallbackId, res, true) }) } if (config.type === 'jsonp') { _jsonp.apply(this, _callArgs) } else { _xhr.apply(this, _callArgs) } } } const meta = { stream: [{ name: 'sendHttp', args: ['object', 'function'] }, { name: 'fetch', args: ['object', 'function', 'function'] }] } export default { init: function (Weex) { utils = Weex.utils Weex.registerApiModule('stream', stream, meta) } }