Skip to content

Commit

Permalink
Merge pull request #14 from ianwith/dev
Browse files Browse the repository at this point in the history
Updating v0.2.0
  • Loading branch information
ianwith authored Feb 8, 2018
2 parents bd07423 + 23917d0 commit 0aa6c88
Show file tree
Hide file tree
Showing 18 changed files with 385 additions and 44 deletions.
84 changes: 58 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,43 +20,45 @@ $ npm install rexxar-web --save

## 使用

### getRexxarWidget
### widgetMessenger

`widgetMessenger` 是一个消息组装器,分段传入参数构成消息体

```js
import { getRexxarWidget } from 'rexxar-web';
let messenger = widgetMessenger('douban', 'rexxar-container')('widget/alert_dialog')
```

const RexxarWidget = getRexxarWidget({
scheme: 'douban',
host: 'rexxar-container'
});
### callbackListener

class Title extends RexxarWidget {
constructor(title) {
super('title');
this.title = title;
}
show() {
super.call({ title: this.title });
}
}
let title = new Title('My Title');
title.show();
`callbackListener` 将注册给定的回调函数,并挂载到全局,用于客户端调用

```js
let cbName = callbackListener('Rexxar.Widget.AlertDialog')('confirm')(() => {})
```

#### getRexxarWidget(config)
### assemblePayload(obj[, base])

配置 Widget 协议的 scheme 和 host,获取 RexxarWidget 基类,推荐使用继承的方式编写自己的组件。
`assemblePayload` 是将一个对象转化成消息中的payload

##### `config.scheme`
```js
let data = {
title: 'AlertDialog',
callback: cbName,
}
let payload = assemblePayload(data)
```

Type: `String`
### dispatch(messenger)

##### `config.host`
`dispatch` 将由widgetMessenger组装好的消息分发给客户端

Type: `String`
```js
dispatch(messenger(payload))
```

### rexxarFetch(input[, init])

