import { camelize, extend, isString, isHTMLTag, isSVGTag, isPlainObject, isArray } from '@vue/shared'; function formatKey(key) { return camelize(key.substring(5)); } function initCostomDataset() { const prototype = HTMLElement.prototype; const setAttribute = prototype.setAttribute; prototype.setAttribute = function (key, value) { if (key.startsWith('data-') && this.tagName.startsWith('UNI-')) { const dataset = this.__uniDataset || (this.__uniDataset = {}); dataset[formatKey(key)] = value; } setAttribute.call(this, key, value); }; const removeAttribute = prototype.removeAttribute; prototype.removeAttribute = function (key) { if (this.__uniDataset && key.startsWith('data-') && this.tagName.startsWith('UNI-')) { delete this.__uniDataset[formatKey(key)]; } removeAttribute.call(this, key); }; } function getCostomDataset(el) { return extend({}, el.dataset, el.__uniDataset); } const unitRE = new RegExp(`"[^"]+"|'[^']+'|url\\([^)]+\\)|(\\d*\\.?\\d+)[r|u]px`, 'g'); function toFixed(number, precision) { const multiplier = Math.pow(10, precision + 1); const wholeNumber = Math.floor(number * multiplier); return (Math.round(wholeNumber / 10) * 10) / multiplier; } const defaultRpx2Unit = { unit: 'rem', unitRatio: 10 / 320, unitPrecision: 5, }; function createRpx2Unit(unit, unitRatio, unitPrecision) { return (val) => val.replace(unitRE, (m, $1) => { if (!$1) { return m; } const value = toFixed(parseFloat($1) * unitRatio, unitPrecision); return value === 0 ? '0' : `${value}${unit}`; }); } function passive(passive) { return { passive }; } function normalizeDataset(el) { // TODO return JSON.parse(JSON.stringify(el.dataset || {})); } function normalizeTarget(el) { const { id, offsetTop, offsetLeft } = el; return { id, dataset: getCostomDataset(el), offsetTop, offsetLeft, }; } function addFont(family, source, desc) { const fonts = document.fonts; if (fonts) { const fontFace = new FontFace(family, source, desc); return fontFace.load().then(() => { fonts.add(fontFace); }); } return new Promise((resolve) => { const style = document.createElement('style'); const values = []; if (desc) { const { style, weight, stretch, unicodeRange, variant, featureSettings } = desc; style && values.push(`font-style:${style}`); weight && values.push(`font-weight:${weight}`); stretch && values.push(`font-stretch:${stretch}`); unicodeRange && values.push(`unicode-range:${unicodeRange}`); variant && values.push(`font-variant:${variant}`); featureSettings && values.push(`font-feature-settings:${featureSettings}`); } style.innerText = `@font-face{font-family:"${family}";src:${source};${values.join(';')}}`; document.head.appendChild(style); resolve(); }); } function scrollTo(scrollTop, duration) { if (isString(scrollTop)) { const el = document.querySelector(scrollTop); if (el) { scrollTop = el.getBoundingClientRect().top + window.pageYOffset; } } if (scrollTop < 0) { scrollTop = 0; } const documentElement = document.documentElement; const { clientHeight, scrollHeight } = documentElement; scrollTop = Math.min(scrollTop, scrollHeight - clientHeight); if (duration === 0) { // 部分浏览器(比如微信)中 scrollTop 的值需要通过 document.body 来控制 documentElement.scrollTop = document.body.scrollTop = scrollTop; return; } if (window.scrollY === scrollTop) { return; } const scrollTo = (duration) => { if (duration <= 0) { window.scrollTo(0, scrollTop); return; } const distaince = scrollTop - window.scrollY; requestAnimationFrame(function () { window.scrollTo(0, window.scrollY + (distaince / duration) * 10); scrollTo(duration - 10); }); }; scrollTo(duration); } function plusReady(callback) { if (typeof callback !== 'function') { return; } if (window.plus) { return callback(); } document.addEventListener('plusready', callback); } const BUILT_IN_TAGS = [ 'ad', 'audio', 'button', 'camera', 'canvas', 'checkbox', 'checkbox-group', 'cover-image', 'cover-view', 'editor', 'form', 'functional-page-navigator', 'icon', 'image', 'input', 'label', 'live-player', 'live-pusher', 'map', 'movable-area', 'movable-view', 'navigator', 'official-account', 'open-data', 'picker', 'picker-view', 'picker-view-column', 'progress', 'radio', 'radio-group', 'rich-text', 'scroll-view', 'slider', 'swiper', 'swiper-item', 'switch', 'text', 'textarea', 'video', 'view', 'web-view', ].map((tag) => 'uni-' + tag); const TAGS = [ 'app', 'layout', 'content', 'main', 'top-window', 'left-window', 'right-window', 'tabbar', 'page', 'page-head', 'page-wrapper', 'page-body', 'page-refresh', 'actionsheet', 'modal', 'toast', 'resize-sensor', 'shadow-root', ].map((tag) => 'uni-' + tag); function isBuiltInComponent(tag) { return BUILT_IN_TAGS.indexOf('uni-' + tag) !== -1; } function isCustomElement(tag) { return TAGS.indexOf(tag) !== -1 || BUILT_IN_TAGS.indexOf(tag) !== -1; } function isNativeTag(tag) { return (isHTMLTag(tag) || isSVGTag(tag)) && !isBuiltInComponent(tag); } const COMPONENT_SELECTOR_PREFIX = 'uni-'; const COMPONENT_PREFIX = 'v-' + COMPONENT_SELECTOR_PREFIX; function getLen(str = '') { return ('' + str).replace(/[^\x00-\xff]/g, '**').length; } function removeLeadingSlash(str) { return str.indexOf('/') === 0 ? str.substr(1) : str; } const invokeArrayFns = (fns, arg) => { let ret; for (let i = 0; i < fns.length; i++) { ret = fns[i](arg); } return ret; }; function updateElementStyle(element, styles) { for (const attrName in styles) { element.style[attrName] = styles[attrName]; } } function once(fn, ctx = null) { let res; return ((...args) => { if (fn) { res = fn.apply(ctx, args); fn = null; } return res; }); } const sanitise = (val) => (val && JSON.parse(JSON.stringify(val))) || val; const _completeValue = (value) => (value > 9 ? value : '0' + value); function formatDateTime({ date = new Date(), mode = 'date' }) { if (mode === 'time') { return (_completeValue(date.getHours()) + ':' + _completeValue(date.getMinutes())); } else { return (date.getFullYear() + '-' + _completeValue(date.getMonth() + 1) + '-' + _completeValue(date.getDate())); } } function callOptions(options, data) { options = options || {}; if (typeof data === 'string') { data = { errMsg: data, }; } if (/:ok$/.test(data.errMsg)) { if (typeof options.success === 'function') { options.success(data); } } else { if (typeof options.fail === 'function') { options.fail(data); } } if (typeof options.complete === 'function') { options.complete(data); } } const encode = encodeURIComponent; function stringifyQuery(obj, encodeStr = encode) { const res = obj ? Object.keys(obj) .map((key) => { let val = obj[key]; if (typeof val === undefined || val === null) { val = ''; } else if (isPlainObject(val)) { val = JSON.stringify(val); } return encodeStr(key) + '=' + encodeStr(val); }) .filter((x) => x.length > 0) .join('&') : null; return res ? `?${res}` : ''; } /** * Decode text using `decodeURIComponent`. Returns the original text if it * fails. * * @param text - string to decode * @returns decoded string */ function decode(text) { try { return decodeURIComponent('' + text); } catch (err) { } return '' + text; } function decodedQuery(query = {}) { const decodedQuery = {}; Object.keys(query).forEach((name) => { try { decodedQuery[name] = decode(query[name]); } catch (e) { decodedQuery[name] = query[name]; } }); return decodedQuery; } const PLUS_RE = /\+/g; // %2B /** * https://github.com/vuejs/vue-router-next/blob/master/src/query.ts * @internal * * @param search - search string to parse * @returns a query object */ function parseQuery(search) { const query = {}; // avoid creating an object with an empty key and empty value // because of split('&') if (search === '' || search === '?') return query; const hasLeadingIM = search[0] === '?'; const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&'); for (let i = 0; i < searchParams.length; ++i) { // pre decode the + into space const searchParam = searchParams[i].replace(PLUS_RE, ' '); // allow the = character let eqPos = searchParam.indexOf('='); let key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos)); let value = eqPos < 0 ? null : decode(searchParam.slice(eqPos + 1)); if (key in query) { // an extra variable for ts types let currentValue = query[key]; if (!isArray(currentValue)) { currentValue = query[key] = [currentValue]; } currentValue.push(value); } else { query[key] = value; } } return query; } function debounce(fn, delay) { let timeout; const newFn = function () { clearTimeout(timeout); const timerFn = () => fn.apply(this, arguments); timeout = setTimeout(timerFn, delay); }; newFn.cancel = function () { clearTimeout(timeout); }; return newFn; } const NAVBAR_HEIGHT = 44; const TABBAR_HEIGHT = 50; const ON_REACH_BOTTOM_DISTANCE = 50; const RESPONSIVE_MIN_WIDTH = 768; const COMPONENT_NAME_PREFIX = 'VUni'; const PRIMARY_COLOR = '#007aff'; const UNI_SSR = '__uniSSR'; const UNI_SSR_STORE = 'store'; const UNI_SSR_DATA = 'data'; const UNI_SSR_GLOBAL_DATA = 'globalData'; function getEnvLocale() { const { env } = process; const lang = env.LC_ALL || env.LC_MESSAGES || env.LANG || env.LANGUAGE; return (lang && lang.replace(/[.:].*/, '')) || 'en'; } export { BUILT_IN_TAGS, COMPONENT_NAME_PREFIX, COMPONENT_PREFIX, COMPONENT_SELECTOR_PREFIX, NAVBAR_HEIGHT, ON_REACH_BOTTOM_DISTANCE, PLUS_RE, PRIMARY_COLOR, RESPONSIVE_MIN_WIDTH, TABBAR_HEIGHT, TAGS, UNI_SSR, UNI_SSR_DATA, UNI_SSR_GLOBAL_DATA, UNI_SSR_STORE, addFont, callOptions, createRpx2Unit, debounce, decode, decodedQuery, defaultRpx2Unit, formatDateTime, getCostomDataset, getEnvLocale, getLen, initCostomDataset, invokeArrayFns, isBuiltInComponent, isCustomElement, isNativeTag, normalizeDataset, normalizeTarget, once, parseQuery, passive, plusReady, removeLeadingSlash, sanitise, scrollTo, stringifyQuery, updateElementStyle };