weex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d...@apache.org
Subject [08/13] incubator-weex git commit: Merge branch '0.14-dev' of https://github.com/apache/incubator-weex into 0.14-dev
Date Mon, 03 Jul 2017 03:44:57 GMT
Merge branch '0.14-dev' of https://github.com/apache/incubator-weex into 0.14-dev


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/da75a60f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/da75a60f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/da75a60f

Branch: refs/heads/0.15-dev
Commit: da75a60fa7e96fcedf88860d567fd4768721018d
Parents: 3fe2ff0
Author: erha19 <faterrole@gmail.com>
Authored: Fri Jun 30 16:31:49 2017 +0800
Committer: erha19 <faterrole@gmail.com>
Committed: Fri Jun 30 16:31:49 2017 +0800

----------------------------------------------------------------------
 android/sdk/libs/armeabi/libweexjsc.so          | Bin 7575352 -> 7570504 bytes
 android/sdk/libs/x86/libweexjsc.so              | Bin 12130116 -> 12121924 bytes
 .../java/com/taobao/weex/ComponentObserver.java |  50 ++++++++++++++++
 .../java/com/taobao/weex/WXSDKInstance.java     |  16 +++++
 .../taobao/weex/ui/component/WXComponent.java   |  18 +++++-
 .../ui/component/list/BasicListComponent.java   |  16 +++--
 build/webpack.examples.web.config.js            |   1 +
 build/webpack.test.web.config.js                |   1 +
 html5/render/vue/README.md                      |  19 +++++-
 .../render/vue/components/slider/slideMixin.js  |  24 ++++----
 html5/render/vue/core/style.js                  |  52 ++++++++++++-----
 html5/render/vue/env/global.js                  |   2 +
 html5/render/vue/env/weex.js                    |   3 +
 html5/render/vue/mixins/scrollable.js           |  38 +++++++-----
 html5/render/vue/mixins/style.js                |  58 ++++++++++++++++---
 html5/render/vue/utils/style.js                 |  28 +++++++++
 html5/test/render/vue/core/scope-style-map.js   |   4 ++
 .../Sources/Component/WXCycleSliderComponent.m  |   7 +++
 package.json                                    |   4 +-
 packages/weex-vue-render/package.json           |   2 +-
 test/pages/components/textarea-maxlength.vue    |  10 +---
 .../components/textarea-maxlength.test.js       |   6 +-
 test/scripts/util.js                            |   2 +-
 23 files changed, 290 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/android/sdk/libs/armeabi/libweexjsc.so