### rexxarFetch
`rexxarFetch` 是对 [fetch](https://github.com/github/fetch) 的包装,提供与 [window.fetch](https://fetch.spec.whatwg.org/) 一样的接口和用法。值得注意的是,在使用 POST 时会有所限制,只允许 `content-type``application/x-www-form-urlencoded` 的请求。

```js
import { rexxarFetch } from 'rexxar-web';
Expand All @@ -71,9 +73,32 @@ rexxarFetch('/request')
)
```

#### rexxarFetch(input[, init])
### getRexxarWidget(config)

rexxarFetch 是对 [fetch](https://github.com/github/fetch) 的包装,提供与 [window.fetch](https://fetch.spec.whatwg.org/) 一样的接口和用法。值得注意的是,在 Android Container 中使用 POST 会有所限制,只允许 `content-type``application/x-www-form-urlencoded` 的请求。
**Deprecated**

配置 Widget 协议的 scheme 和 host,获取 RexxarWidget 基类,推荐使用继承的方式编写自己的组件。

```js
import { getRexxarWidget } from 'rexxar-web';

const RexxarWidget = getRexxarWidget({
scheme: 'douban',
host: 'rexxar-container'
});

class Title extends RexxarWidget {
constructor(title) {
super('title');
this.title = title;
}
show() {
super.call({ title: this.title });
}
}
let title = new Title('My Title');
title.show();
```

## 开发与部署

Expand Down Expand Up @@ -110,6 +135,13 @@ $ gulp deploy
```
在这个例子中我们用 `raw.githubusercontent.com` 作为我们的静态资源存放地址,iOS/Android Container 通过访问 `dist/routes.json` 获取路由文件。当然你可以使用自己的CDN服务器来存放资源,并且可以根据需求定制自己的测试环境和线上环境。

## ChangeLog

- v0.2.0
1. rexxarFetch 对于 iOS WKWebView 亦将 POST 转化成 GET 来处理,需要配合 [rexxar-ios v0.3.0](https://github.com/douban/rexxar-ios#changelog) 及以上使用
2. 新增 widgetMessenger, assemblePayload, callbackListener, dispatch
3. 废弃 getRexxarWidget

## License

Rexxar is released under the MIT license. See LICENSE for details.
38 changes: 38 additions & 0 deletions lib/assemblePayload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _utils = require('./utils');

/**
* Assemble payload for message
*
* assemblePayload({ data: '' })
*
* @param {object} obj
* @param {string} base
* @returns {string}
*/
var assemblePayload = function assemblePayload(obj) {
var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';

if ((0, _utils.getType)(obj) !== 'Object' || (0, _utils.getType)(base) !== 'String') {
throw new Error('assemblePayload arguments type error');
}
var query = Object.getOwnPropertyNames(obj).map(function (key) {
var value = obj[key];
// Q: does callback need to be registed
if ((0, _utils.getType)(value) === 'Object') {
value = JSON.stringify(value);
}
return encodeURIComponent(key) + '=' + encodeURIComponent(value);
}).join('&');
if (base) {
base = '/' + base;
}
return (base + '&' + query).replace(/[&?]/, '?');
};

exports.default = assemblePayload;
34 changes: 34 additions & 0 deletions lib/callbackListener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _utils = require('./utils');

/**
* Curry function for callback register
*
* callbackListener('Rexxar.Widget.AlertDialog')('clickHandler')(()=>{}))
*
* @param {string} ns
* @returns {string} The callback name
*/
var callbackListener = function callbackListener(ns) {
return function (name) {
return function (callback) {
(0, _utils.namespace)(ns)[name] = function (jsonStr) {
var data = void 0;
try {
data = JSON.parse(jsonStr);
} catch (e) {
data = jsonStr;
}
callback(data);
};
return ns + '.' + name;
};
};
};

exports.default = callbackListener;
18 changes: 18 additions & 0 deletions lib/dispatch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _utils = require('./utils');

/**
* Dispatch message to client
*
* @param {string} msg
*/
var dispatch = function dispatch(msg) {
(0, _utils.callUri)(msg);
};

exports.default = dispatch;
18 changes: 18 additions & 0 deletions lib/dispatchMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

Object.defineProperty(exports, "__esModule", {
value: true
});

var _utils = require('./utils');

/**
* Dispatch message to client
*
* @param {string} msg
*/
var dispatchMessage = function dispatchMessage(msg) {
(0, _utils.callUri)(msg);
};

exports.default = dispatchMessage;
4 changes: 3 additions & 1 deletion lib/getRexxarWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ Object.defineProperty(exports, "__esModule", {
value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
* IMPORTANT: This is deprecated
*/

exports.default = getRexxarWidget;

Expand Down
24 changes: 22 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,37 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.rexxarFetch = exports.getRexxarWidget = undefined;
exports.dispatch = exports.callbackListener = exports.assemblePayload = exports.widgetMessenger = exports.rexxarFetch = exports.getRexxarWidget = undefined;

var _getRexxarWidget = require('./getRexxarWidget');

var _getRexxarWidget2 = _interopRequireDefault(_getRexxarWidget);

var _widgetMessenger = require('./widgetMessenger');

var _widgetMessenger2 = _interopRequireDefault(_widgetMessenger);

var _assemblePayload = require('./assemblePayload');

var _assemblePayload2 = _interopRequireDefault(_assemblePayload);

var _callbackListener = require('./callbackListener');

var _callbackListener2 = _interopRequireDefault(_callbackListener);

var _dispatch = require('./dispatch');

var _dispatch2 = _interopRequireDefault(_dispatch);

var _rexxarFetch = require('./rexxarFetch');

var _rexxarFetch2 = _interopRequireDefault(_rexxarFetch);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

exports.getRexxarWidget = _getRexxarWidget2.default;
exports.rexxarFetch = _rexxarFetch2.default;
exports.rexxarFetch = _rexxarFetch2.default;
exports.widgetMessenger = _widgetMessenger2.default;
exports.assemblePayload = _assemblePayload2.default;
exports.callbackListener = _callbackListener2.default;
exports.dispatch = _dispatch2.default;
14 changes: 7 additions & 7 deletions lib/rexxarFetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var isAndroid = navigator ? /android/i.test(navigator.userAgent.toLowerCase()) :
/**
* `rexxarFetch` wraps whatwg-fetch function. Use rexxarFetch like using the normal fetch API.
* However, there are some limitation, rexxarFetch does not support Request object as
* argument when you are using for POST in Android, and `application/x-www-form-urlencoded`
* argument when you are using for HTTP POST, and `application/x-www-form-urlencoded`
* must be specified as content-type.
*
* @param {string|object} input Url string or a Request object
Expand All @@ -34,32 +34,32 @@ function rexxarFetch(input, init) {

if (Request.prototype.isPrototypeOf(input) && !init) {
request = input;
if (request.method === 'POST' && isAndroid) {
throw new Error('Please use `rexxarFetch(input, init)` for HTTP POST in Android');
if (request.method === 'POST') {
throw new Error('rexxarFetch POST error: please use `rexxarFetch(input, init)` for HTTP POST');
}
} else {
request = new Request(input, init);
}

if (request.method === 'POST' && isAndroid) {
if (request.method === 'POST') {
var contentType = request.headers.get('content-type');
var body = init.body;

if (!contentType && !body) {
input = (input + '&_rexxar_method=POST').replace(/[&?]/, '?');
promise = (0, _isomorphicFetch2.default)(input);
} else if (contentType && contentType.indexOf('application/x-www-form-urlencoded') > -1) {
if (window && 'URLSearchParams' in window && URLSearchParams.prototype.isPrototypeOf(body)) {
if (window && 'URLSearchParams' in window && window.URLSearchParams.prototype.isPrototypeOf(body)) {
body = body.toString();
}
if ((0, _utils.getType)(body) === 'String') {
input = (input + '&' + body + '&_rexxar_method=POST').replace(/[&?]/, '?');
promise = (0, _isomorphicFetch2.default)(input);
} else {
throw new Error('rexxarFetch for Android Cannot handle this body type');
throw new Error('rexxarFetch POST error: cannot handle this body type');
}
} else {
throw new Error('rexxarFetch for Android only supports `application/x-www-form-urlencoded` as content-type');
throw new Error('rexxarFetch POST error: only supports `application/x-www-form-urlencoded` as content-type');
}
} else {
promise = (0, _isomorphicFetch2.default)(request);
Expand Down
36 changes: 36 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = [
exports.obj2str = obj2str;
exports.str2obj = str2obj;
exports.getType = getType;
exports.namespace = namespace;
exports.callUri = callUri;

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

Expand Down Expand Up @@ -64,4 +66,38 @@ function str2obj(str) {
*/
function getType(obj) {
return Object.prototype.toString.call(obj).slice(8, -1);
}

/**
* Declare a namespace from a string:
*
* namespace('Rexxar.Widget.AlertDialog') => Rexxar.Widget.AlertDialog = {}
*
* @param {string} ns
* @returns {object}
*/
function namespace(ns) {
var names = ns.split('.');
var owner = window;
for (var i = 0; i < names.length; i++) {
var name = names[i];
owner[name] = owner[name] || {};
owner = owner[name];
}
return owner;
}

/**
* Go to uri
*
* @param {string} uri
*/
function callUri(uri) {
var iframe = document.createElement('iframe');
iframe.src = uri;
iframe.style.display = 'none';
document.documentElement.appendChild(iframe);
setTimeout(function () {
return document.documentElement.removeChild(iframe);
}, 0);
}
Loading

0 comments on commit 0aa6c88

Please sign in to comment.