javascript Issue84 - 20190620电话导线改善

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript Issue84 - 20190620电话导线改善相关的知识,希望对你有一定的参考价值。

import get from 'lodash/get'

const pageId = document.body.getAttribute('data-pageid')
// トップページかどうか
export const isTopPage = pageId === 'top'
// コース一覧かどうか
export const isReservePage = pageId === 'reserve'

// ポイントON/OFF
/* eslint no-magic-numbers: 0 */
const pointFlg = get(window, 'window.sc_plan_data.plan_existence3')
export const isPointOn = pointFlg === '1' || pointFlg === '3'

// トップページ: 吹き出しが`-cp-target`であればキャンペーン対象
export const isCampaignTop = isTopPage && document.querySelector('.button__balloon.-cp-target') !== null

// コース一覧: キャンペーンバナーがあればキャンペーン対象
export const isCampaignPlanList = isReservePage && document.querySelector('.cp-modal-trigger') !== null

// 第一引数で渡すセレクターに第二引数で渡す文字列を含む要素があれば返却
// jQueryの :contains() 代替
export const contains = (selector, text) => {
  const elms = document.querySelectorAll(selector)
  return Array.prototype.filter.call(elms, elm => RegExp(text).test(elm.textContent))
}
function callbackFn(activate, options) {
  var utils = window.optimizely.get('utils');
  var $ = window.optimizely.get('jquery');

  utils.waitForElement('.headerCV .ic-plan-cal').then(function() {
    var target = $('.headerCV .ic-plan-cal');

    var cancelPolling = utils.poll(function() {
      var telNum = window.GNAVI.ShopData.tel;
      var isPPC = /^050/.test(telNum);
      if (target.length > 0 && isPPC) {
        cancelPolling();
        activate();
      } else {
        cancelPolling();
      }
    }, 100);
  });

  utils.waitForElement('.planCal form').then(function() {
    var target = $('.planCal');

    var cancelPolling = utils.poll(function() {
      var telNum = window.GNAVI.ShopData.tel;
      var isPPC = /^050/.test(telNum);
      if (target.length > 0 && isPPC) {
        cancelPolling();
        activate();
      } else {
        cancelPolling();
      }
    }, 100);
  });
}
import { contains } from '../utils'

const changeReserveBtnTxt = (btn, cls, txtElm, txt) => {
  const map = {
    pt1: '電話・ネット予約',
    pt2: '予約する',
    pt3: '空席確認・予約',
  }

  btn.classList.add(cls)
  /* eslint no-param-reassign: 0 */
  txtElm.textContent = map[txt]
}

const reserveBtn = txt => {
  const ISSUE_CLASS = 'issue84'

  // headerCV
  const headerCV = document.querySelector('.headerCV')
  // コース一覧では何もしない
  if (!headerCV) return

  headerCV.classList.add(ISSUE_CLASS)

  // footerCV
  const footerCV = document.querySelector('.footerShopCV')
  footerCV.classList.add(ISSUE_CLASS)

  // 追従エリア
  const stickyReserveWrap = document.getElementById('js-reserve-btn')
  const stickyReserveBtnWrap = stickyReserveWrap.querySelector('.ic-net-yoyaku').parentNode.parentNode

  stickyReserveWrap.classList.add(ISSUE_CLASS)
  stickyReserveBtnWrap.classList.remove('col__12', 'col__9', '-pl8')

  // 各ボタンの文言変更
  if (txt) {
    const headerReserveTxt = contains('.headerCV span', 'ネット予約する')[0]
    const footerReserveTxt = contains('.footerShopCV span', 'ネット予約する')[0]
    const stickyReserveTxt = contains('#js-reserve-btn span', 'ネット予約する')[0]
    const headerReserveBtn = headerCV.querySelector('.ic-net-yoyaku')
    const footerReserveBtn = footerCV.querySelector('.hf-ic-net-yoyaku')
    const stickyReserveBtn = stickyReserveWrap.querySelector('.ic-net-yoyaku')
    const NO_ICON_CLASS = '-no-icon'

    changeReserveBtnTxt(headerReserveBtn, NO_ICON_CLASS, headerReserveTxt, txt)
    changeReserveBtnTxt(footerReserveBtn, NO_ICON_CLASS, footerReserveTxt, txt)
    changeReserveBtnTxt(stickyReserveBtn, NO_ICON_CLASS, stickyReserveTxt, txt)
  }

  // 追従エリアに電話するボタンがある場合は削除
  const telStickyBtn = stickyReserveWrap.querySelector('.ic-tel-sticky')
  if (!telStickyBtn) return

  const telStickyBtnWrap = stickyReserveWrap.querySelector('.ic-tel-sticky').parentNode.parentNode
  telStickyBtnWrap.parentNode.removeChild(telStickyBtnWrap)
}

