Bladeren bron

Merge pull request #56 from ShaMan123/master

Adding AutoWidth capability
iou90 6 jaren geleden
bovenliggende
commit
c3140b353e
No account linked to committer's email address
3 gewijzigde bestanden met toevoegingen van 186 en 95 verwijderingen
  1. 36
    9
      autoHeightWebView/common.js
  2. 84
    47
      autoHeightWebView/index.android.js
  3. 66
    39
      autoHeightWebView/index.ios.js

+ 36
- 9
autoHeightWebView/common.js Bestand weergeven

@@ -5,7 +5,7 @@ function appendFilesToHead(files, script) {
5 5
     return script;
6 6
   }
7 7
   return files.reduceRight((file, combinedScript) => {
8
-    const { rel, type, href } = file;
8
+      const { rel, type, href } = file;
9 9
     return `
10 10
             var link  = document.createElement('link');
11 11
             link.rel  = '${rel}';
@@ -17,12 +17,29 @@ function appendFilesToHead(files, script) {
17 17
   }, script);
18 18
 }
19 19
 
20
-function appendStylesToHead(styles, script) {
21
-  if (!styles) {
22
-    return script;
23
-  }
20
+function appendStylesToHead(styles, script, shouldResizeWidth) {
21
+    var bodyStyle;
22
+    if (shouldResizeWidth) {
23
+        bodyStyle = `
24
+            body {
25
+                display: flex;
26
+                justify-content: center;
27
+                align-items: center;
28
+            }`;
29
+    }
30
+    else {
31
+        bodyStyle = '';
32
+    }
33
+    
34
+    if (!styles) {
35
+        styles = bodyStyle;
36
+    }
37
+    else {
38
+        styles += bodyStyle;
39
+    }
24 40
   // Escape any single quotes or newlines in the CSS with .replace()
25
-  const escaped = styles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
41
+    const escaped = styles.replace(/\'/g, "\\'").replace(/\n/g, '\\n');
42
+    
26 43
   return `
27 44
           var styleElement = document.createElement('style');
28 45
           var styleText = document.createTextNode('${escaped}');
@@ -33,10 +50,10 @@ function appendStylesToHead(styles, script) {
33 50
 }
34 51
 
35 52
 function getScript(props, baseScript, iframeBaseScript) {
36
-  const { hasIframe, files, customStyle } = props;
53
+    const { hasIframe, files, customStyle, shouldResizeWidth } = props;
37 54
   let script = hasIframe ? iframeBaseScript : baseScript;
38 55
   script = files ? appendFilesToHead(files, baseScript) : baseScript;
39
-  script = customStyle ? appendStylesToHead(customStyle, script) : script;
56
+    script = appendStylesToHead(customStyle, script, shouldResizeWidth);
40 57
   return script;
41 58
 }
42 59
 
@@ -44,6 +61,16 @@ function onHeightUpdated(height, props) {
44 61
   props.onHeightUpdated && props.onHeightUpdated(height);
45 62
 }
46 63
 
64
+function onWidthUpdated(width, props) {
65
+    props.onWidthUpdated && props.onWidthUpdated(width);
66
+}
67
+
68
+function onHeightWidthUpdated(height, width, props) {
69
+    onHeightUpdated(height, props);
70
+    onWidthUpdated(width, props);
71
+    props.onHeightWidthUpdated && props.onHeightWidthUpdated(height, width);
72
+}
73
+
47 74
 const domMutationObserveScript = 
48 75
 `
49 76
 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
@@ -54,4 +81,4 @@ observer.observe(document, {
54 81
 });
55 82
 `;
56 83
 
57
-export { getScript, onHeightUpdated, domMutationObserveScript };
84
+export { getScript, onHeightUpdated, onWidthUpdated, onHeightWidthUpdated, domMutationObserveScript };

+ 84
- 47
autoHeightWebView/index.android.js Bestand weergeven

@@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
19 19
 
20 20
 import Immutable from 'immutable';
21 21
 
22
-import { getScript, onHeightUpdated, domMutationObserveScript, getHeight } from './common.js';
22
+import { getScript, onHeightUpdated, onWidthUpdated, onHeightWidthUpdated, domMutationObserveScript } from './common.js';
23 23
 
24 24
 const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', AutoHeightWebView, {
25 25
   nativeOnly: {
@@ -32,10 +32,15 @@ const RCTAutoHeightWebView = requireNativeComponent('RCTAutoHeightWebView', Auto
32 32
   }
33 33
 });
34 34
 
35
+const screenWidth = Dimensions.get('window').width;
36
+
35 37
 export default class AutoHeightWebView extends PureComponent {
36 38
   static propTypes = {
37 39
     source: WebView.propTypes.source,
38
-    onHeightUpdated: PropTypes.func,
40
+      onHeightUpdated: PropTypes.func,
41
+      onWidthUpdated: PropTypes.func,
42
+      onHeightWidthUpdated: PropTypes.func,
43
+      shouldResizeWidth: PropTypes.bool,
39 44
     customScript: PropTypes.string,
40 45
     customStyle: PropTypes.string,
41 46
     enableAnimation: PropTypes.bool,
@@ -44,7 +49,8 @@ export default class AutoHeightWebView extends PureComponent {
44 49
     // only works on enable animation
45 50
     animationDuration: PropTypes.number,
46 51
     // offset of rn webView margin
47
-    heightOffset: PropTypes.number,
52
+      heightOffset: PropTypes.number,
53
+      widthOffset: PropTypes.number,
48 54
     // baseUrl not work in android 4.3 or below version
49 55
     enableBaseUrl: PropTypes.bool,
50 56
     style: ViewPropTypes.style,
@@ -68,7 +74,9 @@ export default class AutoHeightWebView extends PureComponent {
68 74
     enableBaseUrl: false,
69 75
     enableAnimation: true,
70 76
     animationDuration: 555,
71
-    heightOffset: 20
77
+      heightOffset: 20,
78
+      widthOffset: 20,
79
+      shouldResizeWidth: false
72 80
   };
73 81
 
74 82
   constructor(props) {
@@ -78,7 +86,9 @@ export default class AutoHeightWebView extends PureComponent {
78 86
     this.state = {
79 87
       isChangingSource: false,
80 88
       height: 0,
81
-      heightOffset: 0,
89
+        heightOffset: 0,
90
+        width: screenWidth,
91
+        widthOffset: 0,
82 92
       script: getScript(props, baseScript)
83 93
     };
84 94
   }
@@ -89,21 +99,24 @@ export default class AutoHeightWebView extends PureComponent {
89 99
 
90 100
   componentWillReceiveProps(nextProps) {
91 101
     // injectedJavaScript only works when webView reload (source changed)
92
-    if (Immutable.is(Immutable.fromJS(this.props.source), Immutable.fromJS(nextProps.source))) {
93
-      return;
94
-    } else {
95
-      this.setState(
96
-        {
97
-          isChangingSource: true,
98
-          height: 0,
99
-          heightOffset: 0
100
-        },
101
-        () => {
102
-          this.startInterval();
103
-          this.setState({ isChangingSource: false });
104
-        }
105
-      );
106
-    }
102
+      if (Immutable.is(Immutable.fromJS(this.props.source), Immutable.fromJS(nextProps.source))) {
103
+          return;
104
+      }
105
+      else {
106
+          this.setState(
107
+              {
108
+                  isChangingSource: true,
109
+                  height: 0,
110
+                  heightOffset: 0,
111
+                  width: 0,
112
+                  widthOffset: 0,
113
+              },
114
+              () => {
115
+                  this.startInterval();
116
+                  this.setState({ isChangingSource: false });
117
+              }
118
+          );
119
+      }
107 120
     this.setState({ script: getScript(nextProps, baseScript) });
108 121
   }
109 122
 
@@ -147,26 +160,29 @@ export default class AutoHeightWebView extends PureComponent {
147 160
   }
148 161
 
149 162
   onMessage = e => {
150
-    const height = parseInt(isBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
151
-    if (height && height !== this.state.height) {
152
-      const { enableAnimation, animationDuration, heightOffset } = this.props;
153
-      enableAnimation && this.opacityAnimatedValue.setValue(0);
154
-      this.stopInterval();
155
-      this.setState(
156
-        {
157
-          heightOffset,
158
-          height
159
-        },
160
-        () => {
161
-          enableAnimation
162
-            ? Animated.timing(this.opacityAnimatedValue, {
163
-                toValue: 1,
164
-                duration: animationDuration
165
-              }).start(() => onHeightUpdated(height, this.props))
166
-            : onHeightUpdated(height, this.props);
167
-        }
168
-      );
169
-    }
163
+      const { height, width } = JSON.parse(isBelowKitKat ? e.nativeEvent.message : e.nativeEvent.data);
164
+      if (height && height !== this.state.height && width && width !== this.state.width) {
165
+          const { enableAnimation, animationDuration, heightOffset, widthOffset } = this.props;
166
+          enableAnimation && this.opacityAnimatedValue.setValue(0);
167
+          this.stopInterval();
168
+          
169
+          this.setState(
170
+              {
171
+                  heightOffset,
172
+                  height,
173
+                  widthOffset,
174
+                  width
175
+              },
176
+              () => {
177
+                  enableAnimation
178
+                      ? Animated.timing(this.opacityAnimatedValue, {
179
+                          toValue: 1,
180
+                          duration: animationDuration
181
+                      }).start(() => onHeightWidthUpdated(height, width, this.props))
182
+                      : onHeightWidthUpdated(height, width, this.props);
183
+              }
184
+          );
185
+      }
170 186
   };
171 187
 
172 188
   onLoadingStart = event => {
@@ -198,7 +214,7 @@ export default class AutoHeightWebView extends PureComponent {
198 214
   }
199 215
 
200 216
   render() {
201
-    const { height, script, isChangingSource, heightOffset } = this.state;
217
+      const { height, width, script, isChangingSource, heightOffset, widthOffset } = this.state;
202 218
     const { scalesPageToFit, enableAnimation, source, customScript, style, enableBaseUrl } = this.props;
203 219
     let webViewSource = source;
204 220
     if (enableBaseUrl) {
@@ -206,13 +222,15 @@ export default class AutoHeightWebView extends PureComponent {
206 222
         baseUrl: 'file:///android_asset/web/'
207 223
       });
208 224
     }
225
+      
209 226
     return (
210 227
       <Animated.View
211 228
         style={[
212 229
           styles.container,
213 230
           {
214 231
             opacity: enableAnimation ? this.opacityAnimatedValue : 1,
215
-            height: height + heightOffset
232
+              height: height + heightOffset,
233
+              width: width + widthOffset
216 234
           },
217 235
           style
218 236
         ]}
@@ -239,13 +257,11 @@ export default class AutoHeightWebView extends PureComponent {
239 257
   }
240 258
 }
241 259
 
242
-const screenWidth = Dimensions.get('window').width;
243
-
244 260
 const isBelowKitKat = Platform.Version < 19;
245 261
 
246 262
 const styles = StyleSheet.create({
247 263
   container: {
248
-    width: screenWidth,
264
+    //width: screenWidth,
249 265
     backgroundColor: 'transparent'
250 266
   },
251 267
   webView: {
@@ -257,17 +273,38 @@ const styles = StyleSheet.create({
257 273
 const baseScript = isBelowKitKat
258 274
   ? `
259 275
     ; (function () {
276
+        var wrapper = document.createElement('div');
277
+        wrapper.id = 'wrapper';
278
+        while (document.body.firstChild instanceof Node) {
279
+            wrapper.appendChild(document.body.firstChild);
280
+        }
281
+        document.body.appendChild(wrapper);
282
+
260 283
         AutoHeightWebView.onMessage = function (message) {
261
-            AutoHeightWebView.send(String(document.body.offsetHeight));
284
+            var rect = document.body.firstElementChild.getBoundingClientRect().toJSON();
285
+            var width = Math.round(rect.width);
286
+            var height = Math.round(rect.height);
287
+            AutoHeightWebView.send(JSON.stringify({ width, height }));
262 288
         };
263 289
         ${domMutationObserveScript}
264 290
     } ());
265 291
     `
266 292
   : `
267 293
     ; (function () {
294
+        var wrapper = document.createElement('div');
295
+        wrapper.id = 'wrapper';
296
+        while (document.body.firstChild instanceof Node) {
297
+            wrapper.appendChild(document.body.firstChild);
298
+        }
299
+        document.body.appendChild(wrapper);
300
+
268 301
         document.addEventListener('message', function (e) {
269
-            window.postMessage(String(document.body.offsetHeight));
302
+            var rect = document.body.firstElementChild.getBoundingClientRect().toJSON();
303
+            var width = Math.round(rect.width);
304
+            var height = Math.round(rect.height);
305
+            window.postMessage(JSON.stringify({ width, height }));
270 306
         });
271 307
         ${domMutationObserveScript}
272 308
     } ());
273 309
     `;
310
+

+ 66
- 39
autoHeightWebView/index.ios.js Bestand weergeven

@@ -6,13 +6,18 @@ import { Animated, Dimensions, StyleSheet, ViewPropTypes, WebView } from 'react-
6 6
 
7 7
 import PropTypes from 'prop-types';
8 8
 
9
-import { getScript, onHeightUpdated, domMutationObserveScript } from './common.js';
9
+import { getScript, onHeightUpdated, onWidthUpdated, onHeightWidthUpdated, domMutationObserveScript } from './common.js';
10
+
11
+const screenWidth = Dimensions.get('window').width;
10 12
 
11 13
 export default class AutoHeightWebView extends PureComponent {
12 14
   static propTypes = {
13 15
     hasIframe: PropTypes.bool,
14 16
     source: WebView.propTypes.source,
15
-    onHeightUpdated: PropTypes.func,
17
+      onHeightUpdated: PropTypes.func,
18
+      onWidthUpdated: PropTypes.func,
19
+      onHeightWidthUpdated: PropTypes.func,
20
+      shouldResizeWidth: PropTypes.bool,
16 21
     customScript: PropTypes.string,
17 22
     customStyle: PropTypes.string,
18 23
     enableAnimation: PropTypes.bool,
@@ -21,7 +26,8 @@ export default class AutoHeightWebView extends PureComponent {
21 26
     // only works on enable animation
22 27
     animationDuration: PropTypes.number,
23 28
     // offset of rn webview margin
24
-    heightOffset: PropTypes.number,
29
+      heightOffset: PropTypes.number,
30
+      widthOffset: PropTypes.number,
25 31
     style: ViewPropTypes.style,
26 32
     //  rn WebView callback
27 33
     onError: PropTypes.func,
@@ -43,14 +49,19 @@ export default class AutoHeightWebView extends PureComponent {
43 49
     scalesPageToFit: false,
44 50
     enableAnimation: true,
45 51
     animationDuration: 555,
46
-    heightOffset: 12
52
+      heightOffset: 12,
53
+      widthOffset: 12,
54
+      shouldResizeWidth: false
47 55
   };
48 56
 
49 57
   constructor(props) {
50 58
     super(props);
51 59
     props.enableAnimation && (this.opacityAnimatedValue = new Animated.Value(0));
52 60
     this.state = {
53
-      height: 0,
61
+        height: 0,
62
+        //heightOffset: 0, //?? I added this
63
+        width: screenWidth,
64
+        //widthOffset: 0,
54 65
       script: getScript(props, baseScript, iframeBaseScript)
55 66
     };
56 67
   }
@@ -59,20 +70,22 @@ export default class AutoHeightWebView extends PureComponent {
59 70
     this.setState({ script: getScript(nextProps, baseScript, iframeBaseScript) });
60 71
   }
61 72
 
62
-  handleNavigationStateChange = navState => {
63
-    const height = Number(navState.title);
64
-    const { enableAnimation, animationDuration } = this.props;
65
-    if (height && height !== this.state.height) {
66
-      enableAnimation && this.opacityAnimatedValue.setValue(0);
67
-      this.setState({ height }, () => {
68
-        enableAnimation
69
-          ? Animated.timing(this.opacityAnimatedValue, {
70
-              toValue: 1,
71
-              duration: animationDuration
72
-            }).start(() => onHeightUpdated(height, this.props))
73
-          : onHeightUpdated(height, this.props);
74
-      });
75
-    }
73
+    handleNavigationStateChange = navState => {
74
+        var [width, height] = navState.title.split(',');
75
+        width = Number(width);
76
+        height = Number(height);
77
+        const { enableAnimation, animationDuration } = this.props;
78
+        if (height && height !== this.state.height) {       // ??? add to logic ??? width && width !== this.state.width
79
+            enableAnimation && this.opacityAnimatedValue.setValue(0);
80
+            this.setState({ height, width }, () => {
81
+                enableAnimation
82
+                    ? Animated.timing(this.opacityAnimatedValue, {
83
+                        toValue: 1,
84
+                        duration: animationDuration
85
+                    }).start(() => onHeightWidthUpdated(height, width, this.props))
86
+                    : onHeightWidthUpdated(height, width, this.props);
87
+            });
88
+        }
76 89
   };
77 90
 
78 91
   getWebView = webView => (this.webView = webView);
@@ -82,7 +95,7 @@ export default class AutoHeightWebView extends PureComponent {
82 95
   }
83 96
 
84 97
   render() {
85
-    const { height, script } = this.state;
98
+    const { height, width, script } = this.state;
86 99
     const {
87 100
       onError,
88 101
       onLoad,
@@ -93,6 +106,7 @@ export default class AutoHeightWebView extends PureComponent {
93 106
       enableAnimation,
94 107
       source,
95 108
       heightOffset,
109
+      widthOffset,
96 110
       customScript,
97 111
       style
98 112
     } = this.props;
@@ -103,7 +117,8 @@ export default class AutoHeightWebView extends PureComponent {
103 117
           styles.container,
104 118
           {
105 119
             opacity: enableAnimation ? this.opacityAnimatedValue : 1,
106
-            height: height + heightOffset
120
+              height: height + heightOffset,
121
+              width: width + widthOffset
107 122
           },
108 123
           style
109 124
         ]}
@@ -127,11 +142,8 @@ export default class AutoHeightWebView extends PureComponent {
127 142
   }
128 143
 }
129 144
 
130
-const screenWidth = Dimensions.get('window').width;
131
-
132 145
 const styles = StyleSheet.create({
133 146
   container: {
134
-    width: screenWidth,
135 147
     backgroundColor: 'transparent'
136 148
   },
137 149
   webView: {
@@ -141,36 +153,46 @@ const styles = StyleSheet.create({
141 153
 });
142 154
 
143 155
 const commonScript = `
144
-    updateHeight();
145
-    window.addEventListener('load', updateHeight);
146
-    window.addEventListener('resize', updateHeight);
156
+    updateSize();
157
+    window.addEventListener('load', updateSize);
158
+    window.addEventListener('resize', updateSize);
147 159
     `;
148 160
 
149
-const getHeight = `
161
+const _getter = `
150 162
     function getHeight(height) {
151 163
       if(height < 1) {
152 164
         return document.body.offsetHeight;
153 165
       }
154 166
       return height;
155 167
     }
168
+    function getWidth(width) {
169
+      if(width < 1) {
170
+        return document.body.clientWidth; // maybe should be .offsetWidth ??
171
+      }
172
+      return width;
173
+    }
156 174
     `;
157
-
158 175
 const baseScript = `
159 176
     ;
160
-    ${getHeight}
177
+    ${_getter}
161 178
     (function () {
162 179
         var i = 0;
163 180
         var height = 0;
181
+        var width = ${screenWidth};
164 182
         var wrapper = document.createElement('div');
165 183
         wrapper.id = 'height-wrapper';
166 184
         while (document.body.firstChild instanceof Node) {
167 185
             wrapper.appendChild(document.body.firstChild);
168 186
         }
169 187
         document.body.appendChild(wrapper);
170
-        function updateHeight() {
171
-            if(document.body.offsetHeight !== height) {
172
-                height = getHeight(wrapper.clientHeight);
173
-                document.title = height;
188
+        function updateSize() {
189
+            var rect = document.body.firstElementChild.getBoundingClientRect().toJSON();
190
+            var newWidth = Math.round(rect.width);
191
+            var newHeight = Math.round(rect.height);
192
+            if(newHeight !== height) {
193
+                //height = getHeight(wrapper.clientHeight);
194
+                //width = getWidth(wrapper.clientWidth);
195
+                document.title = newWidth + ',' + newHeight;
174 196
                 window.location.hash = ++i;
175 197
             }
176 198
         }
@@ -181,14 +203,19 @@ const baseScript = `
181 203
 
182 204
 const iframeBaseScript = `
183 205
     ;
184
-    ${getHeight}
206
+    ${_getter}
185 207
     (function () {
186 208
         var i = 0;
187 209
         var height = 0;
188
-        function updateHeight() {
189
-            if(document.body.offsetHeight !== height) {
190
-                height = getHeight(document.body.firstChild.clientHeight);
191
-                document.title = height;
210
+        var width = ${screenWidth};
211
+        function updateSize() {
212
+            var rect = document.body.firstElementChild.getBoundingClientRect().toJSON();
213
+            var newWidth = Math.round(rect.width);
214
+            var newHeight = Math.round(rect.height);
215
+            if(newHeight !== height) {
216
+                //height = getHeight(document.body.firstChild.clientHeight);
217
+                //width = getWidth(document.body.firstChild.clientHeight);
218
+                document.title = newWidth + ',' + newHeight;
192 219
                 window.location.hash = ++i;
193 220
             }
194 221
         }