Authored by 沈志敏

活动模版

  1 +'use strict';
  2 +const model = require('../models/feature');
  3 +
  4 +exports.index = function(req, res, next) {
  5 + let code = req.params.code;
  6 +
  7 + model.index(code).then((result) => {
  8 + res.render('feature', {
  9 + module: 'activity',
  10 + page: 'feature',
  11 + title: result.name || 'Yoho!Buy有货',
  12 + content: result,
  13 + isFeature: true
  14 + });
  15 + }).catch(next);
  16 +};
  1 +'use strict';
  2 +const activeapi = global.yoho.ActiveAPI;
  3 +const api = global.yoho.API;
  4 +const helpers = global.yoho.helpers;
  5 +
  6 +const _getProductBySkns = function(productObj) {
  7 + return api.get('', {
  8 + productSkn: productObj.defaultSkns,
  9 + method: 'h5.product.batch'
  10 + }).then((result) => {
  11 + let nskns = [];
  12 +
  13 + if (result && result.data && result.data.product_list && result.code === 200) {
  14 + result.data.product_list.forEach(function(val) {
  15 + var goods_id = Array.isArray(val.goods_list) && val.goods_list.length ? val.goods_list[0].goods_id : null;
  16 + var obj = {
  17 + producturl: `//m.yohobuy.com/product/pro_${val.product_id}_${goods_id}/${val.cn_alphabet}.html?openby:yohobuy={"action":"go.productDetail","params":{"product_skn":${val.product_skn}}}`,
  18 + productimg: helpers.image(val.default_images, 213, 284, 2, 60).replace('quality/80', 'quality/60'),
  19 + productname: val.product_name,
  20 + saleprice: val.sales_price,
  21 + marketprice: val.sales_price === val.market_price ? '' : val.market_price,
  22 + brandname: val.brand_name
  23 + };
  24 +
  25 + if (val.shop_id) {
  26 + obj.brandurl = `//m.yohobuy.com/product/index/brand?domain=${val.brand_domain}&openby:yohobuy={"action":"go.shop","params":{"shop_id":${val.shop_id},"shop_template_type":${val.shop_template_type}}}`;
  27 + } else {
  28 + obj.brandurl = `//m.yohobuy.com/product/index/brand?domain=${val.brand_domain}&openby:yohobuy={"action":"go.brand","params":{"brand_id":${val.brand_id}}}`;
  29 + }
  30 +
  31 + nskns.push(obj);
  32 + });
  33 + productObj.defaultSkns = nskns;
  34 + } else {
  35 + delete productObj.defaultSkns;
  36 + }
  37 + });
  38 +};
  39 +
  40 +module.exports = {
  41 + index: function(code) {
  42 + return Promise.coroutine(function*() {
  43 + if (!code) {
  44 + return Promise.resolve({});
  45 + }
  46 +
  47 + let data = yield activeapi.get('', {
  48 + method: 'app.activity.template',
  49 + activity_id: code
  50 + });
  51 +
  52 + if (data.code === 200) {
  53 + data = data.data;
  54 + }
  55 +
  56 + let sknsArr = [];
  57 +
  58 + if (data.floors) {
  59 + data.floors.forEach(function(f) {
  60 + if (f.component && f.component[0] && f.component[0].type === 'productGroup' && f.component[0].defaultSkns) {
  61 + sknsArr.push(_getProductBySkns(f.component[0]));
  62 + }
  63 + });
  64 + }
  65 +
  66 + if (sknsArr.length) {
  67 + yield Promise.all(sknsArr);
  68 + }
  69 + return data;
  70 + })();
  71 + }
  72 +};
@@ -34,6 +34,8 @@ const promotion = require(`${cRoot}/promotion`); @@ -34,6 +34,8 @@ const promotion = require(`${cRoot}/promotion`);
34 34
35 const individuation = require(`${cRoot}/individuation`); 35 const individuation = require(`${cRoot}/individuation`);
36 36
  37 +const feature = require(`${cRoot}/feature`);
  38 +
37 const appDownloads = require(`${cRoot}/app-downloads`); 39 const appDownloads = require(`${cRoot}/app-downloads`);
38 40
39 const redbag = require(`${cRoot}/redbag`); 41 const redbag = require(`${cRoot}/redbag`);
@@ -162,6 +164,9 @@ router.get('/redbag/2017', redbag.index); @@ -162,6 +164,9 @@ router.get('/redbag/2017', redbag.index);
162 // 获取活动页面个性化推荐商品数据 164 // 获取活动页面个性化推荐商品数据
163 router.get('/individuation', individuation.productLst); 165 router.get('/individuation', individuation.productLst);
164 166
  167 +// 活动页模版
  168 +router.get('/feature/:code', feature.index);
  169 +