export default reserveBtn
const pointUseModal = () => {
  const pointUseModalTrigger = document.getElementById('js-pointUseModal')
  if (!pointUseModalTrigger) return

  pointUseModalTrigger.addEventListener('click', () => {
    const pointUseModalBtn = document.querySelector('.new-point-use-modal__reserve-button a')
    const pointUseModalBtnHref = pointUseModalBtn.getAttribute('href').replace(/#.*$/, '')
    // モーダル内の既存のボタンが「ネット予約する」ボタンのhrefをコピーしているので今回追加したハッシュがここでも付いてしまう
    // 不要なので削除
    pointUseModalBtn.setAttribute('href', pointUseModalBtnHref)
  })
}

export default pointUseModal
import forEach from 'lodash/forEach'
import get from 'lodash/get'
import Path from '../../../utils/path'
import { isTopPage, isPointOn, isCampaignTop, isCampaignPlanList } from '../utils'

const MODAL_CLOSE_TRIGGER = 'js-point-tel-modal-close-trg'
// GNAVI変数から環境ごとの画像パスをゲット
const modalImgRootPath = new Path('sp').get('image')
const telNumber = get(window, 'window.GNAVI.ShopData.tel')
const modalBtnTxt = isTopPage ? 'コース一覧・予約' : 'ネット予約コースを見る'

const setPointImgName = () => {
  let pointImgName = 'modal_point'

  if (!isPointOn) {
    // ポイントOFF
    pointImgName = `${pointImgName}_off`
  } else if (isCampaignTop || isCampaignPlanList) {
    // ポイントON & キャンペーン対象
    const campaignBnr = document.querySelector('.cp-modal-trigger img')
    if (!campaignBnr) return true
    const campaignBnrSrc = campaignBnr.getAttribute('src')

    // 2倍 | 3倍
    if (campaignBnrSrc.match('x2')) {
      pointImgName = `${pointImgName}_x2`
    } else {
      pointImgName = `${pointImgName}_x3`
    }
  } else {
    // ポイントON & キャンペーン対象外
    pointImgName = `${pointImgName}_x0`
  }

  return pointImgName
}

const modalStrDOM = `
<div class="point-tel-modal ${MODAL_CLOSE_TRIGGER}">
        <div class="point-tel-modal__inner">
            <div class="point-tel-modal__body">
                <p><img src="${modalImgRootPath}img/issue84/${setPointImgName()}.png" alt=""></p>
                <button type="button" class="point-tel-modal__btn -base">${modalBtnTxt}</button>
            </div>

            <div class="point-tel-modal__body -tel">
                <p>電話予約の場合、ポイントは貯まりません。</p>
                <a href="tel:${telNumber}" class="issue84__tel-btn -clr-link" onclick="sc_count('r-smp_plan-reserve-modal_phone_to')">${telNumber}</a>
            </div>

            <button type="button" class="point-tel-modal__btn -close-text ${MODAL_CLOSE_TRIGGER}" onclick="sc_count('r-smp_plan-reserve-modal_close')">閉じる</button>
            <button type="button" class="point-tel-modal__btn -close-icon ${MODAL_CLOSE_TRIGGER}" onclick="sc_count('r-smp_plan-reserve-modal_close')"></button>
        </div>
    </div>
`

const pointTelModal = () => {
  const modalContainer = document.createElement('div')
  const page = document.getElementById('page')

  const offsetTop = window.pageYOffset
  // ページを固定してモーダル下がスクロールしないように
  page.setAttribute('style', `position: fixed; z-index: 10; top: -${offsetTop}px; left: 0; width: 100%;`)
  page.appendChild(modalContainer)

  modalContainer.setAttribute('class', 'point-tel-modal-container')
  modalContainer.innerHTML = modalStrDOM

  const closeTriggers = document.getElementsByClassName(MODAL_CLOSE_TRIGGER)
  const modalBodys = document.querySelectorAll('.point-tel-modal__body')
  const pointTelModalInner = document.querySelector('.point-tel-modal__inner')
  const pointTelModalBtn = document.querySelector('.point-tel-modal__btn.-base')

  // 計測
  pointTelModalBtn.addEventListener('click', () => {
    window.sc_count('r-smp_plan-reserve-modal_planbtn')
  })

  // トップページとコース一覧でボタンの役割が変わる
  if (isTopPage) {
    // モーダル内のボタンにハッシュは不要なので削除
    const reserveBtnHref = document
      .querySelector('.js-plan-reserve-button')
      .getAttribute('href')
      .replace(/#.*$/, '')
    pointTelModalBtn.setAttribute('onclick', `location.href='${reserveBtnHref}'`)
  } else {
    pointTelModalBtn.classList.add(MODAL_CLOSE_TRIGGER)
  }

  if (!isPointOn) pointTelModalInner.classList.add('-point-off')

  // モーダルの本体(背景が白い部分)をタップしてもモーダルは閉じないように
  forEach(modalBodys, modalBody => {
    modalBody.addEventListener('click', ev => {
      ev.stopPropagation()
    })
  })

  forEach(closeTriggers, closeTrigger => {
    closeTrigger.addEventListener('click', ev => {
      ev.stopPropagation()

      // ページ固定のstyleを削除
      page.removeAttribute('style')
      // styleがリムーブされるとscrollが0に戻るため元の位置に戻す
      scroll(0, offsetTop)

      modalContainer.parentNode.removeChild(modalContainer)
    })
  })
}

export default pointTelModal
import pointTelModal from '../pointTelModal'

const planList = () => {
  const hash = window.location.hash.replace('#', '')
  const isHash = () => /rs-smp_plan_list_0[4-6]/.test(hash)
  // 規定のハッシュ以外でコース一覧に来ても何もしない
  if (!isHash()) return

  // ブラウザバックで戻った時はモーダルが起動しないようにハッシュを変更
  location.hash = '_'
  pointTelModal()
}

export default planList
const headerCV = document.querySelector('.headerCV')
const footerCV = document.querySelector('.footerShopCV')

const attachPopover = () => {
  // 以下 /src/alljs/popover.js より
  /* global someFunction GNAVI:true */
  new GNAVI.Dialog.Popover({
    button: '.js-popover-button',
    targetId: '#popover_calendar',
  })
}

export const replaceWaitingBtn = () => {
  const waitingBtn = document.getElementById('js-waiting-service-button')
  if (!waitingBtn) return

  const headerPlanCalBtnWrap = headerCV.querySelector('.ic-plan-cal').parentNode.parentNode.parentNode.parentNode

  if (headerPlanCalBtnWrap.parentNode) {
    headerPlanCalBtnWrap.parentNode.insertBefore(waitingBtn, headerPlanCalBtnWrap.nextSibling)
  }
}

export const planCalBtn = flg => {
  // コース一覧では何もしない
  if (!headerCV) return

  const headerReserveBtn = headerCV.querySelector('.ic-net-yoyaku').parentNode
  const headerplanCalBtn = headerCV.querySelector('.ic-plan-cal').parentNode.parentNode.parentNode.parentNode
  const footerReserveBtn = footerCV.querySelector('.hf-ic-net-yoyaku').parentNode
  const footerplanCalBtn = footerCV.querySelector('.hf-ic-plan-cal').parentNode.parentNode.parentNode.parentNode
  const reserveBtnStickyWrap = document.getElementById('js-reserve-btn')
  const reserveStickyBtn = reserveBtnStickyWrap.querySelector('.ic-net-yoyaku').parentNode

  // 空席通知ボタンがあったら空席確認ボタン右に移動(ページ上部のCVエリアのみ)
  replaceWaitingBtn()
  // 空席確認ボタン削除
  headerplanCalBtn.parentNode.removeChild(headerplanCalBtn)
  footerplanCalBtn.parentNode.removeChild(footerplanCalBtn)

  // 追加で空席確認モーダルのイベントをアタッチ
  if (flg === 'attach') {
    headerReserveBtn.classList.add('js-popover-button')
    footerReserveBtn.classList.add('js-popover-button')
    reserveStickyBtn.classList.add('js-popover-button')
    attachPopover()
    // onclickの値も変更
    headerReserveBtn.setAttribute('onclick', "sc_count('plan_list_01')")
    footerReserveBtn.setAttribute('onclick', "sc_count('plan_list_02')")
  }
}
import forEach from 'lodash/forEach'
import { isPointOn } from '../utils'

const hideTelContainer = container => {
  const planCalBtnCourse = document.querySelector('.button--width-255 .js-popover-button')
  if (!planCalBtnCourse) return

  planCalBtnCourse.addEventListener('click', () => {
    /* eslint no-param-reassign: 0 */
    container.style.display = 'none'
  })
}

const planCal = flg => {
  const calendar = document.getElementById('popover_calendar')
  // コース一覧では何もしない
  if (!calendar) return
  const calendarTitle = calendar.querySelector('.planCal__title__body')
  const pointImg = calendar.querySelector('.issue84__reserve-point')
  const telNumber = calendar.querySelector('.issue84__tel')
  const closeBtnWrap = calendar.querySelector('.issue84__popover-close')
  const closeBtns = calendar.querySelectorAll('.js-popover-close')

  calendar.classList.add('issue84')

  if (isPointOn) {
    calendarTitle.parentNode.removeChild(calendarTitle)
  } else {
    calendarTitle.classList.add('-point-off')
    pointImg.classList.add('-point-off')
  }

  pointImg.style.display = 'block'
  closeBtnWrap.style.display = 'block'

  // #3のみ電話番号枠表示
  if (flg === 'tel') {
    // 一旦表示
    telNumber.style.display = 'block'
    // ページ途中「おすすめコース」枠にある空席確認ボタンをタップした場合は電話番号枠を非表示
    hideTelContainer(telNumber)

    // モーダルを閉じた時は常にblock
    forEach(closeBtns, closeBtn => {
      closeBtn.addEventListener('touchstart', ev => {
        ev.preventDefault()
        // モーダルがフェードアウトする時間分ずらさせないと先に見えてしまう
        const DELAY_TIME = 300

        setTimeout(() => {
          telNumber.style.display = 'block'
        }, DELAY_TIME)
      })
    })
  }

  // 計測追加
  // 空席確認モーダルのオリジナルコードで`.js-popover-close`にtouchstartが使われているのでclickでは動かない
  forEach(closeBtns, closeBtn => {
    closeBtn.addEventListener('touchstart', ev => {
      ev.preventDefault()
      window.sc_count('r-smp_plancal-modal_close')
    })
  })
}

export default planCal
import smoothscroll from 'smoothscroll-polyfill'

// Safariが behavior: 'smooth' オプションに対応してないので
// kick off the polyfill!
smoothscroll.polyfill()

const info = () => {
  const infoWrap = document.querySelector('.topHeader')
  // コース一覧では何もしない
  if (!infoWrap) return
  infoWrap.classList.add('issue84')

  // Nodelistを配列に変換
  const basicInfoAnchorWrapArray = Array.from(infoWrap.querySelectorAll('.topHeader__body'))
  // メインが動画の場合にDOMが2つ存在するので最後(後の方)を指定
  const basicInfoAnchorContainer = basicInfoAnchorWrapArray.slice(-1)[0]
  const basicInfoAnchorWrap = document.createElement('p')
  const basicInfoAnchor = document.createElement('a')

  basicInfoAnchor.textContent = 'お店の詳細を見る'
  basicInfoAnchor.setAttribute('href', '#basicInfo')
  basicInfoAnchor.setAttribute('onclick', "sc_count('r-smp_goinfo')")
  basicInfoAnchor.classList.add('text--minor', 'basic-info-anchor')
  basicInfoAnchorWrap.appendChild(basicInfoAnchor)
  basicInfoAnchorContainer.appendChild(basicInfoAnchorWrap)

  basicInfoAnchor.addEventListener('click', ev => {
    ev.preventDefault()
    const targetId = ev.target.hash
    const targetElm = document.querySelector(targetId)
    const globalNavHeight = document.getElementById('js-globalNav').getBoundingClientRect().height
    // 画面上部から要素までの距離
    const rectTop = targetElm.getBoundingClientRect().top
    // 現在のスクロール距離
    const offsetTop = window.pageYOffset
    // 追従するグロナビの高さを抜く
    const top = rectTop + offsetTop - globalNavHeight

    window.scrollTo({
      top,
      behavior: 'smooth',
    })
  })
}

export default info

以上是关于javascript Issue84 - 20190620电话导线改善的主要内容,如果未能解决你的问题,请参考以下文章

javascript Issue302:20171018 - 动画商品トライアル

javascript Issue319:20171101 - バナーとモーダルとAMP

javascript Issue15:20180705 - no79.CVエリア改善

javascript Issue30:20180920 - no82。他店铺リンク设置

javascript Issue345:20180130 - no63。ナビゲーションに「地図」追加

javascript Issue76 - 20190417 - no109。他店铺リンクの情报调整