----------------------------------------------------------------------
diff --git a/android/sdk/libs/armeabi/libweexjsc.so b/android/sdk/libs/armeabi/libweexjsc.so
index a180660..41b1ee8 100755
Binary files a/android/sdk/libs/armeabi/libweexjsc.so and b/android/sdk/libs/armeabi/libweexjsc.so
differ

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/android/sdk/libs/x86/libweexjsc.so
----------------------------------------------------------------------
diff --git a/android/sdk/libs/x86/libweexjsc.so b/android/sdk/libs/x86/libweexjsc.so
index 9626c3c..c45672a 100755
Binary files a/android/sdk/libs/x86/libweexjsc.so and b/android/sdk/libs/x86/libweexjsc.so
differ

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java b/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java
new file mode 100644
index 0000000..a2bcd09
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/ComponentObserver.java
@@ -0,0 +1,50 @@
+/**
+ * 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.
+ */
+package com.taobao.weex;
+
+import android.view.View;
+
+import com.taobao.weex.ui.component.WXComponent;
+
+/**
+ * Created by sospartan on 14/06/2017.
+ */
+
+public interface ComponentObserver {
+
+  /**
+   * Called after component is create.
+   * Notice: View is not created at this moment.
+   * @param component
+   */
+  void onCreate(WXComponent component);
+
+  /**
+   * Called before component destroy.
+   * @param component
+   */
+  void onPreDestory(WXComponent component);
+
+  /**
+   * Called when component's view is created
+   * @param component
+   * @param view
+   */
+  void onViewCreated(WXComponent component,View view);
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
index 5533843..a8d8a60 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
@@ -142,6 +142,7 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext,
View.
   private LayoutFinishListener mLayoutFinishListener;
 
   private boolean mCurrentGround = false;
+  private ComponentObserver mComponentObserver;
 
   /**
    * If anchor is created manually(etc. define a layout xml resource ),
@@ -276,6 +277,21 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext,
View.
     mUserTrackAdapter=WXSDKManager.getInstance().getIWXUserTrackAdapter();
   }
 
+  /**
+   * Set a Observer for component.
+   * This observer will be called in each component, should not doing
+   * anything will impact render performance.
+   *
+   * @param observer
+   */
+  public void setComponentObserver(ComponentObserver observer){
+    mComponentObserver = observer;
+  }
+
+  public ComponentObserver getComponentObserver(){
+    return mComponentObserver;
+  }
+
   public NativeInvokeHelper getNativeInvokeHelper() {
     return mNativeInvokeHelper;
   }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
index 3206c86..730d6da 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
@@ -41,6 +41,7 @@ import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.taobao.weex.ComponentObserver;
 import com.taobao.weex.IWXActivityStateListener;
 import com.taobao.weex.WXEnvironment;
 import com.taobao.weex.WXSDKInstance;
@@ -225,6 +226,10 @@ public abstract class  WXComponent<T extends View> implements IWXObject,
IWXActi
     mGestureType = new HashSet<>();
     ++mComponentNum;
     onCreate();
+    ComponentObserver observer;
+    if ((observer = getInstance().getComponentObserver()) != null) {
+      observer.onCreate(this);
+    }
   }
 
   protected void onCreate(){
@@ -902,6 +907,10 @@ public abstract class  WXComponent<T extends View> implements IWXObject,
IWXActi
       }
       if(mHost != null){
         mHost.setId(WXViewUtils.generateViewId());
+        ComponentObserver observer;
+        if ((observer = getInstance().getComponentObserver()) != null) {
+          observer.onViewCreated(this, mHost);
+        }
       }
       onHostViewInitialized(mHost);
     }else{
@@ -940,7 +949,9 @@ public abstract class  WXComponent<T extends View> implements IWXObject,
IWXActi
    */
   @CallSuper
   protected void onHostViewInitialized(T host){
-    host.setCameraDistance(Float.MAX_VALUE);
+    if(host!=null){
+      host.setCameraDistance(Float.MAX_VALUE);
+    }
     if (mAnimationHolder != null) {
       //Performs cached animation
       mAnimationHolder.execute(mInstance, this);
@@ -1273,6 +1284,11 @@ public abstract class  WXComponent<T extends View> implements
IWXObject, IWXActi
   }
 
   public void destroy() {
+    ComponentObserver observer;
+    if ((observer = getInstance().getComponentObserver()) != null) {
+      observer.onPreDestory(this);
+    }
+
     if (WXEnvironment.isApkDebugable() && !WXUtils.isUiThread()) {
       throw new WXRuntimeException("[WXComponent] destroy can only be called in main thread");
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
index 4f897f3..306be55 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
@@ -330,16 +330,20 @@ public abstract class BasicListComponent<T extends ViewGroup &
ListComponentView
         super.onScrolled(recyclerView, dx, dy);
         List<OnWXScrollListener> listeners = getInstance().getWXScrollListeners();
         if (listeners != null && listeners.size() > 0) {
-          for (OnWXScrollListener listener : listeners) {
-            if (listener != null) {
-              if(listener instanceof ICheckBindingScroller){
-                if(((ICheckBindingScroller) listener).isNeedScroller(getRef(),null)){
+          try {
+            for (OnWXScrollListener listener : listeners) {
+              if (listener != null) {
+                if (listener instanceof ICheckBindingScroller) {
+                  if (((ICheckBindingScroller) listener).isNeedScroller(getRef(), null))
{
+                    listener.onScrolled(recyclerView, dx, dy);
+                  }
+                } else {
                   listener.onScrolled(recyclerView, dx, dy);
                 }
-              }else {
-                listener.onScrolled(recyclerView, dx, dy);
               }
             }
+          } catch (Exception e) {
+            e.printStackTrace();
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/build/webpack.examples.web.config.js
----------------------------------------------------------------------
diff --git a/build/webpack.examples.web.config.js b/build/webpack.examples.web.config.js
index 4b81cc5..c28db57 100644
--- a/build/webpack.examples.web.config.js
+++ b/build/webpack.examples.web.config.js
@@ -81,6 +81,7 @@ module.exports = {
     ]
   },
   vue: {
+    optimizeSSR: false,
     /**
      * important! should use postTransformNode to add $processStyle for
      * inline style prefixing.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/build/webpack.test.web.config.js
----------------------------------------------------------------------
diff --git a/build/webpack.test.web.config.js b/build/webpack.test.web.config.js
index 3135852..6c2a6d4 100644
--- a/build/webpack.test.web.config.js
+++ b/build/webpack.test.web.config.js
@@ -81,6 +81,7 @@ module.exports = {
     ]
   },
   vue: {
+    optimizeSSR: false,
     /**
      * important! should use postTransformNode to add $processStyle for
      * inline style prefixing.

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/README.md
----------------------------------------------------------------------
diff --git a/html5/render/vue/README.md b/html5/render/vue/README.md
index e2f39d0..f0d3ba8 100644
--- a/html5/render/vue/README.md
+++ b/html5/render/vue/README.md
@@ -27,7 +27,24 @@ If you perfer cdn way, and use script tag to import a script link, just
import i
 
 ## use vue-loader to bundle .vue file
 
-**NOTE: ** after `v0.11.3` there's no need to add `$processStyle` and `autoprefixer` in your
vue-loader config anymore. The runtime render will take care of it once for all.
+NOTE: you should inject `$processStyle` to preprocess vnode's style in vue-loader's postTransformNode
hook.
+
+```javascript
+vue: {
+  /**
+    * important! should use postTransformNode to add $processStyle for
+    * inline style prefixing.
+    */
+  compilerModules: [
+    {
+      postTransformNode: el => {
+        el.staticStyle = `$processStyle(${el.staticStyle})`
+        el.styleBinding = `$processStyle(${el.styleBinding})`
+      }
+    }
+  ],
+}
+```
 
 ## component -> dom map
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/components/slider/slideMixin.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/components/slider/slideMixin.js b/html5/render/vue/components/slider/slideMixin.js
index da2c848..73960e5 100644
--- a/html5/render/vue/components/slider/slideMixin.js
+++ b/html5/render/vue/components/slider/slideMixin.js
@@ -48,7 +48,6 @@ export default {
   },
 
   updated () {
-    this._startAutoPlay()
     const children = this.$children
     const len = children && children.length
     if (children && len > 0) {
@@ -69,7 +68,6 @@ export default {
 
   mounted () {
     this._getWrapperSize()
-    this._startAutoPlay()
     this._slideTo(this.currentIndex)
     fireLazyload(this.$el, true)
   },
@@ -79,8 +77,8 @@ export default {
       const wrapper = this.$refs.wrapper
       if (wrapper) {
         const rect = wrapper.getBoundingClientRect()
-        this.wrapperWidth = rect.width
-        this.wrapperHeight = rect.height
+        this._wrapperWidth = rect.width
+        this._wrapperHeight = rect.height
       }
     },
 
@@ -198,7 +196,7 @@ export default {
         const match = translate && translate.match(/translate[^(]+\(([+-\d.]+)/)
         const innerX = match && match[1] || 0
         const dist = innerX - this.innerOffset
-        this.innerOffset += step * this.wrapperWidth
+        this.innerOffset += step * this._wrapperWidth
         // transform the whole slides group.
         inner.style.webkitTransition = `-webkit-transform ${TRANSITION_TIME / 1000}s ease-in-out`
         inner.style.transition = `transform ${TRANSITION_TIME / 1000}s ease-in-out`
@@ -341,7 +339,7 @@ export default {
       }
 
       node._inShow = true
-      const translateX = index * this.wrapperWidth - this.innerOffset
+      const translateX = index * this._wrapperWidth - this.innerOffset
       addTransform(node, {
         translate: `translate3d(${translateX}px, 0px, 0px)`
       })
@@ -439,7 +437,7 @@ export default {
       origNode._inShow = true
       const transObj = getTransformObj(clone)
       transObj.translate = transObj.translate.replace(/[+-\d.]+[pw]x/, ($0) => {
-        return pos * this.wrapperWidth - this.innerOffset + 'px'
+        return pos * this._wrapperWidth - this.innerOffset + 'px'
       })
       this._copyStyle(clone, origNode, styleProps, transObj)
       this._removeClone(clone)
@@ -456,6 +454,10 @@ export default {
         this.currentIndex = 0
         return
       }
+
+      // clear autoPlay timer (and restart after updated hook).
+      this._startAutoPlay()
+
       /**
        * clean nodes. replace current node with non-cloned node.
        * set current index to the new index.
@@ -505,7 +507,7 @@ export default {
         }
         // calculate position offsets according to neighbor scales.
         if (Math.abs(i) === 1) {
-          const dist = ((this.wrapperWidth - this._neighborWidth * this.neighborScale) /
2
+          const dist = ((this._wrapperWidth - this._neighborWidth * this.neighborScale) /
2
             + this.neighborSpace * weex.config.env.scale) / this.neighborScale
           translateX = -i * dist
         }
@@ -582,7 +584,7 @@ export default {
           this._clearNodesOffset()
         }
         this._emitScrollEvent('scroll', {
-          offsetXRatio: offsetX / this.wrapperWidth
+          offsetXRatio: offsetX / this._wrapperWidth
         })
         inner.style.transform = `translate3d(${this.innerOffset + offsetX}px, 0, 0)`
         inner.style.webkitTransform = `translate3d(${this.innerOffset + offsetX}px, 0, 0)`
@@ -602,7 +604,7 @@ export default {
       if (inner) {
         this._nodesOffsetCleared = false
         // TODO: test the velocity if it's less than 0.2.
-        const reset = Math.abs(offsetX / this.wrapperWidth) < 0.2
+        const reset = Math.abs(offsetX / this._wrapperWidth) < 0.2
         const direction = offsetX > 0 ? 1 : -1
         const newIndex = reset ? this.currentIndex : (this.currentIndex - direction)
         this._slideTo(newIndex, true)
@@ -623,7 +625,7 @@ export default {
       const throttleTime = THROTTLE_SCROLL_TIME
       const cnt = parseInt(TRANSITION_TIME / throttleTime) - 1
       const sign = offset > 0 ? 1 : -1
-      const r = Math.abs(offset / this.wrapperWidth)
+      const r = Math.abs(offset / this._wrapperWidth)
       const throttledScroll = () => {
         if (++i > cnt) {
           return callback && callback.call(this)

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/core/style.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/core/style.js b/html5/render/vue/core/style.js
index 063c1e5..d2b155a 100644
--- a/html5/render/vue/core/style.js
+++ b/html5/render/vue/core/style.js
@@ -26,11 +26,13 @@ import {
   autoPrefix,
   isArray,
   getParentScroller,
-  supportSticky
+  supportSticky,
+  appendCss
 } from '../utils'
 import { tagBegin, tagEnd } from '../utils/perf'
 /* istanbul ignore next */
 
+let pseudoId = 0
 /**
  * get scoped class style map from stylesheets in <head>.
  */
@@ -39,8 +41,13 @@ export function getHeadStyleMap () {
     tagBegin('getHeadStyleMap')
   }
   const needToRemoveStyleSheetNodes = []
-  const res = Array.from(document.styleSheets || [])
+  const styleSheetsArr = Array.from(document.styleSheets || []).filter(function (styleSheet)
{
+    return styleSheet.ownerNode.getAttribute('weex-scanned') !== '1'
+  })
+
+  const res = Array.from(styleSheetsArr)
     .reduce((pre, styleSheet) => {
+      styleSheet.ownerNode.setAttribute('weex-scanned', 1)
       /**
        * why not using styleSheet.rules || styleSheet.cssRules to get css rules ?
        * because weex's components defined non-standard style attributes, which is
@@ -48,13 +55,18 @@ export function getHeadStyleMap () {
        * another reason not to use cssRules directy:
        * @issue: https://stackoverflow.com/questions/21642277/security-error-the-operation-is-insecure-in-firefox-document-stylesheets
        */
-      if ((styleSheet.ownerNode.tagName.toLowerCase() === 'link')
-        || !styleSheet.ownerNode.textContent) {
-        /**
-         * css in a link. just ignore this. probably a link stylesheet.
-         */
+      if (
+        // css in a link. just ignore this. probably a link stylesheet.
+        (styleSheet.ownerNode.tagName.toLowerCase() === 'link')
+        || !styleSheet.ownerNode.textContent
+        // pseudo class styleSheet node is generated by weex. just ignore it.
+        || styleSheet.ownerNode.id.match(/weex-pseudo-\d+/)) {
         return pre
       }
+
+      /**
+       * start to analyze it's content.
+       */
       const strArr = trimComment(styleSheet.ownerNode.textContent.trim()).split(/}/)
       const len = strArr.length
       const rules = []
@@ -65,7 +77,8 @@ export function getHeadStyleMap () {
         }
         /**
          * should match these cases:
-         * .a[data-v-xxx] { color: red }
+         * .a[data-v-xxx] { color: red; }
+         * .a[data-v-xxx]:active { color: green; }
          * .a[data-v-xxx], .b[data-v-xxx] { color: red; }
          *
          * should not match these cases:
@@ -92,6 +105,10 @@ export function getHeadStyleMap () {
       }
       Array.from(rules).forEach(rule => {
         const selector = rule.selectorText || ''
+        let isPseudo = false
+        if (selector.match(/:(?:active|focus|enabled|disabled)/)) {
+          isPseudo = true
+        }
         const styleObj = trimComment(rule.cssText).split(';')
           .reduce((styleObj, statement) => {
             statement = statement.trim()
@@ -101,12 +118,19 @@ export function getHeadStyleMap () {
             }
             return styleObj
           }, {})
-        const res = pre[selector]
+        if (isPseudo) {
+          const txt = Object.keys(styleObj).reduce(function (pre, cur) {
+            return pre + `${cur}:${styleObj[cur]}!important;`
+          }, '')
+          appendCss(`${selector}{${txt}}`, `weex-pseudo-${pseudoId++}`)
+        }
+        const objMap = !isPseudo ? pre : pre.pseudo
+        const res = objMap[selector]
         if (!res) {
-          pre[selector] = styleObj
+          objMap[selector] = styleObj
         }
         else {
-          extend(pre[selector], styleObj)
+          extend(objMap[selector], styleObj)
         }
       })
       /**
@@ -116,7 +140,7 @@ export function getHeadStyleMap () {
        */
       needToRemoveStyleSheetNodes.push(styleSheet.ownerNode)
       return pre
-    }, {})
+    }, { pseudo: {}})
   if (!window._no_remove_style_sheets) {
     needToRemoveStyleSheetNodes.forEach(function (node) {
       node.parentNode.removeChild(node)
@@ -153,7 +177,7 @@ export function getScopeId (vnode) {
 export function getScopeStyle (vnode, classNames) {
   const scopeId = getScopeId(vnode)
   const style = {}
-  const styleMap = weex.styleMap || {}
+  const styleMap = weex._styleMap || {}
   let clsNmsIdx = 0
   const clsNmsLen = classNames.length
   while (clsNmsIdx < clsNmsLen) {
@@ -301,7 +325,7 @@ export function processSticky (context) {
     return
   }
   // current only support list and vertical scroller.
-  if (container.scrollDirection === 'horizontal') {
+  if (context.scrollDirection === 'horizontal') {
     return
   }
   const stickyChildren = context._stickyChildren

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/env/global.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/env/global.js b/html5/render/vue/env/global.js
index 337244e..e872c4f 100644
--- a/html5/render/vue/env/global.js
+++ b/html5/render/vue/env/global.js
@@ -22,6 +22,8 @@ import * as core from '../core'
 window.global = window
 window.weex = weex
 
+weex._styleMap = {}
+
 ; ['getComponentStyle',
   'extractComponentStyle',
   'createEventMap',

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/env/weex.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/env/weex.js b/html5/render/vue/env/weex.js
index 9b804cb..199e8ae 100644
--- a/html5/render/vue/env/weex.js
+++ b/html5/render/vue/env/weex.js
@@ -33,6 +33,8 @@ const weex = {
     bundleUrl: location.href
   },
 
+  _components: {},
+
   document: {
     body: {}
   },
@@ -92,6 +94,7 @@ const weex = {
     if (!this.__vue__) {
       return console.log('[Vue Render] Vue is not found. Please import Vue.js before register
a component.')
     }
+    this._components[name] = 1
     if (component._css) {
       const css = component._css.replace(/\b[+-]?[\d.]+rem;?\b/g, function (m) {
         return parseFloat(m) * 75 * weex.config.env.scale + 'px'

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/mixins/scrollable.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/mixins/scrollable.js b/html5/render/vue/mixins/scrollable.js
index 011c8e0..4f7b03c 100644
--- a/html5/render/vue/mixins/scrollable.js
+++ b/html5/render/vue/mixins/scrollable.js
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { getThrottleLazyload, throttle } from '../utils'
+import { getThrottleLazyload, throttle, getRangeWidth } from '../utils'
 import { processSticky } from '../core'
 
 const DEFAULT_OFFSET_ACCURACY = 10
@@ -97,8 +97,20 @@ export default {
       const wrapper = this.$refs.wrapper
       if (wrapper) {
         const rect = wrapper.getBoundingClientRect()
-        this.wrapperWidth = rect.width
-        this.wrapperHeight = rect.height
+        this._wrapperWidth = rect.width
+        this._wrapperHeight = rect.height
+      }
+      const inner = this.$refs.inner
+      const children = inner && inner.children
+      if (inner) {
+        const rect = inner.getBoundingClientRect()
+        this._innerWidth = rect.width
+        this._innerHeight = rect.height
+      }
+      // inner width is always the viewport width somehow in horizontal
+      // scoller, therefore the inner width should be reclaculated.
+      if (this.scrollDirection === 'horizontal' && children) {
+        this._innerWidth = getRangeWidth(inner)
       }
     },
 
@@ -115,19 +127,13 @@ export default {
       // fire loadmore event.
       const inner = this.$refs.inner
       if (inner) {
-        const innerRect = inner.getBoundingClientRect()
         const innerLength = this.scrollDirection === 'horizontal'
-          ? innerRect.width
-          : innerRect.height
-        // hscroller not support loadmore event yet.
-        if (this.scrollDirection === 'horizontal') {
-          return
-        }
+          ? this._innerWidth
+          : this._innerHeight
         if (!this._innerLength) {
           this._innerLength = innerLength
         }
         if (this._innerLength !== innerLength) {
-          console.log(this._innerLength, innerLength)
           this._innerLength = innerLength
           this._loadmoreReset = true
         }
@@ -149,13 +155,15 @@ export default {
       const offset = parseInt(this.loadmoreoffset) * weex.config.env.scale
 
       if (wrapper && inner) {
-        const innerRect = inner.getBoundingClientRect()
-        const wrapperRect = wrapper.getBoundingClientRect()
+        // const innerRect = inner.getBoundingClientRect()
+        // const wrapperRect = wrapper.getBoundingClientRect()
         const key = this.scrollDirection === 'horizontal'
           ? 'width'
           : 'height'
-        const innerLength = innerRect[key]
-        const wrapperLength = wrapperRect[key]
+        // const innerLength = innerRect[key]
+        // const wrapperLength = wrapperRect[key]
+        const innerLength = this[`_inner${key[0].toUpperCase()}${key.substr(1)}`]
+        const wrapperLength = this[`_wrapper${key[0].toUpperCase()}${key.substr(1)}`]
         const scrollOffset = this.scrollDirection === 'horizontal'
           ? wrapper.scrollLeft
           : wrapper.scrollTop

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/mixins/style.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/mixins/style.js b/html5/render/vue/mixins/style.js
index 394c1ab..5be2edc 100644
--- a/html5/render/vue/mixins/style.js
+++ b/html5/render/vue/mixins/style.js
@@ -28,21 +28,63 @@ import {
   extend
 } from '../utils'
 
-export default {
-  beforeCreate () {
+/**
+ * get a beforeCreate hook, which has a mark to identify the hook function itself.
+ */
+function getIdentifiedBeforeCreate () {
+  const disposed = {} // disposed components. Already scanned.
+  function beforeCreate () {
     /**
      * get static class style map from document's styleSheets.
      * Weex.on will create a Vue instance. In this case we'll ignore it, since
      * it's not sure whether the scoped style has already attached to head or not.
      */
-    if (this === this.$root && this.$options && !this._styleMapGot) {
-      if (!weex.styleMap) {
-        weex.styleMap = {}
+    const tagName = this.$options && this.$options._componentTag
+    /**
+     * For vue-loader ^11.3.x, there's no injectStyle function. The styleSheet
+     * is already injected into the head. Just scan it.
+     */
+    if (this === this.$root && this.$options && !this._firstScanned) {
+      this._firstScanned = true
+      extend(weex._styleMap, getHeadStyleMap())
+    }
+    /**
+     * For vue-loader ^12.0, the injectStyle function is hooked. We should scan
+     * style map after the injectStyle hook called.
+     */
+    if (((this === this.$root && this.$options)
+      || (tagName
+      && !weex._components[tagName]
+      && !disposed[tagName]))
+      && !this._secondScanned) {
+      disposed[tagName] = 1
+      this._secondScanned = true
+      const hooks = this.$options.beforeCreate
+      const len = hooks.length
+      let thisHookIdx = 0 // index of this hook in the hooks array.
+      for (; thisHookIdx < len; thisHookIdx++) {
+        if (hooks[thisHookIdx]._styleMixin) { break }
+      }
+      for (let i = thisHookIdx + 1; i < len; i++) {
+        const func = hooks[i]
+        if (func.name === 'injectStyle') {
+          hooks[i] = function () {
+            // call the original injectStyle hook.
+            func.call(this)
+            // scan the new appended styleSheet.
+            extend(weex._styleMap, getHeadStyleMap())
+            hooks[i] = func
+          }
+        }
       }
-      this._styleMapGot = true
-      extend(weex.styleMap, getHeadStyleMap())
     }
-  },
+  }
+  beforeCreate._styleMixin = true
+  return beforeCreate
+}
+
+export default {
+  beforeCreate: getIdentifiedBeforeCreate(),
 
   methods: {
     $processStyle (style) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/render/vue/utils/style.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/utils/style.js b/html5/render/vue/utils/style.js
index a9f7ef1..0d74721 100644
--- a/html5/render/vue/utils/style.js
+++ b/html5/render/vue/utils/style.js
@@ -303,3 +303,31 @@ export function getStyleSheetById (id?: string) {
     }
   }
 }
+
+function getChildrenTotalWidth (children) {
+  const len = children.length
+  let total = 0
+  for (let i = 0; i < len; i++) {
+    total += children[i].getBoundingClientRect().width
+  }
+  return total
+}
+/**
+ * get total content width of the element.
+ * @param {HTMLElement} elm
+ */
+export function getRangeWidth (elm: HTMLElement) {
+  const children = elm.children
+  if (!children) {
+    return elm.getBoundingClientRect().width
+  }
+  if (!Range) {
+    return getChildrenTotalWidth(children)
+  }
+  const range = document.createRange()
+  if (!range.selectNodeContents) {
+    return getChildrenTotalWidth(children)
+  }
+  range.selectNodeContents(elm)
+  return range.getBoundingClientRect().width
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/html5/test/render/vue/core/scope-style-map.js
----------------------------------------------------------------------
diff --git a/html5/test/render/vue/core/scope-style-map.js b/html5/test/render/vue/core/scope-style-map.js
index 38ec2a4..29bea0c 100644
--- a/html5/test/render/vue/core/scope-style-map.js
+++ b/html5/test/render/vue/core/scope-style-map.js
@@ -64,6 +64,10 @@ describe('style map', () => {
      * get style map.
      */
     window._no_remove_style_sheets = false
+    // clear mark set in other test cases.
+    Array.from(document.styleSheets).forEach(function (styleSheet) {
+      styleSheet.ownerNode.removeAttribute('weex-scanned')
+    })
     const styleMap = getHeadStyleMap()
     window._no_remove_style_sheets = true
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
index 690c709..7c7fbd0 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.m
@@ -80,6 +80,13 @@ typedef NS_ENUM(NSInteger, Direction) {
     return self;
 }
 
+- (void)dealloc
+{
+    if (_scrollView) {
+        _scrollView.delegate = nil;
+    }
+}
+
 - (void)layoutSubviews
 {
     [super layoutSubviews];

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 381190f..2888260 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "subversion": {
     "browser": "0.5.0",
     "framework": "0.20.6",
-    "vue-render": "0.11.50",
+    "vue-render": "0.11.52",
     "transformer": ">=0.1.5 <0.5"
   },
   "description": "A framework for building Mobile cross-platform UI",
@@ -155,7 +155,7 @@
     "sinon-chai": "^2.8.0",
     "uglify-js": "^2.6.4",
     "vue": "^2.2.6",
-    "vue-loader": "^11.3.3",
+    "vue-loader": "^12.2.1",
     "vue-template-compiler": "^2.2.6",
     "webpack": "^1.13.1",
     "weex-components": "^0.2.0",

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/packages/weex-vue-render/package.json
----------------------------------------------------------------------
diff --git a/packages/weex-vue-render/package.json b/packages/weex-vue-render/package.json
index e97525f..485a099 100644
--- a/packages/weex-vue-render/package.json
+++ b/packages/weex-vue-render/package.json
@@ -1,6 +1,6 @@
 {
   "name": "weex-vue-render",
-  "version": "0.11.50",
+  "version": "0.11.52",
   "description": "Weex built-in components for Vue 2.x.",
   "license": "Apache-2.0",
   "main": "dist/index.js",

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/test/pages/components/textarea-maxlength.vue
----------------------------------------------------------------------
diff --git a/test/pages/components/textarea-maxlength.vue b/test/pages/components/textarea-maxlength.vue
index 503a59f..a1a9ddc 100644
--- a/test/pages/components/textarea-maxlength.vue
+++ b/test/pages/components/textarea-maxlength.vue
@@ -16,17 +16,9 @@
       oninput (event) {
         this.value = event.value
         console.log('oninput:', event.value)
-        modal.toast({
-          message: `oninput: ${event.value}`,
-          duration: 0.8
-        })
       },
       onchange (event) {
         console.log('onchange:', event.value)
-        modal.toast({
-          message: `onchange: ${event.value}`,
-          duration: 0.8
-        })
       },
     }
   }
@@ -47,4 +39,4 @@
     border-color: #41B883;
     maxlength:10;
   }
-</style>
\ No newline at end of file
+</style>

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/test/scripts/components/textarea-maxlength.test.js
----------------------------------------------------------------------
diff --git a/test/scripts/components/textarea-maxlength.test.js b/test/scripts/components/textarea-maxlength.test.js
index 7473d3d..c3c583d 100644
--- a/test/scripts/components/textarea-maxlength.test.js
+++ b/test/scripts/components/textarea-maxlength.test.js
@@ -43,11 +43,13 @@ describe('@ignore-android textarea maxlength vue test2 ', function ()
{
     return driver
       .elementById('textarea')
       .sendKeys('12345678')
-      .sleep(2000)
+      .sleep(3000)
+      .source()
       .elementById('status')
       .text()
       .then((text)=>{
-      assert.equal(text,'1234')
+        console.log(text)
+        assert.equal(text,'1234')
      })
   })
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/da75a60f/test/scripts/util.js
----------------------------------------------------------------------
diff --git a/test/scripts/util.js b/test/scripts/util.js
index 50bf9ee..fd9fa43 100644
--- a/test/scripts/util.js
+++ b/test/scripts/util.js
@@ -194,7 +194,7 @@ module.exports = {
             return driver.status()
         else{
             driver._isInit = true;
-            return driver.initDriver()
+            return driver.initDriver().sleep(20000) //ios cannot detect at once
         }
     },
     quit:function(driver){


Mime
View raw message