diff --git a/src/mip-258-form-btn/README.md b/src/mip-258-form-btn/README.md
new file mode 100644
index 000000000..6548b6cd8
--- /dev/null
+++ b/src/mip-258-form-btn/README.md
@@ -0,0 +1,45 @@
+# mip-258-form-btn ajax请求
+
+ajax请求
+
+标题|内容
+----|----
+类型|通用
+支持布局|N/S
+## 示例
+
+### 基本使用
+
+```html
+
+
+ 请求成功,一秒后跳转
+ 字段格式不正确
+
+
+
+```
+### url
+
+说明:必须是 HTTP(S) 或 // 开头的地址
+必选项: 是
+
+### method
+
+说明:请求方法
+必选项: 是
+
+### redirect
+
+说明:必须是 HTTP(S) 或 // 开头的地址
+必选项: 否
+
+### reload
+
+说明:boolean值 默认false, 请求成功后是否页面刷新
+必选项: 否
+
+
+
+
+
diff --git a/src/mip-258-form-btn/mip-258-form-btn.js b/src/mip-258-form-btn/mip-258-form-btn.js
new file mode 100644
index 000000000..139a74bd3
--- /dev/null
+++ b/src/mip-258-form-btn/mip-258-form-btn.js
@@ -0,0 +1,50 @@
+
+/**
+ * @file mip-ajax-button 组件
+ *
+ * @author chen
+ * @time 2018.8.21
+ */
+define(function (require) {
+ var customElement = require('customElement').create();
+ var $ = require('zepto');
+ customElement.prototype.build = function () {
+ var element = this.element;
+ var url = $(element).attr('url');
+ var method = $(element).attr('method');
+ var button = $(element).find('button');
+ var reload = $(element).attr('reload');
+ var redirect = $(element).attr('redirect');
+ var input = $(element).find('input');
+ var formData = new FormData();
+ $.each(input, function (index, item) {
+ var filed = $(item).attr('name');
+ var val = $.trim($(item).val());
+ formData.append(filed, val);
+ });
+ button.click(function () {
+ ajaxBox();
+ });
+
+ // tijiao
+ function ajaxBox() {
+ fetch(url, {method: method, mode: 'cors', body: formData}).then(function (res) {
+ res.json().then(function (data) {
+ if (data.status === 1) {
+ $(element).find('span.success').text(data.msg).show();
+ if (redirect) {
+ window.top.location.href = redirect;
+ }
+ if (reload === 'true') {
+ window.top.location.reload();
+ }
+ } else {
+ $(element).find('span.error').text(data.msg).show();
+ }
+ });
+ }).catch(function (e) {
+ });
+ }
+ };
+ return customElement;
+});
diff --git a/src/mip-258-form-btn/package.json b/src/mip-258-form-btn/package.json
new file mode 100644
index 000000000..99a1851f7
--- /dev/null
+++ b/src/mip-258-form-btn/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "mip-258-form-btn",
+ "version": "1.0.0",
+ "description":"按钮ajax请求。",
+ "author": {
+ "name": "chen",
+ "email": "chenweilin@258c.com"
+ },
+ "engines": {
+ "mip": ">=1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/src/mip-258-form1/README.md b/src/mip-258-form1/README.md
new file mode 100644
index 000000000..7e084d40a
--- /dev/null
+++ b/src/mip-258-form1/README.md
@@ -0,0 +1,113 @@
+# mip-258-form1
+
+mip-258-form1 表单组件
+
+标题|内容
+----|----
+类型|通用
+支持布局|fixed
+所需脚本|https://c.mipcdn.com/static/v1/mip-258-form1/mip-258-form1.js
+
+## 示例
+### 基本使用
+
+```html
+
+
+ 获取验证码
+ 59秒后重新获取
+ 请输入正确的电话
+
+ 年龄不能为空
+
+
+ {{aaa}}
+
+
+
+
+ {{failinfo}}
+
+
+
+
+ Error!.
+
+
+
+
+```
+## 属性
+
+### method
+
+说明:表单提交方法
+必选项:是
+
+### controlId
+
+说明:需要控制的id
+必选项:否
+
+### from
+
+说明:来自那张表单
+必选项:否
+
+### url
+
+说明:必须是 HTTP(S) 或 // 开头的地址
+必选项: 是
+
+### validatetarget
+
+说明: 验证提示对应 tag,用于对应错误时的提示显示元素的查找
+必选项:否
+
+### validatetype
+
+说明:验证类型, 用于支持简单的验证。目前提供 `email`, `phone`, `idcar`, `custom`。当为 `custom` 时则需要填写 `validatereg`
+必选项:否
+
+### validatereg
+
+说明: 自定义验证,补充站长个性化的验证规则。如果 `validatetype` 为 `custom` 时需填写相应验证规则
+必选项:否
+
+### fetch-url
+
+说明: 有此属性则可以开启异步请求数据逻辑,组件会并根据数据返回状态来按`submit-success`,`submit-error`块中的模板刷新局部信息。
+需要注意的几个点:
+
+- 方法支持。
+- 请求结果请返回 JSON 对象。
+- 数据状态只有在成功(2xx)的时候触发 `submit-success` 的逻辑,其他的均触发 `submit-error` 逻辑。
+
+必选项:否
+
+### pid
+
+说明: 用来绑定产品id
+必选项: 否
+
+### cid
+
+说明: 用来绑定公司id
+必选项: 否
+
+- 方法支持。
+- 请求结果请返回 JSON 对象。
+- 数据状态只有在成功(2xx)的时候触发 `submit-success` 的逻辑,其他的均触发 `submit-error` 逻辑。
+
+必选项:否
+
+### on
+
+说明: 添加事件清空表单
+必选项: 否
+
+
+## 注意事项
+
+1. 表单提交方法如果为 `post`,应使用 HTTPS 地址。避免 MIP-Cache HTTPS 环境提交到 HTTP,导致浏览器报错。
+2. 使用 fetch 功能时,请求使用 cors 时不能配置为 *。
\ No newline at end of file
diff --git a/src/mip-258-form1/mip-258-form1-fn.js b/src/mip-258-form1/mip-258-form1-fn.js
new file mode 100644
index 000000000..297267c44
--- /dev/null
+++ b/src/mip-258-form1/mip-258-form1-fn.js
@@ -0,0 +1,342 @@
+/**
+ * @file mip-form-fn.js
+ * @description mip-form函数
+ * @author miper
+ */
+
+define(function (require) {
+ var templates = require('templates');
+ var util = require('util');
+ var viewer = require('viewer');
+ var $ = require('zepto');
+ var windowInIframe = viewer.isIframed;
+ var evt;
+ var REGS = {
+ EMAIL: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
+ PHONE: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/,
+ IDCAR: /^\d{15}|\d{18}$/
+ };
+ return {
+
+ /**
+ * 处理fetch请求逻辑
+ *
+ * @param {string} url 请求url
+ */
+ fetchUrl: function (url) {
+ var me = this;
+ util.css([me.successEle, me.failEle, me.errorEle], {display: 'none'});
+ var fetchData = {
+ method: me.method,
+ credentials: 'include'
+ };
+ if (me.method === 'POST') {
+ var formD = me.ele.querySelector('form');
+ var data = $(formD).serializeArray();
+ if (formD) {
+ fetchData = util.fn.extend({}, fetchData, {
+ body: new FormData(formD)
+ });
+ }
+ }
+
+ // 数据请求处理
+ fetch(url, fetchData).then(function (res) {
+ if (res.ok) {
+ res.json().then(function (data) {
+ if (data.status === 1) {
+ util.css(me.successEle, {display: 'block'});
+ me.renderTpl(me.successEle, {successinfo: data.info});
+ me.submitSuccessHandle();
+ }
+ if (data.status === -1) {
+ util.css(me.failEle, {display: 'block'});
+ me.renderTpl(me.failEle, {failinfo: data.info});
+ me.submitFailHandle();
+ }
+ }).catch(function (err) {
+ me.fetchReject(err);
+ });
+ }
+ else {
+ me.submitErrorHandle();
+ me.fetchReject({});
+ }
+ }).catch(function (err) {
+ me.submitErrorHandle();
+ me.fetchReject(err);
+ });
+ },
+
+ /**
+ * fetch出错逻辑处理
+ *
+ * @param {Object} err 错误对象
+ */
+ fetchReject: function (err) {
+ var me = this;
+ util.css(me.errorEle, {display: 'block'});
+ me.renderTpl(me.errorEle, err);
+ },
+
+ /**
+ * fetch成功动作处理
+ *
+ * @param {Object} dom 结构
+ */
+ action: function (dom) {
+ var from = $(dom).attr('from');
+ var actionDom = $(dom).attr('controlId');
+ if (from === 'comment') {
+ setTimeout(function () {
+ window.top.location.href = window.location.href;
+ }, 2000);
+ }
+ $(actionDom).addClass('mip-active');
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 模板父节点
+ * @param {Object} data 模板渲染数据
+ */
+ renderTpl: function (ele, data) {
+ var me = this;
+ templates.render(ele, data).then(function (html) {
+ var tempTarget = me.tempHTML(ele);
+ tempTarget.innerHTML = html;
+ });
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 渲染后模板父节点
+ * @return {HTMLElement} target 新建DOM节点
+ */
+ tempHTML: function (ele) {
+ ele = ele || document;
+ var target = ele.querySelector('[mip-mustache-rendered]');
+ if (!target) {
+ target = util.dom.create('
');
+ ele.appendChild(target);
+ }
+ return target;
+ },
+
+ /**
+ * createDom 创建 form 节点
+ *
+ * @param {HTMLElement} element 组件节点
+ */
+ createDom: function (element) {
+ var me = this;
+ var url = element.getAttribute('url');
+ var target = element.getAttribute('target');
+ var form = document.createElement('form');
+ var method = (element.getAttribute('method') || 'GET').toUpperCase();
+ form.action = url;
+ form.method = method;
+ target = target ? target : '_blank';
+ form.target = viewer.isIframed && target !== '_blank' ? '_top' : target;
+ element.appendChild(form);
+ util.dom.insert(form, element.children);
+
+ // 按钮提交
+ var curEles = element.querySelectorAll('form');
+ Array.prototype.forEach.call(curEles, function (item) {
+ item.addEventListener('submit', function (event) {
+ event.preventDefault();
+ evt = event;
+ me.onSubmit(element, event);
+ });
+ });
+
+ // 部分浏览器回车不触发submit,
+ element.addEventListener('keydown', function (event) {
+ if (event.keyCode === 13) {
+
+ // 为了使余下浏览器不多次触发submit, 使用prevent
+ evt = event;
+ event.preventDefault();
+ me.onSubmit(this);
+ }
+ }, false);
+ },
+
+ /**
+ * 事件通信
+ *
+ * @description 在 input focus 或 blur 时向iframe外层文档发送数据,iframe外层文档返回设置预览头部为 absolute
+ * @param {Object} event 事件对象
+ */
+ sendFormMessage: function (event) {
+ if (windowInIframe) {
+ // mip_video_jump 为写在外层的承接方法
+ viewer.sendMessage('input-' + event, {});
+ }
+ },
+
+ /**
+ * 事件发送处理
+ *
+ * @description 给 input 绑定事件,向 SF 发送数据,为了解决 ios 的 UC 浏览器在iframe外层文档悬浮头部 fixed 位置混乱问题
+ * @param {HTMLElement} element mip 组件标签
+ */
+ initMessageEvents: function (element) {
+ var me = this;
+ var inputAll = element.querySelectorAll('input');
+ Array.prototype.forEach.call(inputAll, function (item, index) {
+ item.addEventListener('focus', function () {
+ me.sendFormMessage('focus');
+ }, false);
+
+ item.addEventListener('blur', function () {
+ me.sendFormMessage('blur');
+ }, false);
+ });
+ },
+
+ /**
+ * 文案格式验证
+ *
+ * @param {string} type 验证类型
+ * @param {string} value 需要验证的文案
+ * @return {boolean} 是否符合自定义校验
+ */
+ verification: function (type, value) {
+ return (type === 'must') ? !(value === '') : REGS[type.toUpperCase()].test(value);
+ },
+
+ /**
+ * 点击提交按钮事件处理函数
+ *
+ * @param {HTMLElement} element form节点
+ */
+ onSubmit: function (element) {
+ var me = this;
+ var preventSubmit = false;
+ var inputs = element.querySelectorAll('input, textarea, select');
+ var url = element.getAttribute('url') || '';
+ var getUrl = url.toLowerCase();
+ var isHttp = getUrl.match('http://');
+ var valueJson = '';
+ var hasFetch = element.getAttribute('fetch-url') || '';
+ me.method = (element.getAttribute('method') || 'GET').toUpperCase();
+ var isGet = me.method === 'GET';
+
+ this.ele = element;
+ this.successEle = element.querySelector('[submit-success]');
+ this.failEle = element.querySelector('[submit-fail]');
+ this.errorEle = element.querySelector('[submit-error]');
+ // 执行提交句柄
+ me.submitHandle();
+ // 校验输入内容是否合法
+ Array.prototype.forEach.call(inputs, function (item) {
+ var type = item.getAttribute('validatetype');
+ var target = item.getAttribute('validatetarget');
+ var regval = item.getAttribute('validatereg');
+ var value = item.value;
+ var reg;
+
+ if (item.type === 'submit') {
+ return;
+ }
+ else if (item.type === 'checkbox' || item.type === 'radio') {
+ value = item.checked ? item.value : '';
+ }
+
+ valueJson += '&' + item.name + '=' + value;
+ if (type) {
+ if (regval) {
+ reg = value === '' ? false : (new RegExp(regval)).test(value);
+ }
+ else {
+ reg = me.verification(type, value);
+ }
+ util.css(element.querySelectorAll('div[target="' + target + '"]'),
+ {display: (!reg ? 'block' : 'none')});
+ preventSubmit = !reg ? true : preventSubmit;
+ }
+ });
+
+ if (preventSubmit) {
+ return;
+ }
+
+ // 在iframe下使用mibm-jumplink,跳转显示手百框。 http-GET请求交给外层跳转
+ if (window.parent !== window && isHttp && isGet) {
+ var messageUrl = '';
+ if (getUrl.match('\\?')) {
+ // eg. getUrl == 'http://www.mipengine.org?we=123'
+ messageUrl = getUrl + valueJson;
+ }
+ else {
+ // eg. getUrl == 'http://www.mipengine.org'
+ valueJson = valueJson.substring(1);
+ messageUrl = getUrl + '?' + valueJson;
+ }
+ var message = {
+ event: 'mibm-jumplink',
+ data: {
+ url: messageUrl
+ }
+ };
+ window.parent.postMessage(message, '*');
+ }
+ else if (hasFetch.trim()) {
+ me.fetchUrl(hasFetch);
+ }
+ else {
+ // https请求 或 post请求 或 非iframe下不做处理
+ element.getElementsByTagName('form')[0].submit();
+ }
+ },
+
+ /**
+ * 提交时的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitHandle: function () {
+ viewer.eventAction.execute('submit', evt.target, evt);
+ },
+
+ /**
+ * 提交成功调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitSuccessHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('submitSuccess', evt.target, evt);
+ },
+
+ /**
+ * 提交成功调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitFailHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('submitFail', evt.target, evt);
+ },
+
+ /**
+ * 提交失败调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitErrorHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('submitError', evt.target, evt);
+ }
+ };
+});
diff --git a/src/mip-258-form1/mip-258-form1.css b/src/mip-258-form1/mip-258-form1.css
new file mode 100644
index 000000000..7e461c5ea
--- /dev/null
+++ b/src/mip-258-form1/mip-258-form1.css
@@ -0,0 +1 @@
+mip-258-form1{position:relative}mip-258-form1 .btnCode{display:block;padding:10px;color:#fff}mip-258-form1 #mip-form-cross{position:absolute;display:block;padding:6px;width:20px;height:20px;right:0;background:url(//m.baidu.com/static/search/clear.png) no-repeat center;z-index:100;background-size:100% 100%;background-origin:content-box;-webkit-tap-highlight-color:rgba(0,0,0,.4);tap-highlight-color:rgba(0,0,0,.4)}mip-258-form1 input,mip-258-form1 textarea,mip-258-form1 select{border:1px solid #f1f1f1;padding:6px;display:block;box-sizing:border-box;-webkit-box-sizing:border-box;resize:none;font-size:16px}mip-258-form1 input[type=text],mip-258-form1 input[type=input],mip-258-form1 input[type=datetime],mip-258-form1 input[type=email],mip-258-form1 input[type=number],mip-258-form1 input[type=tel],mip-258-form1 input[type=url]{padding-right:30px}mip-258-form1 form{position:relative}mip-258-form1 input[type=radio]{display:inline}mip-258-form1 label{display:block}mip-258-form1 .error{display:none;color:#ec1f5c;font-size:12px;text-align:left;line-height:22px;padding:0 10% 0 3%}mip-258-form1 .error[mip-mustache-rendered]{display:block}mip-258-form1 input[type=submit]{border:1px solid #f1f1f1;border-radius:5px;color:#333;background:#d8d7d7}mip-258-form1 [submit-success],mip-258-form1 [submit-error]{display:none}
\ No newline at end of file
diff --git a/src/mip-258-form1/mip-258-form1.js b/src/mip-258-form1/mip-258-form1.js
new file mode 100644
index 000000000..14cc1fc1c
--- /dev/null
+++ b/src/mip-258-form1/mip-258-form1.js
@@ -0,0 +1,82 @@
+/**
+ * @file mip-258-form 组件
+ * @author
+ */
+
+define(function (require) {
+ var customElement = require('customElement').create();
+ var form = require('./mip-258-form1-fn');
+ var $ = require('zepto');
+
+ customElement.prototype.build = function () {
+ var element = this.element;
+ var url = $(element).attr('fetch-url');
+
+
+ // 获取验证码事件
+
+ $(element).find('.btnCode').click(function () {
+ var url = $(this).attr('btn-url');
+ var mobile = $(element).find('.inquiryMobile').val();
+ getInquiryMobileCode(mobile, 60, url);
+ });
+
+ function getInquiryMobileCode(mobile, second, url) {
+ if (mobile === '' || isNaN(mobile)) {
+ alert('请输入手机号码');
+ return false;
+ }
+ else if (mobile.length !== 11) {
+ alert('请输入正确的手机号码');
+ return false;
+ }
+ $(element).find('.btnCode').hide();
+ if (second <= 1) {
+ $(element).find('.waitInquiry').html(59);
+ $(element).find('.getInquiryCode').show();
+ $(element).find('.waitInquiryCode').addClass('hide');
+ $(element).find('.btnCode').show();
+ return true;
+ }
+
+ if (second >= 60) {
+ $.ajax({
+ type: 'POST',
+ url: url,
+ data: 'mobile=' + mobile,
+ async: true,
+ success: function (data) {
+ alert(data.info);
+ },
+ headers: {
+ 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
+ }
+ });
+ $(element).find('.getInquiryCode').hide();
+ $(element).find('.waitInquiryCode').removeClass('hide');
+ }
+ second--;
+ $(element).find('.waitInquiry').html(second);
+ setTimeout(function () {
+ getInquiryMobileCode(mobile, second);
+ }, 1000);
+ }
+ form.createDom(element);
+ form.initMessageEvents(element);
+ };
+ customElement.prototype.firstInviewCallback = function () {
+ this.addEventAction('reload', function (event, str) {
+ // 页面刷新操作
+ str = str ? 500 : parseInt(str, 10);
+ setTimeout(function () {
+ window.top.location.reload();
+ }, str);
+ });
+
+ this.addEventAction('reset', function (event, str) {
+ // 页面刷新操作
+ event.target.reset();
+ });
+ };
+ return customElement;
+});
diff --git a/src/mip-258-form1/mip-258-form1.less b/src/mip-258-form1/mip-258-form1.less
new file mode 100644
index 000000000..6d1aa0f97
--- /dev/null
+++ b/src/mip-258-form1/mip-258-form1.less
@@ -0,0 +1,74 @@
+mip-258-form1 {
+ position: relative;
+ .btnCode {
+ display: block;
+ padding: 10px;
+ color: #fff;
+ }
+ #mip-form-cross {
+ position: absolute;
+ display: block;
+ padding: 6px;
+ width: 20px;
+ height: 20px;
+ right: 0;
+ background: url('//m.baidu.com/static/search/clear.png') no-repeat center;
+ z-index: 100;
+ background-size: 100% 100%;
+ background-origin: content-box;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.4);
+ tap-highlight-color: rgba(0, 0, 0, 0.4)
+ }
+ input,
+ textarea,
+ select {
+ border: 1px solid #f1f1f1;
+ padding: 6px;
+ display: block;
+ box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ resize: none;
+ font-size: 16px;
+ }
+ input[type='text'],
+ input[type='input'],
+ input[type='datetime'],
+ input[type='email'],
+ input[type='number'],
+ input[type='tel'],
+ input[type='url'] {
+ padding-right: 30px;
+ }
+ form {
+ position: relative;
+ }
+ input[type='radio'] {
+ display: inline
+ }
+ label {
+ display: block
+ }
+ .error {
+ display: none;
+ color: #ec1f5c;
+ font-size: 12px;
+ text-align: left;
+ line-height: 22px;
+ padding: 0 10% 0 3%
+ }
+ .error[mip-mustache-rendered] {
+ display: block;
+ }
+ input[type='submit'] {
+ border: 1px solid #f1f1f1;
+ border-radius: 5px;
+ color: #333;
+ background: #d8d7d7;
+ }
+ [submit-success],
+ [submit-fail],
+ [submit-error] {
+ display: none;
+ }
+}
+
diff --git a/src/mip-258-form1/package.json b/src/mip-258-form1/package.json
new file mode 100644
index 000000000..4862ab68c
--- /dev/null
+++ b/src/mip-258-form1/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "mip-258-form1",
+ "version": "1.0.0",
+ "description": "258表单提交",
+ "contributors": [
+ {
+ "name": "teemor",
+ "email": "232957726@qq.com"
+ }
+ ],
+ "engines": {
+ "mip": ">=1.1.0"
+ }
+}
diff --git a/src/mip-258-tool/README.md b/src/mip-258-tool/README.md
new file mode 100644
index 000000000..d6ad7bac0
--- /dev/null
+++ b/src/mip-258-tool/README.md
@@ -0,0 +1,31 @@
+# mip-258-tool
+
+ajax请求
+
+标题|内容
+----|----
+类型|通用
+支持布局|N/S
+## 示例
+
+### 基本使用
+
+```html
+
+
+```
+### on
+
+说明:goback事件对应window.history.back()事件
+reload(100)事件对应window.reload()事件,传入毫秒数,用于刷新等待
+alert()事件对应window.alert()事件
+redirect('url,time_wait') 对应window.location.href事件
+必选项: 否
+
+
+
+
+
+
+
+
diff --git a/src/mip-258-tool/mip-258-tool.js b/src/mip-258-tool/mip-258-tool.js
new file mode 100644
index 000000000..f60f3930d
--- /dev/null
+++ b/src/mip-258-tool/mip-258-tool.js
@@ -0,0 +1,52 @@
+
+/**
+ * @file mip-ajax-button 组件
+ *
+ * @author chen
+ * @time 2018.8.21
+ */
+define(function (require) {
+ var customElement = require('customElement').create();
+
+ customElement.prototype.build = function () {
+
+ };
+
+ customElement.prototype.firstInviewCallback = function (event, str) {
+
+ // 添加页面刷新事件
+ this.addEventAction('reload', function (event, str) {
+ str = str ? 500 : parseInt(str, 10);
+ setTimeout(function () {
+ window.top.location.reload();
+ }, str);
+ });
+
+ // 添加alert提示事件
+ this.addEventAction('alert', function (event, str) {
+ window.top.alert(str);
+ });
+
+ // 添加后退事件
+ this.addEventAction('goback', function (event, str) {
+ if (window.top.history.length === 0) {
+ window.top.location.href = str;
+ }
+ window.top.history.back();
+ });
+
+ // 添加重定向事件
+ this.addEventAction('redirect', function (event, url) {
+ var params = url.split(',');
+ url = params[0];
+ var timeWait = params[1] ? Number.parseInt(params[1], 10) : 0;
+
+ if (url) {
+ setTimeout(function () {
+ window.top.location.href = url;
+ }, timeWait);
+ }
+ });
+ };
+ return customElement;
+});
diff --git a/src/mip-258-tool/package.json b/src/mip-258-tool/package.json
new file mode 100644
index 000000000..e7424602d
--- /dev/null
+++ b/src/mip-258-tool/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "mip-258-tool",
+ "version": "1.0.0",
+ "description":"简单的js事件工具。",
+ "author": {
+ "name": "chen",
+ "email": "chenweilin@258c.com"
+ },
+ "engines": {
+ "mip": ">=1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/src/mip-code-button/README.md b/src/mip-code-button/README.md
new file mode 100644
index 000000000..9f665e509
--- /dev/null
+++ b/src/mip-code-button/README.md
@@ -0,0 +1,47 @@
+# mip-code-button
+
+标题|内容
+----|----
+类型|通用
+支持布局|N/S
+## 示例
+
+### 基本使用
+
+```html
+
+
+
+```
+### url
+
+说明: 必须是 HTTP(S) 或 // 开头的地址
+必选项: 是
+
+### fetch-button
+
+说明:提交触发选择器属性
+必选项: 是
+
+### time-count
+说明: 时间倒计时选择器属性
+必选项: 是
+注意: 时间数值必须包裹在firstElementChild里面
+
+### timeout
+说明 : 倒计时超时时间
+默认值: 60
+必选项: 否
+
+### fail-info-id
+说明 : 获取失败错误信息提示元素
+必选项: 否
+
+
+
+
+
+
diff --git a/src/mip-code-button/mip-code-button-fn.js b/src/mip-code-button/mip-code-button-fn.js
new file mode 100644
index 000000000..a4b190aa8
--- /dev/null
+++ b/src/mip-code-button/mip-code-button-fn.js
@@ -0,0 +1,297 @@
+/**
+ * @file mip-code-button.js
+ * @description mip-form函数
+ * @author chen
+ */
+
+define(function (require) {
+ var templates = require('templates');
+ var util = require('util');
+ var viewer = require('viewer');
+ var evt;
+ return {
+
+ /**
+ * 处理fetch请求逻辑
+ *
+ * @param {string} url 请求url
+ */
+ fetchUrl: function (url) {
+ var me = this;
+ var data = new FormData();
+
+ for (var index in me.fetchData) {
+ if (me.fetchData.hasOwnProperty(index)) {
+ data.append(index, me.fetchData[index]);
+ }
+ }
+ // 获取CSRF-TOKEN
+ var tokenDom = document.querySelector('meta[name="csrf-token"]');
+ if (tokenDom) {
+ var token = tokenDom.getAttribute('content');
+ }
+
+ var options = {
+ method: 'POST',
+ credentials: 'include',
+ body: data,
+ // 使用Accept,用来判断异步
+ headers: new Headers({
+ 'Accept': 'application/json',
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-CSRF-TOKEN': token ? token : ''
+ })
+ };
+ // 判断域名,是否跨域.测试使用
+ var localhost = location.host;
+ if (url.indexOf(localhost) === -1) {
+ options.mode = 'cors';
+ options.credentials = 'omit';
+ }
+
+ // 数据请求处理
+ fetch(url, options).then(function (res) {
+ if (res.ok) {
+ return res.json();
+ }
+ }).then(function (response) {
+ var status = parseInt(response.status, 10);
+ if (status === 1) {
+
+ me.successHandle();
+ } else {
+ // 处理错误提示
+ me.showFailInfo(response.info);
+ me.failHandle();
+ }
+
+ }).catch(function (err) {
+
+ me.errorHandle();
+ // me.fetchReject(err);
+ });
+ },
+ hideFailInfo: function () {
+ if (this.failInfoId) {
+ var failInfoEl = document.getElementById(this.failInfoId);
+ if (failInfoEl) {
+ util.css(failInfoEl, {display: 'none'});
+ }
+ }
+ },
+ showFailInfo: function (info) {
+ if (this.failInfoId) {
+ var failInfoEl = document.getElementById(this.failInfoId);
+ if (failInfoEl) {
+ failInfoEl.innerHTML = info;
+ util.css(failInfoEl, {display: 'block'});
+ }
+ }
+ },
+ setFetchData: function (key, val) {
+ if (!this.fetchData) {
+ this.fetchData = {};
+ }
+ this.fetchData[key] = val;
+ },
+
+ /**
+ * fetch出错逻辑处理
+ *
+ * @param {Object} err 错误对象
+ */
+ fetchReject: function (err) {
+ var me = this;
+ util.css(me.errorEle, {display: 'block'});
+ me.renderTpl(me.errorEle, err);
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 模板父节点
+ * @param {Object} data 模板渲染数据
+ */
+ renderTpl: function (ele, data) {
+ var me = this;
+ templates.render(ele, data).then(function (html) {
+ var tempTarget = me.tempHTML(ele);
+ tempTarget.innerHTML = html;
+ });
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 渲染后模板父节点
+ * @return {HTMLElement} target 新建DOM节点
+ */
+
+ tempHTML: function (ele) {
+ ele = ele || document;
+ var target = ele.querySelector('[mip-mustache-rendered]');
+ if (!target) {
+ target = util.dom.create('');
+ ele.appendChild(target);
+ }
+ return target;
+ },
+
+ /**
+ * createDom 创建 form 节点
+ *
+ * @param {HTMLElement} element 组件节点
+ */
+ createDom: function (element) {
+ var me = this;
+ me.fetchData = {};
+ me.url = element.getAttribute('url');
+
+ me.method = (element.getAttribute('method') || 'GET').toUpperCase();
+
+ me.failInfoId = element.getAttribute('fail-info-id');
+ me.hideFailInfo();
+ var submitBtn = element.querySelector('[fetch-button]');
+ // 添加点击事件监听
+ submitBtn.addEventListener('click', function (event) {
+ evt = event;
+ me.onSubmit(element);
+ });
+ },
+
+
+ /**
+ * 点击提交按钮事件处理函数
+ *
+ * @param {HTMLElement} element form节点
+ */
+ onSubmit: function (element) {
+ var me = this;
+ me.hideFailInfo();
+ // 定时器已存在不允许再次触发点击
+ if (me.timer) {
+ return;
+ }
+ var url = element.getAttribute('url') || '';
+ if (!url) {
+ return;
+ }
+
+ var mobile = this.fetchData.mobile;
+ var reg = mobile && (/^1[3578]\d{9}$/.test(mobile));
+ // 手机验证通过
+ if (!reg) {
+ me.invalidHandle('mobile');
+ return;
+ }
+ else {
+ me.validHandle('mobile');
+ }
+
+ // 获取时间限制
+ var timeout = element.getAttribute('timeout') || 60;
+ // 开始计时
+ me.timeEle = element.querySelector('[time-count]');
+ me.submitBtn = element.querySelector('[fetch-button]');
+
+ // 设置初始值,然后再show
+ me.timeEle.firstElementChild.innerHTML = timeout;
+ util.css(me.submitBtn, {display: 'none'});
+ util.css(me.timeEle, {display: 'block'});
+
+ me.timer = setInterval(function () {
+ me.timeEle.firstElementChild.innerHTML = timeout--;
+ if (timeout <= 0) {
+ me.clearTimer();
+ }
+ }, 1000);
+
+ this.ele = element;
+
+ // 执行数据请求
+ this.fetchUrl(url);
+ },
+
+ /**
+ * 清除定时器
+ *
+ * @param {HTMLElement} element form节点
+ */
+ clearTimer: function () {
+
+ if (this.timer) {
+ clearInterval(this.timer);
+ util.css(this.submitBtn, {display: 'block'});
+ util.css(this.timeEle, {display: 'none'});
+ this.timer = null;
+ }
+ },
+
+ /**
+ * 输出表单错误信息
+ * @param {HTMLElement} element form节点
+ */
+ invalidHandle: function () {
+ console.log('mobile字段格式不正确');
+ viewer.eventAction.execute('invalid', evt.target, evt);
+ },
+
+ /**
+ * 隐藏表单错误信息
+ * @param {HTMLElement} element form节点
+ */
+ validHandle: function () {
+ console.log('mobile字段格式验证通过');
+ viewer.eventAction.execute('valid', evt.target, evt);
+ },
+
+
+ /**
+ * 提交时的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitHandle: function () {
+ viewer.eventAction.execute('submit', evt.target, evt);
+ },
+
+ /**
+ * 提交成功调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ successHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('success', evt.target, evt);
+ },
+
+ /**
+ * 提交成功,但处理结果为失败,调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ failHandle: function () {
+
+ if (!evt) {
+ return;
+ }
+ this.clearTimer();
+ viewer.eventAction.execute('fail', evt.target, evt);
+ },
+
+
+ /**
+ * 提交失败调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ errorHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('error', evt.target, evt);
+ }
+ };
+});
diff --git a/src/mip-code-button/mip-code-button.js b/src/mip-code-button/mip-code-button.js
new file mode 100644
index 000000000..f851a046d
--- /dev/null
+++ b/src/mip-code-button/mip-code-button.js
@@ -0,0 +1,27 @@
+/**
+ * @file mip-code-button 组件
+ *
+ * @author chen
+ * @time 2018.8.28
+ */
+
+define(function (require) {
+ var customElement = require('customElement').create();
+ var initJs = require('./mip-code-button-fn');
+ customElement.prototype.build = function () {
+ var element = this.element;
+ // 初始化
+ initJs.createDom(element);
+ };
+
+ // 缩进不能用tab,就这么喜欢标新立异?
+ customElement.prototype.firstInviewCallback = function () {
+ // 添加绑定手机号事件
+ this.addEventAction('bind', function (event, str) {
+ if (event.target.tagName === 'INPUT') {
+ initJs.setFetchData(str, event.target.value.trim());
+ }
+ });
+ };
+ return customElement;
+});
diff --git a/src/mip-code-button/mip-code-button.less b/src/mip-code-button/mip-code-button.less
new file mode 100644
index 000000000..565700003
--- /dev/null
+++ b/src/mip-code-button/mip-code-button.less
@@ -0,0 +1,11 @@
+mip-code-button {
+ position: relative;
+ .btnCode {
+ display: block;
+ padding: 10px;
+ color: #fff;
+ }
+ [time-count] {
+ display: none;
+ }
+}
\ No newline at end of file
diff --git a/src/mip-code-button/package.json b/src/mip-code-button/package.json
new file mode 100644
index 000000000..9e2f78455
--- /dev/null
+++ b/src/mip-code-button/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "mip-code-button",
+ "version": "1.0.0",
+ "description":"验证码获取。",
+ "author": {
+ "name": "chen",
+ "email": "chenweilin@258c.com"
+ },
+ "engines": {
+ "mip": ">=1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/src/mip-product-form/README.md b/src/mip-product-form/README.md
new file mode 100644
index 000000000..b8ed6339d
--- /dev/null
+++ b/src/mip-product-form/README.md
@@ -0,0 +1,70 @@
+# mip-product-form
+
+fetch请求
+
+标题|内容
+----|----
+类型|通用
+支持布局|N/S
+## 示例
+
+### 基本使用
+
+```html
+
+
+
+
+
+
+ {{failmsg}}
+
+
+
+
+```
+### url
+
+说明:必须是 HTTP(S) 或 // 开头的地址
+必选项: 是
+
+### method
+说明:请求方法 ,默认post
+必选项: 无
+
+### on
+
+说明:可以被触发的事件
+必选项: 否
+服务端返回的数据格式 :
+{
+ status: 1,
+ msg: '',
+ data: [],
+}
+status -1 代表服务器响应成功,但处理结果为失败。可以触发使用fail事件
+status 1 代表服务器响应成功,处理结果为成功。可以触发使用success事件
+若服务器异常,则触发error事件
+
+
+
+
+
+
diff --git a/src/mip-product-form/mip-product-form-fn.js b/src/mip-product-form/mip-product-form-fn.js
new file mode 100644
index 000000000..e5f104cbb
--- /dev/null
+++ b/src/mip-product-form/mip-product-form-fn.js
@@ -0,0 +1,337 @@
+/**
+ * @file mip-form-fn.js
+ * @description mip-form函数
+ * @author chen
+ */
+
+define(function (require) {
+ var templates = require('templates');
+ var util = require('util');
+ var viewer = require('viewer');
+ var windowInIframe = viewer.isIframed;
+ var evt;
+ var REGS = {
+ EMAIL: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
+ PHONE: /^1\d{10}$/,
+ IDCAR: /^\d{15}|\d{18}$/
+ };
+
+ return {
+
+ /**
+ * 处理fetch请求逻辑
+ *
+ * @param {string} url 请求url
+ */
+ fetchUrl: function (url) {
+ var me = this;
+ util.css([me.successEle, me.failElem, me.errorEle], {display: 'none'});
+ var formD = me.ele.querySelector('form');
+ var data = new FormData(formD);
+ var options = {
+ method: 'POST',
+ body: data,
+ credentials: 'include',
+ // 使用Accept,用来判断异步
+ headers: {
+ 'Accept': 'application/json'
+ }
+ };
+ // 判断域名,是否跨域.测试使用
+ var localhost = location.host;
+ if (url.indexOf(localhost) === -1) {
+ options.mode = 'cors';
+ options.credentials = 'omit';
+ }
+ // 数据请求处理
+ fetch(url, options).then(function (res) {
+ if (res.ok) {
+ return res.json();
+ }
+ }).then(function (response) {
+
+ if (response.status === 1) {
+ me.successHandle();
+ }
+ if (response.status === -1) {
+ util.css(me.failEle, {display: 'block'});
+ me.renderTpl(me.failEle, {failinfo: response.info});
+ me.failHandle();
+ }
+ // 表单验证不通过
+ if (response.status === -2) {
+
+ me.invalidHandle();
+ }
+ }).catch(function (err) {
+
+ me.errorHandle();
+ me.fetchReject(err);
+ });
+ },
+
+ /**
+ * trim 字符串前后空格
+ * @param {string} str 需要trim的字符串
+ * @return {string} 过滤完成的字符串
+ */
+ trim: function (str) {
+ return str.replace(/(^\s*)|(\s*$)/g, '');
+ },
+
+ /**
+ * fetch出错逻辑处理
+ *
+ * @param {Object} err 错误对象
+ */
+ fetchReject: function (err) {
+ var me = this;
+ util.css(me.errorEle, {display: 'block'});
+ me.renderTpl(me.errorEle, err);
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 模板父节点
+ * @param {Object} data 模板渲染数据
+ */
+ renderTpl: function (ele, data) {
+ var me = this;
+ templates.render(ele, data).then(function (html) {
+ var tempTarget = me.tempHTML(ele);
+ tempTarget.innerHTML = html;
+ });
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 渲染后模板父节点
+ * @return {HTMLElement} target 新建DOM节点
+ */
+
+ tempHTML: function (ele) {
+ ele = ele || document;
+ var target = ele.querySelector('[mip-mustache-rendered]');
+ if (!target) {
+ target = util.dom.create('');
+ ele.appendChild(target);
+ }
+ return target;
+ },
+
+ /**
+ * createDom 创建 form 节点
+ *
+ * @param {HTMLElement} element 组件节点
+ */
+ createDom: function (element) {
+ var me = this;
+ var url = element.getAttribute('url');
+ var target = element.getAttribute('target');
+ var form = document.createElement('form');
+ var method = (element.getAttribute('method') || 'GET').toUpperCase();
+ form.action = url;
+ form.method = method;
+ target = target ? target : '_blank';
+ form.target = viewer.isIframed && target !== '_blank' ? '_top' : target;
+ element.appendChild(form);
+ util.dom.insert(form, element.children);
+
+ // 按钮提交
+ var curEles = element.querySelectorAll('form');
+ Array.prototype.forEach.call(curEles, function (item) {
+ item.addEventListener('submit', function (event) {
+ event.preventDefault();
+ evt = event;
+ me.onSubmit(element, event);
+ });
+ });
+
+ // 部分浏览器回车不触发submit,
+ element.addEventListener('keydown', function (event) {
+ if (event.keyCode === 13) {
+ // 为了使余下浏览器不多次触发submit, 使用prevent
+ evt = event;
+ event.preventDefault();
+ me.onSubmit(this);
+ }
+ }, false);
+ },
+
+ /**
+ * 事件通信
+ *
+ * @description 在 input focus 或 blur 时向iframe外层文档发送数据,iframe外层文档返回设置预览头部为 absolute
+ * @param {Object} event 事件对象
+ */
+ sendFormMessage: function (event) {
+ if (windowInIframe) {
+ // mip_video_jump 为写在外层的承接方法
+ viewer.sendMessage('input-' + event, {});
+ }
+ },
+
+ /**
+ * 事件发送处理
+ *
+ * @description 给 input 绑定事件,向 SF 发送数据,为了解决 ios 的 UC 浏览器在iframe外层文档悬浮头部 fixed 位置混乱问题
+ * @param {HTMLElement} element mip 组件标签
+ */
+ initMessageEvents: function (element) {
+ var me = this;
+ var inputAll = element.querySelectorAll('input');
+ Array.prototype.forEach.call(inputAll, function (item, index) {
+ item.addEventListener('focus', function () {
+ me.sendFormMessage('focus');
+ }, false);
+
+ item.addEventListener('blur', function () {
+ me.sendFormMessage('blur');
+ }, false);
+ });
+ },
+
+ /**
+ * 文案格式验证
+ *
+ * @param {string} type 验证类型
+ * @param {string} value 需要验证的文案
+ * @return {boolean} 是否符合自定义校验
+ */
+ verification: function (type, value) {
+ return (type === 'must') ? !(value === '') : REGS[type.toUpperCase()].test(value);
+ },
+
+ /**
+ * 点击提交按钮事件处理函数
+ *
+ * @param {HTMLElement} element form节点
+ */
+ onSubmit: function (element) {
+ var me = this;
+ var preventSubmit = false;
+ var inputs = element.querySelectorAll('input, textarea, select');
+ var url = element.getAttribute('url') || '';
+ var getUrl = url.toLowerCase();
+ var isHttp = getUrl.match('http://');
+ var valueJson = '';
+ var hasFetch = element.getAttribute('fetch-url') || '';
+ me.method = (element.getAttribute('method') || 'GET').toUpperCase();
+ var isGet = me.method === 'GET';
+ this.ele = element;
+ this.successEle = element.querySelector('[submit-success]');
+ this.failEle = element.querySelector('[submit-fail]');
+ this.errorEle = element.querySelector('[submit-error]');
+ // 执行提交句柄
+ me.submitHandle();
+ // 校验输入内容是否合法
+ Array.prototype.forEach.call(inputs, function (item) {
+ var type = item.getAttribute('validatetype');
+ var target = item.getAttribute('validatetarget');
+ var regval = item.getAttribute('validatereg');
+ var value = item.value;
+ var reg;
+
+ if (item.type === 'submit') {
+ return;
+ }
+ else if (item.type === 'checkbox' || item.type === 'radio') {
+ value = item.checked ? item.value : '';
+ }
+
+ valueJson += '&' + item.name + '=' + value;
+ if (type) {
+ if (regval) {
+ reg = value === '' ? false : (new RegExp(regval)).test(value);
+ }
+ else {
+ reg = me.verification(type, value);
+ }
+ util.css(element.querySelectorAll('div[target="' + target + '"]'),
+ {display: (!reg ? 'block' : 'none')});
+ preventSubmit = !reg ? true : preventSubmit;
+ }
+ });
+
+ if (preventSubmit) {
+ return;
+ }
+
+ // 在iframe下使用mibm-jumplink,跳转显示手百框。 http-GET请求交给外层跳转
+ if (window.parent !== window && isHttp && isGet) {
+ var messageUrl = '';
+ if (getUrl.match('\\?')) {
+ // eg. getUrl == 'http://www.mipengine.org?we=123'
+ messageUrl = getUrl + valueJson;
+ }
+ else {
+ // eg. getUrl == 'http://www.mipengine.org'
+ valueJson = valueJson.substring(1);
+ messageUrl = getUrl + '?' + valueJson;
+ }
+ var message = {
+ event: 'mibm-jumplink',
+ data: {
+ url: messageUrl
+ }
+ };
+ window.parent.postMessage(message, '*');
+ }
+ else if (hasFetch.trim()) {
+ me.fetchUrl(hasFetch);
+ }
+ else {
+ // https请求 或 post请求 或 非iframe下不做处理
+ element.getElementsByTagName('form')[0].submit();
+ }
+ },
+
+ /**
+ * 提交时的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitHandle: function () {
+ viewer.eventAction.execute('submit', evt.target, evt);
+ },
+
+ /**
+ * 提交成功调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ successHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('success', evt.target, evt);
+ },
+
+ /**
+ * 提交成功,但处理结果为失败,调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ failHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('fail', evt.target, evt);
+ },
+
+
+ /**
+ * 提交失败调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ errorHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('error', evt.target, evt);
+ }
+ };
+});
diff --git a/src/mip-product-form/mip-product-form.js b/src/mip-product-form/mip-product-form.js
new file mode 100644
index 000000000..61da498ed
--- /dev/null
+++ b/src/mip-product-form/mip-product-form.js
@@ -0,0 +1,33 @@
+
+/**
+ * @file mip-button-form 组件
+ *
+ * @author chen
+ * @time 2018.8.21
+ */
+define(function (require) {
+ var customElement = require('customElement').create();
+ var form = require('./mip-product-form-fn');
+ customElement.prototype.build = function () {
+ var element = this.element;
+ form.createDom(element);
+
+
+ form.initMessageEvents(element);
+ };
+ customElement.prototype.firstInviewCallback = function () {
+ this.addEventAction('reload', function (event, str) {
+ // 页面刷新操作
+ str = str ? 500 : parseInt(str, 10);
+ setTimeout(function () {
+ window.top.location.reload();
+ }, str);
+ });
+
+ this.addEventAction('reset', function (event, str) {
+ // 页面刷新操作
+ event.target.reset();
+ });
+ };
+ return customElement;
+});
diff --git a/src/mip-product-form/mip-product-form.less b/src/mip-product-form/mip-product-form.less
new file mode 100644
index 000000000..651ea2662
--- /dev/null
+++ b/src/mip-product-form/mip-product-form.less
@@ -0,0 +1,69 @@
+mip-product-form {
+ position: relative;
+ #mip-form-cross {
+ position: absolute;
+ display: block;
+ padding: 6px;
+ width: 20px;
+ height: 20px;
+ right: 0;
+ background: url(//m.baidu.com/static/search/clear.png) no-repeat center;
+ z-index: 100;
+ background-size: 100% 100%;
+ background-origin: content-box;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.4);
+ tap-highlight-color: rgba(0, 0, 0, 0.4)
+ }
+ input,
+ textarea,
+ select {
+ border: 1px solid #f1f1f1;
+ padding: 6px;
+ display: block;
+ box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ resize: none;
+ font-size: 16px;
+ }
+ input[type='text'],
+ input[type='input'],
+ input[type='datetime'],
+ input[type='email'],
+ input[type='number'],
+ input[type='tel'],
+ input[type='url'] {
+ padding-right: 30px;
+
+ }
+ form {
+ position: relative;
+ }
+ input[type='radio'] {
+ display: inline
+ }
+ label {
+ display: block
+ }
+ div {
+ display: none;
+ color: #ec1f5c;
+ font-size: 12px;
+ text-align: left;
+ padding: 0 10% 0 3%
+ }
+ div[mip-mustache-rendered] {
+ display: block;
+ }
+ input[type='submit'] {
+ border: 1px solid #f1f1f1;
+ border-radius: 5px;
+ color: #333;
+ background-color: #d8d7d7
+ }
+ [submit-success],
+ [submit-fail],
+ [submit-error] {
+ display: none;
+ }
+}
+
diff --git a/src/mip-product-form/package.json b/src/mip-product-form/package.json
new file mode 100644
index 000000000..bb4bd453b
--- /dev/null
+++ b/src/mip-product-form/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "mip-product-form",
+ "version": "1.0.2",
+ "description":"自定义表单",
+ "author": {
+ "name": "chen",
+ "email": "chenweilin@258.com"
+ },
+ "engines": {
+ "mip": ">=1.0.0"
+ }
+}
\ No newline at end of file
diff --git a/src/mip-youbao-form/README.md b/src/mip-youbao-form/README.md
new file mode 100644
index 000000000..470b78239
--- /dev/null
+++ b/src/mip-youbao-form/README.md
@@ -0,0 +1,98 @@
+# mip-youbao-form
+
+mip-youbao-form 表单组件
+
+标题|内容
+----|----
+类型|通用
+支持布局|fixed
+所需脚本|https://c.mipcdn.com/static/v1/mip-youbao-form/mip-youbao-form.js
+
+## 示例
+### 基本使用
+
+```html
+
+
+ 请输入正确的电话
+
+ 年龄不能为空
+
+
+ 请选择性别
+
+
+
+
+
+
+ {{failinfo}}
+
+
+
+
+ 服务器错误
+
+
+
+
+```
+## 属性
+
+### method
+
+说明:表单提交方法
+必选项:是
+
+### from
+
+说明:来自那张表单
+必选项:否
+
+### url
+
+说明:必须是 HTTP(S) 或 // 开头的地址
+必选项: 是
+
+### validatetarget
+
+说明: 验证提示对应 tag,用于对应错误时的提示显示元素的查找
+必选项:否
+
+### validatetype
+
+说明:验证类型, 用于支持简单的验证。目前提供 `email`, `phone`, `idcar`, `custom`。当为 `custom` 时则需要填写 `validatereg`
+必选项:否
+
+### validatereg
+
+说明: 自定义验证,补充站长个性化的验证规则。如果 `validatetype` 为 `custom` 时需填写相应验证规则
+必选项:否
+
+### fetch-url
+
+说明: 有此属性则可以开启异步请求数据逻辑,组件会并根据数据返回状态来按`submit-success`,`submit-error`块中的模板刷新局部信息。
+需要注意的几个点:
+
+- 方法支持。
+- 请求结果请返回 JSON 对象。
+- 数据状态只有在成功(2xx)的时候触发 `submit-success` 的逻辑,其他的均触发 `submit-error` 逻辑。
+
+必选项:否
+
+
+### on
+
+说明: 添加事件清空表单
+参数使用: reload事件,传入数值控制页面刷新等待事件, reset表单数据重置事件 invalidTag(target)目标对象字段验证不通过 validTag(target)目标对象字段验证通过
+必选项: 否
+
+
+## 注意事项
+
+1. 表单提交方法如果为 `post`,应使用 HTTPS 地址。避免 MIP-Cache HTTPS 环境提交到 HTTP,导致浏览器报错。
+2. 使用 fetch 功能时,请求使用 cors 时不能配置为 *。
\ No newline at end of file
diff --git a/src/mip-youbao-form/mip-youbao-form-fn.js b/src/mip-youbao-form/mip-youbao-form-fn.js
new file mode 100644
index 000000000..ab41329c7
--- /dev/null
+++ b/src/mip-youbao-form/mip-youbao-form-fn.js
@@ -0,0 +1,388 @@
+/**
+ * @file mip-form-fn.js
+ * @description mip-form函数
+ * @author miper
+ */
+
+define(function (require) {
+ var templates = require('templates');
+ var util = require('util');
+ var viewer = require('viewer');
+ var windowInIframe = viewer.isIframed;
+ var evt;
+ var formEle;
+ var REGS = {
+ EMAIL: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
+ PHONE: /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/,
+ IDCAR: /^\d{15}|\d{18}$/
+ };
+ return {
+
+ /**
+ * 处理fetch请求逻辑
+ *
+ * @param {string} url 请求url
+ */
+ fetchUrl: function (url) {
+ var me = this;
+ util.css([me.successEle, me.failEle, me.errorEle], {display: 'none'});
+
+ // 获取CSRF-TOKEN
+ var tokenDom = document.querySelector('meta[name="csrf-token"]');
+ if (tokenDom) {
+ var token = tokenDom.getAttribute('content');
+ }
+
+ var fetchData = {
+ method: me.method,
+ credentials: 'include',
+ headers: new Headers({
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'Accept': 'application/json',
+ 'X-CSRF-TOKEN': token ? token : ''
+ })
+ };
+ if (me.method === 'POST') {
+ var formD = me.ele.querySelector('form');
+ if (formD) {
+ fetchData = util.fn.extend({}, fetchData, {
+ body: new FormData(formD)
+ });
+ }
+ }
+
+ // 数据请求处理
+ fetch(url, fetchData).then(function (res) {
+ if (res.ok) {
+ res.json().then(function (data) {
+ if (data.status === 1) {
+ util.css(me.successEle, {display: 'block'});
+ me.renderTpl(me.successEle, {successinfo: data.info});
+ me.submitSuccessHandle();
+ }
+ if (data.status === -1) {
+ util.css(me.failEle, {display: 'block'});
+ me.renderTpl(me.failEle, {failinfo: data.info});
+ me.submitFailHandle();
+ }
+ }).catch(function (err) {
+ me.fetchReject(err);
+ });
+ }
+ else {
+ me.submitErrorHandle();
+ me.fetchReject({});
+ }
+ }).catch(function (err) {
+ me.submitErrorHandle();
+ me.fetchReject(err);
+ });
+ },
+
+ /**
+ * fetch出错逻辑处理
+ *
+ * @param {Object} err 错误对象
+ */
+ fetchReject: function (err) {
+ var me = this;
+ util.css(me.errorEle, {display: 'block'});
+ me.renderTpl(me.errorEle, err);
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 模板父节点
+ * @param {Object} data 模板渲染数据
+ */
+ renderTpl: function (ele, data) {
+ var me = this;
+ templates.render(ele, data).then(function (html) {
+ var tempTarget = me.tempHTML(ele);
+ tempTarget.innerHTML = html;
+ });
+ },
+
+ /**
+ * 处理模板渲染
+ *
+ * @param {HTMLElement} ele 渲染后模板父节点
+ * @return {HTMLElement} target 新建DOM节点
+ */
+ tempHTML: function (ele) {
+ ele = ele || document;
+ var target = ele.querySelector('[mip-mustache-rendered]');
+ if (!target) {
+ target = util.dom.create('');
+ ele.appendChild(target);
+ }
+ return target;
+ },
+
+ /**
+ * createDom 创建 form 节点
+ *
+ * @param {HTMLElement} element 组件节点
+ */
+ createDom: function (element) {
+ formEle = element;
+ var me = this;
+ var url = element.getAttribute('url');
+ var target = element.getAttribute('target');
+ var form = document.createElement('form');
+ var method = (element.getAttribute('method') || 'GET').toUpperCase();
+ form.action = url;
+ form.method = method;
+ target = target ? target : '_blank';
+ form.target = viewer.isIframed && target !== '_blank' ? '_top' : target;
+ element.appendChild(form);
+ util.dom.insert(form, element.children);
+
+ // 按钮提交
+ var curEles = element.querySelectorAll('form');
+ Array.prototype.forEach.call(curEles, function (item) {
+ item.addEventListener('submit', function (event) {
+ event.preventDefault();
+ evt = event;
+ me.onSubmit(element, event);
+ });
+ });
+
+ // 部分浏览器回车不触发submit,
+ element.addEventListener('keydown', function (event) {
+ if (event.keyCode === 13) {
+
+ // 为了使余下浏览器不多次触发submit, 使用prevent
+ evt = event;
+ event.preventDefault();
+ me.onSubmit(this);
+ }
+ }, false);
+ },
+
+ /**
+ * 事件通信
+ *
+ * @description 在 input focus 或 blur 时向iframe外层文档发送数据,iframe外层文档返回设置预览头部为 absolute
+ * @param {Object} event 事件对象
+ */
+ sendFormMessage: function (event) {
+ if (windowInIframe) {
+ // mip_video_jump 为写在外层的承接方法
+ viewer.sendMessage('input-' + event, {});
+ }
+ },
+
+ /**
+ * 事件发送处理
+ *
+ * @description 给 input 绑定事件,向 SF 发送数据,为了解决 ios 的 UC 浏览器在iframe外层文档悬浮头部 fixed 位置混乱问题
+ * @param {HTMLElement} element mip 组件标签
+ */
+ initMessageEvents: function (element) {
+ var me = this;
+ var inputAll = element.querySelectorAll('input');
+ Array.prototype.forEach.call(inputAll, function (item, index) {
+ item.addEventListener('focus', function () {
+ me.sendFormMessage('focus');
+ }, false);
+
+ item.addEventListener('blur', function () {
+ me.sendFormMessage('blur');
+ }, false);
+ });
+ },
+
+ /**
+ * 文案格式验证
+ *
+ * @param {string} type 验证类型
+ * @param {string} value 需要验证的文案
+ * @param {HTMLElement} target dom元素
+ * @return {boolean} 是否符合自定义校验
+ */
+ verification: function (type, value, target) {
+ if (target.type === 'radio' || target.type === 'checkbox') {
+ var selector = 'input[type="' + target.type + '"][name="' + target.name + '"]';
+ var sameEle = this.ele.querySelectorAll(selector);
+ var checked = false;
+ for (var i in sameEle) {
+ if (sameEle[i].checked) {
+ checked = true;
+ }
+ }
+ return checked;
+ }
+ return (type === 'must') ? !(value === '') : REGS[type.toUpperCase()].test(value);
+ },
+
+ /**
+ * 点击提交按钮事件处理函数
+ *
+ * @param {HTMLElement} element form节点
+ */
+ onSubmit: function (element) {
+ var me = this;
+ var preventSubmit = false;
+ var inputs = element.querySelectorAll('input, textarea, select');
+ var url = element.getAttribute('url') || '';
+ var getUrl = url.toLowerCase();
+ var isHttp = getUrl.match('http://');
+ var valueJson = '';
+ var hasFetch = element.getAttribute('fetch-url') || '';
+ me.method = (element.getAttribute('method') || 'GET').toUpperCase();
+ var isGet = me.method === 'GET';
+
+ this.ele = element;
+ this.successEle = element.querySelector('[submit-success]');
+ this.failEle = element.querySelector('[submit-fail]');
+ this.errorEle = element.querySelector('[submit-error]');
+ // 执行提交句柄
+ me.submitHandle();
+ // 校验输入内容是否合法
+ Array.prototype.forEach.call(inputs, function (item) {
+ var type = item.getAttribute('validatetype');
+ var target = item.getAttribute('validatetarget');
+ var regval = item.getAttribute('validatereg');
+ var value = item.value;
+ var reg;
+
+ if (item.type === 'submit') {
+ return;
+ }
+ else if (item.type === 'checkbox' || item.type === 'radio') {
+ value = item.checked ? item.value : '';
+ }
+
+ valueJson += '&' + item.name + '=' + value;
+ if (type) {
+ if (regval) {
+ reg = value === '' ? false : (new RegExp(regval)).test(value);
+ }
+ else {
+ reg = me.verification(type, value, item);
+ }
+
+ // 显示表单错误信息
+ if (reg) {
+ me.validHandle(target);
+ }
+ else {
+ me.invalidHandle(target);
+ }
+
+ preventSubmit = !reg ? true : preventSubmit;
+ }
+ });
+
+ if (preventSubmit) {
+ return;
+ }
+
+ // 在iframe下使用mibm-jumplink,跳转显示手百框。 http-GET请求交给外层跳转
+ if (window.parent !== window && isHttp && isGet) {
+ var messageUrl = '';
+ if (getUrl.match('\\?')) {
+ // eg. getUrl == 'http://www.mipengine.org?we=123'
+ messageUrl = getUrl + valueJson;
+ }
+ else {
+ // eg. getUrl == 'http://www.mipengine.org'
+ valueJson = valueJson.substring(1);
+ messageUrl = getUrl + '?' + valueJson;
+ }
+ var message = {
+ event: 'mibm-jumplink',
+ data: {
+ url: messageUrl
+ }
+ };
+ window.parent.postMessage(message, '*');
+ }
+ else if (hasFetch.trim()) {
+ me.fetchUrl(hasFetch);
+ }
+ else {
+ // https请求 或 post请求 或 非iframe下不做处理
+ element.getElementsByTagName('form')[0].submit();
+ }
+ },
+
+ /**
+ * 显示对应字段的错误信息
+ *
+ * @param {string} target 表单验证目标
+ * @return {void} 无返回值
+ */
+ invalidHandle: function (target) {
+ var targetEle = formEle.querySelectorAll('div[target="' + target + '"]');
+ if (!targetEle) {
+ console.log('验证对象target不存在');
+ return;
+ }
+ util.css(targetEle, {display: 'block'});
+ },
+
+ /**
+ * 显示对应字段的错误信息
+ *
+ * @param {string} target 表单验证目标
+ * @return {void} 无返回值
+ */
+ validHandle: function (target) {
+ var targetEle = formEle.querySelectorAll('div[target="' + target + '"]');
+ if (!targetEle) {
+ console.log('验证对象target不存在');
+ return;
+ }
+ util.css(targetEle, {display: 'none'});
+ },
+
+
+ /**
+ * 提交时的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitHandle: function () {
+ viewer.eventAction.execute('submit', evt.target, evt);
+ },
+
+ /**
+ * 提交成功调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitSuccessHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('submitSuccess', evt.target, evt);
+ },
+
+ /**
+ * 提交成功调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitFailHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('submitFail', evt.target, evt);
+ },
+
+ /**
+ * 提交失败调用的在html on里使用的事件
+ *
+ * @param {HTMLElement} element form节点
+ */
+ submitErrorHandle: function () {
+ if (!evt) {
+ return;
+ }
+ viewer.eventAction.execute('submitError', evt.target, evt);
+ }
+ };
+});
diff --git a/src/mip-youbao-form/mip-youbao-form.css b/src/mip-youbao-form/mip-youbao-form.css
new file mode 100644
index 000000000..af2d33710
--- /dev/null
+++ b/src/mip-youbao-form/mip-youbao-form.css
@@ -0,0 +1 @@
+mip-youbao-form{position:relative}mip-youbao-form .btnCode{display:block;padding:10px;color:#fff}mip-youbao-form #mip-form-cross{position:absolute;display:block;padding:6px;width:20px;height:20px;right:0;background:url(//m.baidu.com/static/search/clear.png) no-repeat center;z-index:100;background-size:100% 100%;background-origin:content-box;-webkit-tap-highlight-color:rgba(0,0,0,.4);tap-highlight-color:rgba(0,0,0,.4)}mip-youbao-form input,mip-youbao-form textarea,mip-youbao-form select{border:1px solid #f1f1f1;padding:6px;display:block;box-sizing:border-box;-webkit-box-sizing:border-box;resize:none;font-size:16px}mip-youbao-form input[type=text],mip-youbao-form input[type=input],mip-youbao-form input[type=datetime],mip-youbao-form input[type=email],mip-youbao-form input[type=number],mip-youbao-form input[type=tel],mip-youbao-form input[type=url]{padding-right:30px}mip-youbao-form form{position:relative}mip-youbao-form input[type=radio]{display:inline}mip-youbao-form label{display:block}mip-youbao-form .error{display:none;color:#ec1f5c;font-size:12px;text-align:left;line-height:22px;padding:0 10% 0 3%}mip-youbao-form .error[mip-mustache-rendered]{display:block}mip-youbao-form input[type=submit]{border:1px solid #f1f1f1;border-radius:5px;color:#333;background:#d8d7d7}mip-youbao-form [submit-success],mip-youbao-form [submit-error]{display:none}
\ No newline at end of file
diff --git a/src/mip-youbao-form/mip-youbao-form.js b/src/mip-youbao-form/mip-youbao-form.js
new file mode 100644
index 000000000..556985e25
--- /dev/null
+++ b/src/mip-youbao-form/mip-youbao-form.js
@@ -0,0 +1,41 @@
+/**
+ * @file mip-258-form 组件
+ * @author
+ */
+
+define(function (require) {
+ var customElement = require('customElement').create();
+ var form = require('./mip-youbao-form-fn');
+
+ customElement.prototype.build = function () {
+ var element = this.element;
+ form.createDom(element);
+ form.initMessageEvents(element);
+ };
+ customElement.prototype.firstInviewCallback = function () {
+
+ // 页面刷新事件
+ this.addEventAction('reload', function (event, str) {
+ str = str ? 500 : parseInt(str, 10);
+ setTimeout(function () {
+ window.top.location.reload();
+ }, str);
+ });
+
+ // 表单数据重置事件
+ this.addEventAction('reset', function (event, str) {
+ event.target.reset();
+ });
+
+ // 验证错误事件
+ this.addEventAction('invalidTag', function (event, target) {
+ form.invalidHandle(target);
+ });
+
+ // mip?尼玛B,我34行哪里多空格了,艹。5min写东西,10min调格式
+ this.addEventAction('validTag', function (event, target) {
+ form.validHandle(target);
+ });
+ };
+ return customElement;
+});
diff --git a/src/mip-youbao-form/mip-youbao-form.less b/src/mip-youbao-form/mip-youbao-form.less
new file mode 100644
index 000000000..b6062239d
--- /dev/null
+++ b/src/mip-youbao-form/mip-youbao-form.less
@@ -0,0 +1,74 @@
+mip-youbao-form {
+ position: relative;
+ .btnCode {
+ display: block;
+ padding: 10px;
+ color: #fff;
+ }
+ #mip-form-cross {
+ position: absolute;
+ display: block;
+ padding: 6px;
+ width: 20px;
+ height: 20px;
+ right: 0;
+ background: url('//m.baidu.com/static/search/clear.png') no-repeat center;
+ z-index: 100;
+ background-size: 100% 100%;
+ background-origin: content-box;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.4);
+ tap-highlight-color: rgba(0, 0, 0, 0.4)
+ }
+ input,
+ textarea,
+ select {
+ border: 1px solid #f1f1f1;
+ padding: 6px;
+ display: block;
+ box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ resize: none;
+ font-size: 16px;
+ }
+ input[type='text'],
+ input[type='input'],
+ input[type='datetime'],
+ input[type='email'],
+ input[type='number'],
+ input[type='tel'],
+ input[type='url'] {
+ padding-right: 30px;
+ }
+ form {
+ position: relative;
+ }
+ input[type='radio'] {
+ display: inline
+ }
+ label {
+ display: block
+ }
+ .error {
+ display: none;
+ color: #ec1f5c;
+ font-size: 12px;
+ text-align: left;
+ line-height: 22px;
+ padding: 0 10% 0 3%
+ }
+ .error[mip-mustache-rendered] {
+ display: block;
+ }
+ input[type='submit'] {
+ border: 1px solid #f1f1f1;
+ border-radius: 5px;
+ color: #333;
+ background: #d8d7d7;
+ }
+ [submit-success],
+ [submit-fail],
+ [submit-error] {
+ display: none;
+ }
+}
+
diff --git a/src/mip-youbao-form/package.json b/src/mip-youbao-form/package.json
new file mode 100644
index 000000000..c59be345d
--- /dev/null
+++ b/src/mip-youbao-form/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "mip-youbao-form",
+ "version": "1.0.0",
+ "description": "youbao表单提交",
+ "contributors": [
+ {
+ "name": "teemor",
+ "email": "232957726@qq.com"
+ }
+ ],
+ "engines": {
+ "mip": ">=1.1.0"
+ }
+}