165 // 2016 年度账单 170 // 2016 年度账单
166 router.get('/annual-account', annualAccount.index); 171 router.get('/annual-account', annualAccount.index);
167 router.get('/annual-account/share', annualAccount.share); 172 router.get('/annual-account/share', annualAccount.share);
  1 +<div class="feature-page yoho-page">
  2 + {{#content.floors}}
  3 + {{#isEqualOr type 'sidebar'}}
  4 + {{! 侧悬浮}}
  5 + <div class="cexuanfu" id="load_cxf"></div>
  6 + {{/isEqualOr}}
  7 + {{#isEqualOr type '' 'common_floor' 'fix'}}
  8 + {{! 普通楼层 顶悬浮}}
  9 + <div {{#if param.anchorname}}id="{{param.anchorname}}"{{/if}} {{#if id}}data-id="{{id}}"{{/if}} class="floor {{type}}"
  10 + style="{{#if param.bgcolor}}background-color:{{param.bgcolor}}{{/if}}">
  11 + {{#if param.bgimg}}
  12 + <img src="{{image2 param.bgimg q=60}}">
  13 + {{/if}}
  14 + {{#component}}
  15 + {{#isEqualOr type 'link'}}
  16 + {{! 普通组件}}
  17 + <a class="anchor" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
  18 + {{/isEqualOr}}
  19 +
  20 + {{#isEqualOr type 'coupon'}}
  21 + {{! 优惠券}}
  22 + <a class="anchor yoho-conpon" style="{{styleFormat this percent=1}}" data-token="{{token}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
  23 + {{/isEqualOr}}
  24 +
  25 + {{#isEqualOr type 'yohoCoin'}}
  26 + {{! 有货币}}
  27 + <a class="anchor yoho-coin" style="{{styleFormat this percent=1}}" data-token="{{token}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
  28 + {{/isEqualOr}}
  29 +
  30 + {{#isEqualOr type 'video'}}
  31 + {{! 视频}}
  32 + <a class="anchor video-bg" style="{{styleFormat this percent=1}}" href="{{#if url}}{{url}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../this @index}}"></a>
  33 + <div class="video-android-close hide"></div>
  34 + <div class="video-android-bg hide"></div>
  35 + <video class="video" controls loop preload="meta" name="media">
  36 + <source src="{{videoSrc}}">
  37 + </video>
  38 + {{/isEqualOr}}
  39 +
  40 + {{#isEqualOr type 'marquee' 'swiper'}}
  41 + {{! 轮播/滑动}}
  42 + <div class="swiper-container {{type}}" data-loop="{{loop}}" {{#if autoplay}}data-autoplay="{{autoplay}}"{{/if}}>
  43 + <div class="swiper-wrapper">
  44 + {{#list}}
  45 + <div class="swiper-slide" style="{{styleFormat this percent=1}}">
  46 + <img src="{{image2 src q=60}}">
  47 + <a class="anchor" href="{{#if link}}{{link}}{{else}}javascript:void(0);{{/if}}" fp="{{getAnalysis ../../this @index}}"></a>
  48 + </div>
  49 + {{/list}}
  50 + </div>
  51 + {{#isEqualOr type 'marquee'}}
  52 + <div class="swiper-pagination"></div>
  53 + {{/isEqualOr}}
  54 + </div>
  55 + {{/isEqualOr}}
  56 +
  57 + {{#isEqualOr type 'tab'}}
  58 + {{! tab}}
  59 + <div class="tab-container">
  60 + {{#repeat count}}
  61 + <a class="anchor {{#if @first}}active{{/if}}" style="{{tabStyle @index ../count}}"></a>
  62 + {{/repeat}}
  63 + </div>
  64 + {{/isEqualOr}}
  65 +
  66 + {{#isEqualOr type 'productGroup'}}
  67 + {{! 商品池}}
  68 + <div class="product-container item{{numOfOneRow}}">
  69 + <div class="product-source" {{#if searchCondition}}cloneitem="{{searchCondition.limit}}" condition='{{stringify searchCondition}}'{{/if}} fp="{{getAnalysis ../this @index}}">
  70 + <input class="imgwh" type="hidden" value="193x257">
  71 + {{#ifand defaultSkns defaultSkns.length}}
  72 + {{#defaultSkns}}
  73 + <div class="feature-product-info {{#if ../condition}}novisible{{/if}}">
  74 + <a class="first-part product-detail" href='{{producturl}}'>
  75 + <div class="product-detail-imgbox">
  76 + {{#if ../lefTopImg}}<img class="leftopimg" src="{{image2 ../lefTopImg q=60}}">{{/if}}
  77 + {{#if ../rigTopImg}}<img class="rigtopimg" src="{{image2 ../rigTopImg q=60}}">{{/if}}
  78 + <img class="product-detail-img" src="{{image2 productimg q=60}}">
  79 + </div>
  80 + {{#isEqualOr ../showPrdName '1'}}<p class="product-name">{{productname}}</p>{{/isEqualOr}}
  81 + <div class="product-detail-text">
  82 + <div class="price">
  83 + <span class="sale-price">¥{{saleprice}}</span>
  84 + {{#if marketprice}}<span class="market-price">¥{{marketprice}}</span>{{/if}}
  85 + </div>
  86 + </div>
  87 + </a>
  88 + {{#if ../brandImg}}
  89 + <a class="second-part {{#isEqualOr ../showBrandUrl '1'}}product-brand{{else}}product-detail{{/isEqualOr}}" href='{{brandurl}}'>
  90 + <div class="brand-div">
  91 + <span class="brand-name">{{brandname}}</span>
  92 + </div>
  93 + <img class="brand-img" src="{{image2 ../brandImg q=60}}">
  94 + </a>
  95 + {{/if}}
  96 + </div>
  97 + {{/defaultSkns}}
  98 + {{else}}
  99 + <div class="feature-product-info novisible">
  100 + <a class="first-part product-detail" href=''>
  101 + <div class="product-detail-imgbox">
  102 + {{#if lefTopImg}}<img class="leftopimg" src="{{image2 lefTopImg q=60}}">{{/if}}
  103 + {{#if rigTopImg}}<img class="rigtopimg" src="{{image2 rigTopImg q=60}}">{{/if}}
  104 + <img class="product-detail-img" src="">
  105 + </div>
  106 + {{#isEqualOr showpname '1'}}<p class="product-name"></p>{{/isEqualOr}}
  107 + <div class="product-detail-text">
  108 + <div class="price">
  109 + <span class="sale-price"></span>
  110 + <span class="market-price"></span>
  111 + </div>
  112 + </div>
  113 + </a>
  114 + {{#if brandImg}}
  115 + <a class="second-part {{#isEqualOr showBrandUrl '1'}}product-brand{{else}}product-detail{{/isEqualOr}}" href=''>
  116 + <div class="brand-div">
  117 + <span class="brand-name"></span>
  118 + </div>
  119 + <img class="brand-img" src="{{image2 brandImg q=60}}">
  120 + </a>
  121 + {{/if}}
  122 + </div>
  123 + {{/ifand}}
  124 + </div>
  125 + </div>
  126 + {{/isEqualOr}}
  127 + {{/component}}
  128 + </div>
  129 + {{/isEqualOr}}
  130 + {{/content.floors}}
  131 +</div>
@@ -44,22 +44,30 @@ @@ -44,22 +44,30 @@
44 {{#if localCss}} 44 {{#if localCss}}
45 <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/common.css"> 45 <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/common.css">
46 {{/if}} 46 {{/if}}
47 - {{#ifor localCss vue}}  
48 - <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/{{module}}.{{page}}.css">  
49 - {{^}}  
50 47
51 - <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/index.css">  
52 - {{/ifor}} 48 + {{#if isFeature}}
  49 + <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/feature.css">
  50 + {{else}}
  51 + {{#ifor localCss vue}}
  52 + <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/{{module}}.{{page}}.css">
  53 + {{^}}
  54 + <link rel="stylesheet" media="all" href="//{{devHost}}:5001/bundle/index.css">
  55 + {{/ifor}}
  56 + {{/if}}
53 {{^}} 57 {{^}}
54 -  
55 {{#if localCss }} 58 {{#if localCss }}
56 <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/common.css"> 59 <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/common.css">
57 {{/if}} 60 {{/if}}
58 - {{#ifor localCss vue}}  
59 - <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.css">  
60 - {{^}}  
61 - <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css">  
62 - {{/ifor}} 61 +
  62 + {{#if isFeature}}
  63 + <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/feature.css">
  64 + {{else}}
  65 + {{#ifor localCss vue}}
  66 + <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.css">
  67 + {{^}}
  68 + <link rel="stylesheet" media="all" href="//cdn.yoho.cn/m-yohobuy-node/{{version}}/index.css">
  69 + {{/ifor}}
  70 + {{/if}}
63 {{/if}} 71 {{/if}}
64 <link rel="apple-touch-icon-precomposed" href="http://static.yohobuy.com/m/v1/img/touch/apple-touch-icon-144x144-precomposed-new.png"> 72 <link rel="apple-touch-icon-precomposed" href="http://static.yohobuy.com/m/v1/img/touch/apple-touch-icon-144x144-precomposed-new.png">
65 <link rel="apple-touch-startup-image" sizes="640x920" href="http://static.yohobuy.com/m/v1/img/startup/startup-retina.png" media="screen and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2)"> 73 <link rel="apple-touch-startup-image" sizes="640x920" href="http://static.yohobuy.com/m/v1/img/startup/startup-retina.png" media="screen and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2)">
@@ -97,7 +105,9 @@ @@ -97,7 +105,9 @@
97 <script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/libs.js"></script> 105 <script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/libs.js"></script>
98 <script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script> 106 <script src="//cdn.yoho.cn/m-yohobuy-node/{{version}}/{{module}}.{{page}}.js"></script>
99 {{/if}} 107 {{/if}}
100 - {{#unless devEnv}} 108 + {{#isFeature}}
  109 + <script type="text/javascript" src="//cdn.yoho.cn/js-sdk/99.99.99/jssdk.js"></script>
  110 + {{/isFeature}}
101 {{> analysis}} 111 {{> analysis}}
102 {{/unless}} 112 {{/unless}}
103 </body> 113 </body>
@@ -160,7 +160,7 @@ gulp.task('dist', ['ge'], () => { @@ -160,7 +160,7 @@ gulp.task('dist', ['ge'], () => {
160 160
161 // postcss compile in dev 161 // postcss compile in dev
162 gulp.task('postcss-dev', () => { 162 gulp.task('postcss-dev', () => {
163 - return gulp.src(['scss/index.css', 'scss/common.css']) 163 + return gulp.src(['scss/index.css', 'scss/common.css', 'scss/feature.css'])
164 .pipe(sourcemaps.init()) 164 .pipe(sourcemaps.init())
165 .pipe(postcss(postcssPlugin(env.dev), { 165 .pipe(postcss(postcssPlugin(env.dev), {
166 parser: require('postcss-scss') 166 parser: require('postcss-scss')
@@ -191,7 +191,7 @@ gulp.task('font', () => { @@ -191,7 +191,7 @@ gulp.task('font', () => {
191 191
192 // postcss compile in pro 192 // postcss compile in pro
193 gulp.task('postcss', ['assets'], () => { 193 gulp.task('postcss', ['assets'], () => {
194 - return gulp.src(['scss/index.css', 'scss/common.css']) 194 + return gulp.src(['scss/index.css', 'scss/common.css', 'scss/feature.css'])
195 .pipe(postcss(postcssPlugin(env.pro), { 195 .pipe(postcss(postcssPlugin(env.pro), {
196 parser: require('postcss-scss') 196 parser: require('postcss-scss')
197 })) 197 }))
  1 +var $ = require('yoho-jquery');
  2 +var Swiper = require('yoho-swiper');
  3 +
  4 +global.jQuery = $;
  5 +
  6 +var isAndroid = /(Android)/i.test(navigator.userAgent);
  7 +var isWechat = /micromessenger/i.test(navigator.userAgent);
  8 +
  9 +function swiperInit() {
  10 + $('.swiper-container').each(function() {
  11 + var opt = {
  12 + loop: $(this).data('loop') === '1' ? true : false,
  13 + spaceBetween: 15,
  14 + slidesPerView: 'auto'
  15 + };
  16 + var autoplay = $(this).data('autoplay');
  17 + var pagination = $(this).find('.swiper-pagination');
  18 +
  19 + if (autoplay) {
  20 + opt.autoplay = Number(autoplay);
  21 + }
  22 + if (pagination) {
  23 + opt.pagination = pagination;
  24 + opt.paginationClickable = true;
  25 + }
  26 +
  27 + new Swiper(this, opt);
  28 + });
  29 +}
  30 +
  31 +function topNavInit() {
  32 + var topnav = $('.floor.fix');
  33 +
  34 + if (topnav.length) {
  35 + var doc = $(document);
  36 + var cloneNav = topnav.clone().addClass('fixnav').prependTo($('.feature-page'));
  37 +
  38 + $(window).scroll(function() {
  39 + var top = doc.scrollTop();
  40 + var top1 = topnav.offset().top;
  41 +
  42 + if (top > top1) {
  43 + cloneNav.fadeIn('slow');
  44 + } else {
  45 + cloneNav.fadeOut('slow');
  46 + }
  47 + });
  48 + }
  49 +}
  50 +
  51 +function ceXuanFuInit() {
  52 + $('#load_cxf').load('http://feature.yoho.cn/public/cexuanfu/cexuanfu.html', function() {
  53 + $('#cxf').click(function() {
  54 + if ($(this).hasClass('isclick')) {
  55 + $('.cxfall').hide();
  56 + $(this).removeClass('iscxf');
  57 + } else {
  58 + $('.cxfall').show();
  59 + $(this).addClass('iscxf');
  60 + }
  61 + });
  62 + $('.cxfallbg').click(function() {
  63 + $(this).parent().hide();
  64 + $('#cxf').removeClass('iscxf');
  65 + });
  66 + });
  67 +}
  68 +
  69 +function videoInit() {
  70 + function cancelMove(e) {
  71 + e.preventDefault && e.preventDefault();
  72 + e.returnValue = false;
  73 + e.stopPropagation && e.stopPropagation();
  74 + return false;
  75 + }
  76 +
  77 + $('.video-bg').on('click', function() {
  78 + var v = $(this).nextAll('video')[0];
  79 +
  80 + v.play();
  81 + if (isAndroid && !isWechat) {
  82 + $('.video').addClass('android');
  83 + $('.video-android-bg').removeClass('hide');
  84 + $('.video-android-close').removeClass('hide');
  85 + $('body').css('overflow', 'hidden').on('touchmove', cancelMove);
  86 + }
  87 + });
  88 +
  89 + $('.video-android-close').on('click', function() {
  90 + $('.video').removeClass('android');
  91 + $('.video-android-bg').addClass('hide');
  92 + $('.video-android-close').addClass('hide');
  93 + $('body').css('overflow', '').off('touchmove', cancelMove);
  94 + $(this).nextAll('video')[0].pause();
  95 + });
  96 +}
  97 +
  98 +function tabInit() {
  99 + var tabContainer = $('.tab-container');
  100 + var nextDom = tabContainer.parent().nextAll();
  101 + var tab = tabContainer.find('a.anchor');
  102 +
  103 + tab.on('click', function() {
  104 + tab.removeClass('active');
  105 + $(this).addClass('active');
  106 +
  107 + var index = $(this).index();
  108 +
  109 + for (var i = 0; i < tab.length; i++) {
  110 + if (index === i) {
  111 + $(nextDom[i]).show();
  112 + } else {
  113 + $(nextDom[i]).hide();
  114 + }
  115 + }
  116 + });
  117 +
  118 + for (var i = 1; i < tab.length; i++) {
  119 + $(nextDom[i]).hide();
  120 + }
  121 +}
  122 +
  123 +$(function() {
  124 + // 微信中点击之后,返回跳到指定位置
  125 + var totalH, scH;
  126 + var top = localStorage.changtu1;
  127 +
  128 + window.scrollTo(0, top);
  129 + localStorage.removeItem('changtu1');
  130 +
  131 + $('a').click(function() {
  132 + totalH = event.pageY;
  133 + scH = event.clientY;
  134 + localStorage.changtu1 = totalH - scH; // 每次点击缓存高度
  135 + });
  136 +
  137 + // 轮播
  138 + swiperInit();
  139 +
  140 + // 顶悬浮
  141 + topNavInit();
  142 +
  143 + // 侧悬浮
  144 + ceXuanFuInit();
  145 +
  146 + // 视频相关
  147 + videoInit();
  148 +
  149 + // tab
  150 + tabInit();
  151 +});
  1 +@charset "utf-8";
  2 +
  3 +@import "feature/anchor";
  4 +@import "feature/product";
  5 +@import "feature/swiper.min";
  1 +body,
  2 +ul,
  3 +dl,
  4 +dd,
  5 +dt,
  6 +ol,
  7 +li,
  8 +p,
  9 +h1,
  10 +h2,
  11 +h3,
  12 +h4,
  13 +h5,
  14 +h6,
  15 +textarea,
  16 +form,
  17 +select,
  18 +fieldset,
  19 +table,
  20 +td,
  21 +div,
  22 +input {
  23 + margin: 0;
  24 + padding: 0;
  25 + -webkit-text-size-adjust: none;
  26 +}
  27 +
  28 +h1,
  29 +h2,
  30 +h3,
  31 +h4,
  32 +h5,
  33 +h6 {
  34 + font-size: 12px;
  35 + font-weight: normal;
  36 +}
  37 +
  38 +body > div {
  39 + margin: 0 auto;
  40 +}
  41 +
  42 +div {
  43 + text-align: left;
  44 +}
  45 +
  46 +a img {
  47 + border: 0;
  48 +}
  49 +
  50 +body {
  51 + color: #333;
  52 + text-align: center;
  53 + font-size: 12px;
  54 + font-family: helvetica,Arial,黑体;
  55 +}
  56 +
  57 +ul,
  58 +ol,
  59 +li {
  60 + list-style-type: none;
  61 + vertical-align: 0;
  62 +}
  63 +
  64 +body {
  65 + background-color: #fff;
  66 + color: #666;
  67 +}
  68 +
  69 +* {
  70 + -webkit-user-select: none;
  71 + -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  72 + -ms-touch-action: none;
  73 + -webkit-touch-callout: none;
  74 + -webkit-box-sizing: border-box;
  75 + box-sizing: border-box;
  76 +}
  77 +
  78 +.feature-page {
  79 + max-width: 640px;
  80 + margin: 0 auto;
  81 +}
  82 +
  83 +.feature-page .cexuanfu {
  84 + img {
  85 + width: 100%;
  86 + }
  87 +
  88 + .anchor {
  89 + position: absolute;
  90 + top: 0;
  91 + left: 0;
  92 + background: transparent;
  93 + cursor: pointer;
  94 + z-index: 100;
  95 + }
  96 +}
  97 +
  98 +.feature-page .floor {
  99 + width: 100%;
  100 + position: relative;
  101 +
  102 + img {
  103 + display: block;
  104 + width: 100%;
  105 + height: 100%;
  106 + }
  107 +
  108 + .anchor {
  109 + position: absolute;
  110 + top: 0;
  111 + left: 0;
  112 + background: transparent;
  113 + cursor: pointer;
  114 + z-index: 100;
  115 + }
  116 +
  117 + .hide {
  118 + display: none;
  119 + }
  120 +
  121 + /*顶悬浮*/
  122 + &.fixnav {
  123 + position: fixed;
  124 + top: 0;
  125 + left: 0;
  126 + width: 100%;
  127 + display: none;
  128 + z-index: 1000;
  129 + }
  130 +
  131 + .tab-container {
  132 + a.active {
  133 + background: rgba(0, 0, 0, 0.2);
  134 + }
  135 + }
  136 +}
  137 +
  138 +.swiper-container {
  139 + height: 100%;
  140 +
  141 + &.swiper {
  142 + padding: 5px 10px;
  143 + height: 100%;
  144 + }
  145 +}
  146 +
  147 +.swiper-slide {
  148 + .anchor {
  149 + width: 100%;
  150 + height: 100%;
  151 + }
  152 +}
  153 +
  154 +/*弹窗*/
  155 +.tc_box {
  156 + position: fixed;
  157 + width: 100%;
  158 + height: 100%;
  159 + top: 0;
  160 + left: 0;
  161 + margin: 0 auto;
  162 + display: none;
  163 + z-index: 1000;
  164 +}
  165 +
  166 +.tc_bg {
  167 + width: 100%;
  168 + height: 100%;
  169 + background: rgba(0, 0, 0, 0.5);
  170 + margin: 0 auto;
  171 + z-index: 1001;
  172 +}
  173 +
  174 +.tc_con {
  175 + position: fixed;
  176 + top: 50%;
  177 + left: 3.9%;
  178 + width: 92.2%;
  179 + margin-top: -200px;
  180 + z-index: 1000000;
  181 + display: block;
  182 +}
  1 +.video {
  2 + position: fixed;
  3 + top: -100%;
  4 + width: 100%;
  5 + height: 360px;
  6 + z-index: 3;
  7 +
  8 + &.android {
  9 + top: 30%;
  10 + z-index: 1002;
  11 + }
  12 +}
  13 +
  14 +.video-android-bg {
  15 + position: fixed;
  16 + top: 0;
  17 + left: 0;
  18 + right: 0;
  19 + bottom: 0;
  20 + width: 100%;
  21 + height: 100%;
  22 + z-index: 1001;
  23 + background: #000;
  24 + opacity: 0.7;
  25 +}
  26 +
  27 +.video-android-close {
  28 + position: fixed;
  29 + top: 26.2%;
  30 + right: 10px;
  31 + width: 35px;
  32 + height: 35px;
  33 + z-index: 1003;
  34 + background-image: resolve("activity/close.png");
  35 + background-size: cover;
  36 +}
  37 +
  38 +.product-container {
  39 + overflow: hidden;
  40 + padding: 0 20px 10px;
  41 + font-size: 22px;
  42 +
  43 + &.item3 {
  44 + padding: 0 20px 10px;
  45 + font-size: 20px;
  46 +
  47 + .feature-product-info {
  48 + width: 193px;
  49 + margin-right: 10px;
  50 +
  51 + &:nth-of-type(3n) {
  52 + margin-right: 0;
  53 + }
  54 +
  55 + .product-detail-img {
  56 + height: 257px;
  57 + }
  58 +
  59 + .price {
  60 + line-height: 34px;
  61 + height: 34px;
  62 + }
  63 + }
  64 +
  65 + .brand-name {
  66 + line-height: 23px;
  67 + font-size: 12px;
  68 + }
  69 + }
  70 +
  71 + .product-source {
  72 + display: block;
  73 + overflow: hidden;
  74 + position: relative;
  75 + }
  76 +
  77 + .feature-product-info {
  78 + float: left;
  79 + width: 288px;
  80 + margin-right: 20px;
  81 + border: 1px solid #eee;
  82 + margin-top: 25px;
  83 + overflow: hidden;
  84 +
  85 + &.novisible {
  86 + visibility: hidden;
  87 + }
  88 +
  89 + &:nth-of-type(2n) {
  90 + margin-right: 0;
  91 + }
  92 +
  93 + a {
  94 + display: block;
  95 + text-decoration: none;
  96 + }
  97 +
  98 + img {
  99 + display: block;
  100 + width: 100%;
  101 + }
  102 +
  103 + .first-part {
  104 + background: #fff;
  105 + }
  106 +
  107 + .product-detail-imgbox {
  108 + position: relative;
  109 +
  110 + .product-detail-img {
  111 + width: 100%;
  112 + height: 380px;
  113 + }
  114 + }
  115 +
  116 + .product-name {
  117 + display: -webkit-box;
  118 + -webkit-box-orient: vertical;
  119 + -webkit-line-clamp: 2;
  120 + overflow: hidden;
  121 + color: #444;
  122 + height: 60px;
  123 + line-height: 35px;
  124 + padding: 0 5px;
  125 + }
  126 +
  127 + .leftopimg {
  128 + position: absolute;
  129 + left: 0;
  130 + top: 0;
  131 + width: 40%;
  132 + height: auto;
  133 + z-index: 1;
  134 + }
  135 +
  136 + .rigtopimg {
  137 + position: absolute;
  138 + right: 0;
  139 + top: 0;
  140 + width: 40%;
  141 + height: auto;
  142 + z-index: 1;
  143 + }
  144 +
  145 + .price {
  146 + font-size: 18px;
  147 + line-height: 40px;
  148 + height: 40px;
  149 + white-space: nowrap;
  150 + text-align: center;
  151 + }
  152 +
  153 + .sale-price {
  154 + color: #f73207;
  155 + font-size: 30px;
  156 + }
  157 +
  158 + .market-price {
  159 + margin: 0 0 0 3px;
  160 + color: #bebebe;
  161 + text-decoration: line-through;
  162 + }
  163 + }
  164 +
  165 + .second-part {
  166 + display: block;
  167 + color: #fff;
  168 + font-size: 32px;
  169 + position: relative;
  170 +
  171 + .brand-div {
  172 + position: absolute;
  173 + top: 8px;
  174 + left: 50%;
  175 + width: 100%;
  176 + transform: translateX(-50%);
  177 + }
  178 +
  179 + .brand-name {
  180 + display: -webkit-box;
  181 + -webkit-box-orient: vertical;
  182 + -webkit-line-clamp: 1;
  183 + text-align: center;
  184 + line-height: 30px;
  185 + overflow: hidden;
  186 + font-size: 26px;
  187 + }
  188 +
  189 + .brand-img {
  190 + display: block;
  191 + margin: 0 auto;
  192 + }
  193 + }
  194 +}
  1 +@charset "utf-8";
  2 +/* CSS Document */
  3 +
  4 +/**
  5 + * Swiper 3.1.7
  6 + * Most modern mobile touch slider and framework with hardware accelerated transitions
  7 + *
  8 + * http://www.idangero.us/swiper/
  9 + *
  10 + * Copyright 2015, Vladimir Kharlampidi
  11 + * The iDangero.us
  12 + * http://www.idangero.us/
  13 + *
  14 + * Licensed under MIT
  15 + *
  16 + * Released on: October 10, 2015
  17 + */
  18 +.swiper-container {
  19 + margin: 0 auto;
  20 + position: relative;
  21 + overflow: hidden;
  22 + /*z-index: 1*/
  23 +}
  24 +
  25 +.swiper-container-no-flexbox .swiper-slide {
  26 + float: left;
  27 +}
  28 +
  29 +.swiper-container-vertical > .swiper-wrapper {
  30 + -webkit-box-orient: vertical;
  31 + -moz-box-orient: vertical;
  32 + -ms-flex-direction: column;
  33 + -webkit-flex-direction: column;
  34 + flex-direction: column;
  35 +}
  36 +
  37 +.swiper-wrapper {
  38 + position: relative;
  39 + width: 100%;
  40 + height: 100%;
  41 + z-index: 1;
  42 + display: -webkit-box;
  43 + display: -moz-box;
  44 + display: -ms-flexbox;
  45 + display: -webkit-flex;
  46 + display: flex;
  47 + -webkit-transition-property: -webkit-transform;
  48 + -moz-transition-property: -moz-transform;
  49 + -o-transition-property: -o-transform;
  50 + -ms-transition-property: -ms-transform;
  51 + transition-property: transform;
  52 + -webkit-box-sizing: content-box;
  53 + -moz-box-sizing: content-box;
  54 + box-sizing: content-box;
  55 +}
  56 +
  57 +.swiper-container-android .swiper-slide,
  58 +.swiper-wrapper {
  59 + -webkit-transform: translate3d(0, 0, 0);
  60 + -moz-transform: translate3d(0, 0, 0);
  61 + -o-transform: translate(0, 0);
  62 + -ms-transform: translate3d(0, 0, 0);
  63 + transform: translate3d(0, 0, 0);
  64 +}
  65 +
  66 +.swiper-container-multirow > .swiper-wrapper {
  67 + -webkit-box-lines: multiple;
  68 + -moz-box-lines: multiple;
  69 + -ms-flex-wrap: wrap;
  70 + -webkit-flex-wrap: wrap;
  71 + flex-wrap: wrap;
  72 +}
  73 +
  74 +.swiper-container-free-mode > .swiper-wrapper {
  75 + -webkit-transition-timing-function: ease-out;
  76 + -moz-transition-timing-function: ease-out;
  77 + -ms-transition-timing-function: ease-out;
  78 + -o-transition-timing-function: ease-out;
  79 + transition-timing-function: ease-out;
  80 + margin: 0 auto;
  81 +}
  82 +
  83 +.swiper-slide {
  84 + -webkit-flex-shrink: 0;
  85 + -ms-flex: 0 0 auto;
  86 + flex-shrink: 0;
  87 + width: 100%;
  88 + height: 100%;
  89 + position: relative;
  90 +}
  91 +
  92 +.swiper-container .swiper-notification {
  93 + position: absolute;
  94 + left: 0;
  95 + top: 0;
  96 + pointer-events: none;
  97 + opacity: 0;
  98 + z-index: -1000;
  99 +}
  100 +
  101 +.swiper-wp8-horizontal {
  102 + -ms-touch-action: pan-y;
  103 + touch-action: pan-y;
  104 +}
  105 +
  106 +.swiper-wp8-vertical {
  107 + -ms-touch-action: pan-x;
  108 + touch-action: pan-x;
  109 +}
  110 +
  111 +.swiper-button-next,
  112 +.swiper-button-prev {
  113 + position: absolute;
  114 + top: 50%;
  115 + width: 27px;
  116 + height: 44px;
  117 + margin-top: -22px;
  118 + z-index: 10;
  119 + cursor: pointer;
  120 + -moz-background-size: 27px 44px;
  121 + -webkit-background-size: 27px 44px;
  122 + background-size: 27px 44px;
  123 + background-position: center;
  124 + background-repeat: no-repeat;
  125 +}
  126 +
  127 +.swiper-button-next.swiper-button-disabled,
  128 +.swiper-button-prev.swiper-button-disabled {
  129 + opacity: 0.35;
  130 + cursor: auto;
  131 + pointer-events: none;
  132 +}
  133 +
  134 +.swiper-pagination {
  135 + position: absolute;
  136 + text-align: center;
  137 + -webkit-transition: 0.3s;
  138 + -moz-transition: 0.3s;
  139 + -o-transition: 0.3s;
  140 + transition: 0.3s;
  141 + -webkit-transform: translate3d(0, 0, 0);
  142 + -ms-transform: translate3d(0, 0, 0);
  143 + -o-transform: translate3d(0, 0, 0);
  144 + transform: translate3d(0, 0, 0);
  145 + z-index: 10;
  146 +}
  147 +
  148 +.swiper-pagination.swiper-pagination-hidden {
  149 + opacity: 0;
  150 +}
  151 +
  152 +.swiper-pagination-bullet {
  153 + width: 8px;
  154 + height: 8px;
  155 + border-radius: 50%;
  156 + display: inline-block;
  157 + background: #9b9b9a;
  158 + opacity: 1;
  159 +}
  160 +
  161 +button.swiper-pagination-bullet {
  162 + border: none;
  163 + margin: 0;
  164 + padding: 0;
  165 + box-shadow: none;
  166 + -moz-appearance: none;
  167 + -ms-appearance: none;
  168 + -webkit-appearance: none;
  169 + appearance: none;
  170 +}
  171 +
  172 +.swiper-pagination-clickable .swiper-pagination-bullet {
  173 + cursor: pointer;
  174 +}
  175 +
  176 +.swiper-pagination-white .swiper-pagination-bullet {
  177 + background: #fff;
  178 +}
  179 +
  180 +.swiper-pagination-bullet-active {
  181 + opacity: 1;
  182 + background: #383838;
  183 +}
  184 +
  185 +.swiper-pagination-white .swiper-pagination-bullet-active {
  186 + background: #fff;
  187 +}
  188 +
  189 +.swiper-pagination-black .swiper-pagination-bullet-active {
  190 + background: #000;
  191 +}
  192 +
  193 +.swiper-container-vertical > .swiper-pagination {
  194 + right: 10px;
  195 + top: 50%;
  196 + -webkit-transform: translate3d(0, -50%, 0);
  197 + -moz-transform: translate3d(0, -50%, 0);
  198 + -o-transform: translate(0, -50%);
  199 + -ms-transform: translate3d(0, -50%, 0);
  200 + transform: translate3d(0, -50%, 0);
  201 +}
  202 +
  203 +.swiper-container-vertical > .swiper-pagination .swiper-pagination-bullet {
  204 + margin: 5px 0;
  205 + display: block;
  206 +}
  207 +
  208 +.swiper-container-horizontal > .swiper-pagination {
  209 + bottom: 0;
  210 + right: 0;
  211 + width: 100%;
  212 +}
  213 +
  214 +.swiper-container-horizontal > .swiper-pagination .swiper-pagination-bullet {
  215 + margin: 0 3px;
  216 +}
  217 +
  218 +.swiper-container-3d {
  219 + -webkit-perspective: 1200px;
  220 + -moz-perspective: 1200px;
  221 + -o-perspective: 1200px;
  222 + perspective: 1200px;
  223 +}
  224 +
  225 +.swiper-container-3d .swiper-cube-shadow,
  226 +.swiper-container-3d .swiper-slide,
  227 +.swiper-container-3d .swiper-slide-shadow-bottom,
  228 +.swiper-container-3d .swiper-slide-shadow-left,
  229 +.swiper-container-3d .swiper-slide-shadow-right,
  230 +.swiper-container-3d .swiper-slide-shadow-top,
  231 +.swiper-container-3d .swiper-wrapper {
  232 + -webkit-transform-style: preserve-3d;
  233 + -moz-transform-style: preserve-3d;
  234 + -ms-transform-style: preserve-3d;
  235 + transform-style: preserve-3d;
  236 +}
  237 +
  238 +.swiper-container-3d .swiper-slide-shadow-bottom,
  239 +.swiper-container-3d .swiper-slide-shadow-left,
  240 +.swiper-container-3d .swiper-slide-shadow-right,
  241 +.swiper-container-3d .swiper-slide-shadow-top {
  242 + position: absolute;
  243 + left: 0;
  244 + top: 0;
  245 + width: 100%;
  246 + height: 100%;
  247 + pointer-events: none;
  248 + z-index: 10;
  249 +}
  250 +
  251 +.swiper-container-3d .swiper-slide-shadow-left {
  252 + background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
  253 + background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  254 + background-image: -moz-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  255 + background-image: -o-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  256 + background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  257 +}
  258 +
  259 +.swiper-container-3d .swiper-slide-shadow-right {
  260 + background-image: -webkit-gradient(linear, right top, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
  261 + background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  262 + background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  263 + background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  264 + background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  265 +}
  266 +
  267 +.swiper-container-3d .swiper-slide-shadow-top {
  268 + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
  269 + background-image: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  270 + background-image: -moz-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  271 + background-image: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  272 + background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  273 +}
  274 +
  275 +.swiper-container-3d .swiper-slide-shadow-bottom {
  276 + background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
  277 + background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  278 + background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  279 + background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  280 + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  281 +}
  282 +
  283 +.swiper-container-coverflow .swiper-wrapper {
  284 + -ms-perspective: 1200px;
  285 +}
  286 +
  287 +.swiper-container-fade.swiper-container-free-mode .swiper-slide {
  288 + -webkit-transition-timing-function: ease-out;
  289 + -moz-transition-timing-function: ease-out;
  290 + -ms-transition-timing-function: ease-out;
  291 + -o-transition-timing-function: ease-out;
  292 + transition-timing-function: ease-out;
  293 +}
  294 +
  295 +.swiper-container-fade .swiper-slide {
  296 + pointer-events: none;
  297 +}
  298 +
  299 +.swiper-container-fade .swiper-slide .swiper-slide {
  300 + pointer-events: none;
  301 +}
  302 +
  303 +.swiper-container-fade .swiper-slide-active,
  304 +.swiper-container-fade .swiper-slide-active .swiper-slide-active {
  305 + pointer-events: auto;
  306 +}
  307 +
  308 +.swiper-container-cube {
  309 + overflow: visible;
  310 +}
  311 +
  312 +.swiper-container-cube .swiper-slide {
  313 + pointer-events: none;
  314 + visibility: hidden;
  315 + -webkit-transform-origin: 0 0;
  316 + -moz-transform-origin: 0 0;
  317 + -ms-transform-origin: 0 0;
  318 + transform-origin: 0 0;
  319 + -webkit-backface-visibility: hidden;
  320 + -moz-backface-visibility: hidden;
  321 + -ms-backface-visibility: hidden;
  322 + backface-visibility: hidden;
  323 + width: 100%;
  324 + height: 100%;
  325 + z-index: 1;
  326 +}
  327 +
  328 +.swiper-container-cube.swiper-container-rtl .swiper-slide {
  329 + -webkit-transform-origin: 100% 0;
  330 + -moz-transform-origin: 100% 0;
  331 + -ms-transform-origin: 100% 0;
  332 + transform-origin: 100% 0;
  333 +}
  334 +
  335 +.swiper-container-cube .swiper-slide-active,
  336 +.swiper-container-cube .swiper-slide-next,
  337 +.swiper-container-cube .swiper-slide-next + .swiper-slide,
  338 +.swiper-container-cube .swiper-slide-prev {
  339 + pointer-events: auto;
  340 + visibility: visible;
  341 +}
  342 +
  343 +.swiper-container-cube .swiper-slide-shadow-bottom,
  344 +.swiper-container-cube .swiper-slide-shadow-left,
  345 +.swiper-container-cube .swiper-slide-shadow-right,
  346 +.swiper-container-cube .swiper-slide-shadow-top {
  347 + z-index: 0;
  348 + -webkit-backface-visibility: hidden;
  349 + -moz-backface-visibility: hidden;
  350 + -ms-backface-visibility: hidden;
  351 + backface-visibility: hidden;
  352 +}
  353 +
  354 +.swiper-container-cube .swiper-cube-shadow {
  355 + position: absolute;
  356 + left: 0;
  357 + bottom: 0;
  358 + width: 100%;
  359 + height: 100%;
  360 + background: #000;
  361 + opacity: 0.6;
  362 + -webkit-filter: blur(50px);
  363 + filter: blur(50px);
  364 + z-index: 0;
  365 +}
  366 +
  367 +.swiper-scrollbar {
  368 + border-radius: 10px;
  369 + position: relative;
  370 + -ms-touch-action: none;
  371 + background: rgba(0, 0, 0, 0.1);
  372 +}
  373 +
  374 +.swiper-container-horizontal > .swiper-scrollbar {
  375 + position: absolute;
  376 + left: 1%;
  377 + bottom: 3px;
  378 + z-index: 50;
  379 + height: 5px;
  380 + width: 98%;
  381 +}
  382 +
  383 +.swiper-container-vertical > .swiper-scrollbar {
  384 + position: absolute;
  385 + right: 3px;
  386 + top: 1%;
  387 + z-index: 50;
  388 + width: 5px;
  389 + height: 98%;
  390 +}
  391 +
  392 +.swiper-scrollbar-drag {
  393 + height: 100%;
  394 + width: 100%;
  395 + position: relative;
  396 + background: rgba(0, 0, 0, 0.5);
  397 + border-radius: 10px;
  398 + left: 0;
  399 + top: 0;
  400 +}
  401 +
  402 +.swiper-scrollbar-cursor-drag {
  403 + cursor: move;
  404 +}
@@ -5,7 +5,79 @@ const _ = require('lodash'); @@ -5,7 +5,79 @@ const _ = require('lodash');
5 const config = require('../config/common'); 5 const config = require('../config/common');
6 const assetUrl = config.assetUrl; 6 const assetUrl = config.assetUrl;
7 7
  8 +const unitfromat = function(value, params) {
  9 + if (params.rem) {
  10 + value = Number(value) / (params.width || 40) + 'rem';
  11 + } else if (params.percent) {
  12 + value = value + '%';
  13 + } else {
  14 + value = value + 'px';
  15 + }
  16 +
  17 + return value;
  18 +};
  19 +
8 module.exports = { 20 module.exports = {
  21 + getAnalysis: function(data, index) {
  22 + if (!data) {
  23 + return '';
  24 + }
  25 +
  26 + let fp = {
  27 + F_ID: data.id,
  28 + F_INDEX: data.order,
  29 + F_NM: data.param.name,
  30 + I_INDEX: index
  31 + };
  32 +
  33 + if (data.component[index] && data.component[index].name) {
  34 + fp.I_NM = data.component[index].name;
  35 + }
  36 + return JSON.stringify(fp);
  37 + },
  38 + styleFormat: function(styleObj, opts) {
  39 + let style = '';
  40 +
  41 + if (styleObj && _.isObject(styleObj)) {
  42 + let params = opts.hash;
  43 + let keys = ['width', 'height', 'top', 'left', 'right', 'bottom'];
  44 +
  45 + keys.forEach(function(k) {
  46 + if (styleObj[k]) {
  47 + style += k + ':' + unitfromat(styleObj[k], params) + ';';
  48 + }
  49 + });
  50 + }
  51 + return style;
  52 + },
  53 + tabStyle: function(index, count) {
  54 + let width = (100 / Number(count)).toFixed(2);
  55 + let style = 'height:100%;width:' + width + '%;';
  56 +
  57 + style += 'left:' + (Number(index) * Number(width)) + '%;';
  58 + return style;
  59 + },
  60 + stringify: function(obj) {
  61 + return JSON.stringify(obj);
  62 + },
  63 + repeat: function(n, options) {
  64 + if (n) {
  65 + var str = '';
  66 +
  67 + for (var i = 0; i < n; i++) {
  68 + var opt = {
  69 + index: i,
  70 + first: i === 0
  71 + };
  72 +
  73 + str += options.fn(options, {
  74 + data: _.merge(opt, options)
  75 + });
  76 + }
  77 + return str;
  78 + }
  79 + return options.inverse(this);
  80 + },
9 imgSrc: function(imgSrc) { 81 imgSrc: function(imgSrc) {
10 return url.resolve(assetUrl, imgSrc); 82 return url.resolve(assetUrl, imgSrc);
11 }, 83 },
@@ -35,7 +107,7 @@ module.exports = { @@ -35,7 +107,7 @@ module.exports = {
35 } else if (params.q) { 107 } else if (params.q) {
36 query += '/quality/' + params.q; 108 query += '/quality/' + params.q;
37 } 109 }
38 - } else if (query.indexOf('imageView/') === 0){ 110 + } else if (query.indexOf('imageView/') === 0) {
39 if (params.q && query.indexOf('/q/') > 0) { 111 if (params.q && query.indexOf('/q/') > 0) {
40 query = query.replace(/\/q\/\d+/g, '/q/' + params.q); 112 query = query.replace(/\/q\/\d+/g, '/q/' + params.q);
41 } else if (params.q) { 113 } else if (params.q) {
@@ -54,6 +126,43 @@ module.exports = { @@ -54,6 +126,43 @@ module.exports = {
54 return ''; 126 return '';
55 } 127 }
56 }, 128 },
  129 + isEqualOr: function() {
  130 + var args = Array.prototype.slice.call(arguments);
  131 + var v1 = args[0];
  132 + var opt = args[args.length - 1];
  133 + var isTrue = false;
  134 +
  135 + for (var i = 1; i < args.length - 1; i++) {
  136 + if (v1 === args[i]) {
  137 + isTrue = true;
  138 + break;
  139 + }
  140 + }
  141 +
  142 + if (isTrue) {
  143 + return opt.fn(this); // eslint-disable-line
  144 + } else {
  145 + return opt.inverse(this); // eslint-disable-line
  146 + }
  147 + },
  148 + ifand: function() {
  149 + var args = Array.prototype.slice.call(arguments);
  150 + var opt = args[args.length - 1];
  151 + var isTrue = true;
  152 +
  153 + for (var i = 0; i < args.length - 1; i++) {
  154 + if (!args[i]) {
  155 + isTrue = false;
  156 + break;
  157 + }
  158 + }
  159 +
  160 + if (isTrue) {
  161 + return opt.fn(this);
  162 + } else {
  163 + return opt.inverse(this);
  164 + }
  165 + },
57 ifor: function() { 166 ifor: function() {
58 var args = Array.prototype.slice.call(arguments); 167 var args = Array.prototype.slice.call(arguments);
59 var opt = args[args.length - 1]; 168 var opt = args[args.length - 1];