UNPKG

3.4 kBJavaScriptView Raw
1// @flow
2import courier from './courier';
3import normalizeSlots from './normalizeSlots';
4
5import type {
6 Ctor,
7 CreateRenderFnOptions,
8 CreateRenderFn,
9 CreateRenderFnc,
10} from './annotations';
11
12const isObject = test => Object.prototype.toString.call(test) === '[object Object]';
13const isFn = test => Object.prototype.toString.call(test) === '[object Function]';
14
15const justBindOptions = [
16 'listeners',
17 'nativeOn',
18 'scopedSlots',
19];
20
21const justBindFn = key => justBindOptions.indexOf(key) > -1;
22
23const getOptionsKeys = options => Object
24 .keys(options)
25 .concat(['listeners', 'props', 'attrs'])
26 .filter((k, i, a) => a.indexOf(k) === i);
27
28const createOptionHandlers = (originalOptions, keys) => {
29 const options: {
30 [dataName: string]: Function
31 } = {};
32
33 keys.forEach(key => {
34 const option = originalOptions[key];
35
36 if (!option){
37 options[key] = owner => owner;
38 return;
39 }
40
41 if (isFn(option)){
42 // $FlowFixMe
43 options[key] = option;
44 return;
45 }
46
47 if (isObject(option)){
48 const optionKeys = Object.keys(option);
49
50 if (!optionKeys.some(k => isFn(option[k]))){
51 options[key] = (owner) => Object.assign({}, owner, option);
52 return;
53 }
54
55 options[key] = function(owner) {
56 const result = Object.assign({}, owner);
57 const justBind = justBindFn(key);
58
59 optionKeys.forEach(k => {
60 let value = option && option[k];
61
62 if (isFn(value)){
63 if (justBind){
64 value = value.bind(this);
65 }else{
66 value = value.call(this, owner);
67 }
68 }
69 result[k] = value;
70 });
71 return result;
72 };
73 return;
74 }
75
76 options[key] = () => option;
77 });
78
79 return options;
80};
81
82const preprocessOptions = (originalOptions) => {
83 const keys = getOptionsKeys(originalOptions);
84 const options = createOptionHandlers(originalOptions, keys);
85
86 return (context, isFunctional) => {
87 const result: {
88 on: Object,
89 props: Object,
90 attrs: Object,
91 scopedSlots?: Object,
92 } = {
93 on: {},
94 props: {},
95 attrs: {},
96 };
97
98 keys.forEach(key => {
99 const owner = isFunctional ?
100 context[key] || context.data[key] :
101 context[`$${key}`];
102
103 const value = options[key].call(context, owner);
104
105 if (key === 'listeners'){
106 key = 'on';
107 }
108
109 result[key] = value;
110 });
111
112 return result;
113 };
114};
115
116
117export const createRenderFn: CreateRenderFn = (Component, options) => {
118 const getData = preprocessOptions(options || {});
119
120 return function renderHoc(
121 h: (
122 ctor: Object,
123 data: Object,
124 slots: Array<any>
125 ) => any,
126 context?: Object
127 ) {
128 //const data = processOptions(this || context || {}, options || {});
129 const data = getData(context || this, !!context);
130 const scopedSlots: Object = (context && context.data && context.data.scopedSlots) ||
131 (this && this.$scopedSlots);
132 const slots: Array<any> = (context && context.children) || (this && this.$slots && normalizeSlots(this.$slots)) || [];
133
134 data.scopedSlots = data.scopedSlots || scopedSlots;
135
136 return h(Component, data, slots);
137 };
138};
139
140export const createRenderFnc: CreateRenderFnc = courier(2, (
141 options: CreateRenderFnOptions,
142 Component: Ctor
143) => {
144 return createRenderFn(Component, options);
145});