first commit

This commit is contained in:
2026-09-08 20:28:54 +08:00
commit 2ada8d3d5a
37380 changed files with 4886169 additions and 0 deletions
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
@media(prefers-color-scheme:dark){uni-button,uni-button[type='default']{color:#d6d6d6;background-color:#343434}.button-hover,.button-hover[type='default']{color:#d6d6d6;background-color:rgba(255,255,255,0.1)}uni-button[disabled][type='default'],uni-button[disabled]:not([type]){color:rgba(255,255,255,0.2);background-color:rgba(255,255,255,0.08)}uni-button[type='primary'][plain][disabled]{color:rgba(255,255,255,0.2);border-color:rgba(255,255,255,0.2)}uni-button[type='default'][plain]{color:#d6d6d6;border:1px solid #d6d6d6}.button-hover[type='default'][plain]{color:rgba(150,150,150,0.6);border-color:rgba(150,150,150,0.6);background-color:rgba(50,50,50,0.2)}uni-button[type='default'][plain][disabled]{border-color:hsla(0,0%,100%,0.2);color:hsla(0,0%,100%,0.2)}}@media(prefers-color-scheme:dark){.uni-picker-view-indicator:before{border-top-color:var(--UI-FG-3)}.uni-picker-view-indicator:after{border-bottom-color:var(--UI-FG-3)}.uni-picker-view-mask{background-image:-webkit-linear-gradient(top,rgba(35,35,35,0.95),rgba(35,35,35,0.6)),-webkit-linear-gradient(bottom,rgba(35,35,35,0.95),rgba(35,35,35,0.6));background-image:linear-gradient(180deg,rgba(35,35,35,0.95),rgba(35,35,35,0.6)),linear-gradient(0,rgba(35,35,35,0.95),rgba(35,35,35,0.6))}}@media(prefers-color-scheme:dark){uni-switch .uni-switch-input{border-color:#3b3b3f}uni-switch .uni-switch-input,uni-switch .uni-switch-input:before{background-color:#3b3b3f}uni-switch .uni-switch-input:after{background-color:#fff;box-shadow:0 1px 3px rgba(0,0,0,0.4)}uni-switch .uni-checkbox-input{background-color:#2c2c2c;border:1px solid #656565}}@media(prefers-color-scheme:dark){html{--UI-BG-COLOR-ACTIVE:#373737;--UI-BORDER-COLOR-1:#373737;--UI-BG:#000;--UI-BG-0:#191919;--UI-BG-1:#1f1f1f;--UI-BG-2:#232323;--UI-BG-3:#2f2f2f;--UI-BG-4:#606060;--UI-BG-5:#2c2c2c;--UI-FG:#fff;--UI-FG-0:hsla(0,0%,100%,0.8);--UI-FG-HALF:hsla(0,0%,100%,0.6);--UI-FG-1:hsla(0,0%,100%,0.5);--UI-FG-2:hsla(0,0%,100%,0.3);--UI-FG-3:hsla(0,0%,100%,0.05)}.uni-mask{background:rgba(0,0,0,.6)}}@media(prefers-color-scheme:dark){uni-actionsheet .uni-actionsheet__title{background-color:var(--UI-BG-1);border-bottom-color:var(--UI-BORDER-COLOR-1)}uni-actionsheet .uni-actionsheet{background-color:var(--UI-BG-1)}uni-actionsheet .uni-actionsheet__action,uni-actionsheet .uni-actionsheet__menu{background-color:var(--UI-BG-2)}uni-actionsheet .uni-actionsheet__cell:active{background-color:var(--UI-BG-COLOR-ACTIVE)}uni-actionsheet .uni-actionsheet__cell:before{border-top-color:var(--UI-BORDER-COLOR-1);color:var(--UI-BORDER-COLOR-1)}}@media(prefers-color-scheme:dark){uni-modal .uni-modal{color:var(--UI-FG-0);background-color:var(--UI-BG-2)}uni-modal .uni-modal__bd{color:var(--UI-FG-1)}uni-modal .uni-modal__btn:active{color:#aaa;background-color:var(--UI-BG-COLOR-ACTIVE)}uni-modal .uni-modal__ft:after,uni-modal .uni-modal__btn:after{color:var(--UI-BORDER-COLOR-1);border-color:var(--UI-BORDER-COLOR-1)}}@media(prefers-color-scheme:dark){uni-toast .uni-toast{background-color:#606060;color:var(--UI-FG-0)}uni-toast .uni-icon_toast.uni-icon-error:before,uni-toast .uni-icon_toast.uni-icon-success-no-circle:before{color:rgba(255,255,255,0.9)}}@media(prefers-color-scheme:dark){uni-page-body{background-color:#191919;color:hsla(0,0%,100%,0.8)}}@media(prefers-color-scheme:dark){.uni-picker-container .uni-picker-content{background-color:var(--UI-BG-2)}.uni-picker-container .uni-picker-item,.uni-selector-select .uni-picker-item,.uni-picker-container .uni-picker-action.uni-picker-action-cancel{color:var(--UI-FG-0)}.uni-picker-container .uni-picker-custom{background-color:var(--UI-BG-2)}.uni-picker-container .uni-picker-header:after{border-bottom-color:var(--UI-FG-3)}}
File diff suppressed because one or more lines are too long
+311
View File
@@ -0,0 +1,311 @@
const base = [
'base64ToArrayBuffer',
'arrayBufferToBase64',
'addInterceptor',
'removeInterceptor',
'interceptors'
]
const network = [
'request',
'uploadFile',
'downloadFile',
'connectSocket',
'onSocketOpen',
'onSocketError',
'sendSocketMessage',
'onSocketMessage',
'closeSocket',
'onSocketClose',
'getUpdateManager',
'configMTLS'
]
const route = [
'navigateTo',
'redirectTo',
'reLaunch',
'switchTab',
'navigateBack'
]
const storage = [
'setStorage',
'setStorageSync',
'getStorage',
'getStorageSync',
'getStorageInfo',
'getStorageInfoSync',
'removeStorage',
'removeStorageSync',
'clearStorage',
'clearStorageSync'
]
const location = [
'getLocation',
'chooseLocation',
'openLocation',
'createMapContext',
'onLocationChange',
'onLocationChangeError',
'startLocationUpdate',
'stopLocationUpdate',
'offLocationChange',
'offLocationChangeError'
]
const media = [
'chooseImage',
'chooseFile',
'previewImage',
'closePreviewImage',
'getImageInfo',
'getVideoInfo',
'saveImageToPhotosAlbum',
'compressImage',
'compressVideo',
'getRecorderManager',
'getBackgroundAudioManager',
'createAudioContext',
'createInnerAudioContext',
'chooseVideo',
'saveVideoToPhotosAlbum',
'createVideoContext',
'createCameraContext',
'createLivePlayerContext',
'createLivePusherContext'
]
const device = [
'getSystemInfo',
'getSystemInfoSync',
'getWindowInfo',
'getDeviceInfo',
'getAppBaseInfo',
'canIUse',
'onMemoryWarning',
'getNetworkType',
'onNetworkStatusChange',
'offNetworkStatusChange',
'onAccelerometerChange',
'offAccelerometerChange',
'startAccelerometer',
'stopAccelerometer',
'onCompassChange',
'offCompassChange',
'startCompass',
'stopCompass',
'onGyroscopeChange',
'startGyroscope',
'stopGyroscope',
'makePhoneCall',
'scanCode',
'setClipboardData',
'getClipboardData',
'setScreenBrightness',
'getScreenBrightness',
'setKeepScreenOn',
'onUserCaptureScreen',
'vibrateLong',
'vibrateShort',
'addPhoneContact',
'openBluetoothAdapter',
'startBluetoothDevicesDiscovery',
'onBluetoothDeviceFound',
'stopBluetoothDevicesDiscovery',
'onBluetoothAdapterStateChange',
'getConnectedBluetoothDevices',
'getBluetoothDevices',
'getBluetoothAdapterState',
'closeBluetoothAdapter',
'writeBLECharacteristicValue',
'readBLECharacteristicValue',
'onBLEConnectionStateChange',
'onBLECharacteristicValueChange',
'notifyBLECharacteristicValueChange',
'getBLEDeviceServices',
'getBLEDeviceCharacteristics',
'createBLEConnection',
'closeBLEConnection',
'setBLEMTU',
'getBLEDeviceRSSI',
'onBeaconServiceChange',
'onBeaconUpdate',
'getBeacons',
'startBeaconDiscovery',
'stopBeaconDiscovery',
'checkIsSupportSoterAuthentication',
'checkIsSoterEnrolledInDevice',
'startSoterAuthentication',
'onThemeChange',
'offThemeChange',
'onUIStyleChange',
'getSystemSetting',
'getAppAuthorizeSetting',
'openAppAuthorizeSetting'
]
const keyboard = [
'hideKeyboard',
'onKeyboardHeightChange',
'offKeyboardHeightChange',
'getSelectedTextRange'
]
const ui = [
'showToast',
'hideToast',
'showLoading',
'hideLoading',
'showModal',
'showActionSheet',
'setNavigationBarTitle',
'setNavigationBarColor',
'showNavigationBarLoading',
'hideNavigationBarLoading',
'setTabBarItem',
'setTabBarStyle',
'hideTabBar',
'showTabBar',
'setTabBarBadge',
'removeTabBarBadge',
'showTabBarRedDot',
'hideTabBarRedDot',
'onTabBarMidButtonTap',
'setBackgroundColor',
'setBackgroundTextStyle',
'createAnimation',
'pageScrollTo',
'onWindowResize',
'offWindowResize',
'loadFontFace',
'startPullDownRefresh',
'stopPullDownRefresh',
'createSelectorQuery',
'createIntersectionObserver',
'createMediaQueryObserver',
'getMenuButtonBoundingClientRect',
'showTopWindow',
'showLeftWindow',
'showRightWindow',
'hideTopWindow',
'hideLeftWindow',
'hideRightWindow',
'getTopWindowStyle',
'getLeftWindowStyle',
'getRightWindowStyle',
'setTopWindowStyle',
'setLeftWindowStyle',
'setRightWindowStyle',
'getLocale',
'setLocale',
'onLocaleChange'
]
const event = [
'$emit',
'$on',
'$once',
'$off'
]
const file = [
'saveFile',
'getSavedFileList',
'getSavedFileInfo',
'removeSavedFile',
'getFileInfo',
'openDocument',
'getFileSystemManager'
]
const canvas = [
'createOffscreenCanvas',
'createCanvasContext',
'canvasToTempFilePath',
'canvasPutImageData',
'canvasGetImageData'
]
const third = [
'getProvider',
'login',
'checkSession',
'getUserInfo',
'getUserProfile',
'preLogin',
'closeAuthView',
'getCheckBoxState',
'getUniverifyManager',
'share',
'shareWithSystem',
'showShareMenu',
'hideShareMenu',
'requestPayment',
'subscribePush',
'unsubscribePush',
'onPush',
'offPush',
'requireNativePlugin',
'upx2px',
'restoreGlobal',
'requireGlobal',
'getSubNVueById',
'getCurrentSubNVue',
'setPageMeta',
'onHostEventReceive',
'onNativeEventReceive',
'sendNativeEvent',
'preloadPage',
'unPreloadPage',
'loadSubPackage',
'sendHostEvent',
'navigateToMiniProgram',
'getLaunchOptionsSync',
'getEnterOptionsSync',
'initUTSProxyClass',
'initUTSProxyFunction',
'initUTSIndexClassName',
'initUTSClassName',
'initUTSPackageName',
'requireUTSPlugin',
'registerUTSPlugin',
'registerUTSInterface'
]
const ad = [
'createRewardedVideoAd',
'createFullScreenVideoAd',
'createInterstitialAd',
'createInteractiveAd'
]
const plugin = [
'invokePushCallback',
'getPushClientId',
'onPushMessage',
'offPushMessage',
'createPushMessage',
'getChannelManager'
]
const apis = [
...base,
...network,
...route,
...storage,
...location,
...media,
...device,
...keyboard,
...ui,
...event,
...file,
...canvas,
...third,
...ad,
...plugin
]
module.exports = apis
+18
View File
@@ -0,0 +1,18 @@
export {
upx2px
}
from 'uni-core/service/api/base/upx2px'
export * from 'uni-platform/view/api'
export {
getSystemInfoSync
}
from '../../src/platforms/h5/service/api/device/get-system-info'
export function canIUse (schema) {
if (schema === 'css.var') {
return window.CSS && window.CSS.supports && window.CSS.supports('--a:0')
}
return true
}
+32
View File
@@ -0,0 +1,32 @@
import Vue from 'vue'
import 'uni-platform/view/index.css'
import {
definePage
} from 'uni-platform/page-factory'
import {
getCurrentPages
} from 'uni-platform/view/framework/page'
import ViewPlugin from 'uni-platform/view/framework/plugins/index'
global.UniViewJSBridge = {
subscribe: UniViewJSBridge.subscribe,
publishHandler: UniViewJSBridge.publishHandler,
subscribeHandler: UniViewJSBridge.subscribeHandler
}
global.getCurrentPages = getCurrentPages
global.__definePage = definePage
global.Vue = Vue
Vue.use(ViewPlugin)
require('uni-components')
export * from './view-api.js'
+144
View File
@@ -0,0 +1,144 @@
const path = require('path')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
function resolve(...args) {
return normalizePath(path.resolve.apply(path, [__dirname, ...args]))
}
const srcPath = resolve('../../src/')
const protocolPath = resolve('../../src/core/helpers/protocol')
const coreApiPath = resolve('../../src/core/service/api')
const platformApiPath = resolve('../../src/platforms/' + process.env.UNI_PLATFORM + '/service/api')
const apis = require('../apis')
process.UNI_SERVICE_API_MANIFEST = Object.create(null)
process.UNI_SERVICE_API_PROTOCOL = Object.create(null)
function parseProtocolExport({
file,
exports
}) {
const filepath = file.replace(srcPath, '')
exports.forEach(exportName => {
if (process.UNI_SERVICE_API_PROTOCOL[exportName]) {
console.warn(`API[${exportName}] 冲突:`)
console.warn(process.UNI_SERVICE_API_PROTOCOL[exportName])
console.warn(filepath)
} else {
process.UNI_SERVICE_API_PROTOCOL[exportName] = filepath
}
})
}
function parseApiExport({
file,
methods,
exports,
isPlatform
}) {
const deps = []
methods && methods.forEach(method => {
deps.push(['', method])
})
const filepath = file.replace(srcPath, '')
exports.forEach(exportName => {
if (process.UNI_SERVICE_API_MANIFEST[exportName]) {
console.warn('\n')
console.warn(`API[${exportName}] 冲突:`)
console.warn(process.UNI_SERVICE_API_MANIFEST[exportName][0])
console.warn(filepath)
if (isPlatform) { // 优先使用 platform
process.UNI_SERVICE_API_MANIFEST[exportName] = [filepath, deps]
console.warn(`优先使用` + filepath)
}
} else {
process.UNI_SERVICE_API_MANIFEST[exportName] = [filepath, deps]
}
})
}
const CONTEXTS = ['VideoContext', 'MapContext', 'EditorContext', 'CanvasContext']
function parseExports(node, t, file) {
if (t.isFunctionDeclaration(node)) {
return [node.id.name]
} else if (
t.isVariableDeclaration(node) &&
node.declarations.length === 1
) {
return [node.declarations[0].id.name]
} else if (Array.isArray(node) && node.length) {
return node.map(specifier => {
return specifier.exported.name
})
} else {
if (t.isClassDeclaration(node) && CONTEXTS.includes(node.id.name)) {
// ignore
return
}
console.warn('\n')
console.warn(`${file} 解析 export 失败`, node)
}
}
module.exports = function({
types: t
}) {
return {
visitor: {
Program: {
enter(path, state) {
state.file.opts.file = normalizePath(state.file.opts.filename)
state.file.opts.isCore = state.file.opts.file.indexOf(coreApiPath) === 0
state.file.opts.isPlatform = state.file.opts.file.indexOf(platformApiPath) === 0
state.file.opts.isProtocol = state.file.opts.file.indexOf(protocolPath) === 0
},
exit(path, state) {
const {
exports,
isProtocol
} = state.file.opts
if (exports && exports.length) {
if (isProtocol) {
parseProtocolExport(state.file.opts)
} else {
parseApiExport(state.file.opts)
}
}
}
},
ExportNamedDeclaration(path, state) {
const {
file,
isCore,
isPlatform,
isProtocol
} = state.file.opts
if (isCore || isPlatform || isProtocol) {
const exports = parseExports(path.node.declaration || path.node.specifiers, t, file)
if (Array.isArray(exports)) {
(state.file.opts.exports || (state.file.opts.exports = [])).push(...exports)
}
}
},
CallExpression(path, state) {
const {
file,
isCore,
isPlatform
} = state.file.opts
if (
isCore &&
path.node.callee.name === 'invokeMethod'
) {
(state.file.opts.methods || (state.file.opts.methods = new Set())).add(path.node.arguments[0].value)
}
}
}
}
}
+40
View File
@@ -0,0 +1,40 @@
const fs = require('fs')
const path = require('path')
const glob = require('glob')
const loaderUtils = require('loader-utils')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
module.exports = function loader(source) {
const options = loaderUtils.getOptions(this)
const baseDir = options['base']
const extendsDir = options['extends']
const exportCode = []
const extendsFiles = []
// extends目录均导出
glob.sync('**/*.js', {
cwd: extendsDir
}).forEach(file => {
if (file === 'index.js') {
return
}
extendsFiles.push(file)
exportCode.push(`export * from 'uni-sub-platform-api/${normalizePath(file)}'`)
})
//base目录中有,extends无的导出
glob.sync('**/*.js', {
cwd: baseDir
}).forEach(file => {
if (file === 'index.js') {
return
}
if (!extendsFiles.includes(file)) {
exportCode.push(`export * from 'uni-platform-api/${normalizePath(file)}'`)
}
})
// console.log(exportCode.join('\n'))
return exportCode.join('\n')
}
+58
View File
@@ -0,0 +1,58 @@
const fs = require('fs')
const path = require('path')
const glob = require('glob')
const loaderUtils = require('loader-utils')
const isWin = /^win/.test(process.platform)
const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path)
module.exports = function loader(source) {
const options = loaderUtils.getOptions(this)
const baseDir = options['base']
const platformDir = options['platform']
const extendsDir = options['extends']
const components = []
const extendsFiles = []
// extends目录均导出
glob.sync('**/index.vue', {
cwd: extendsDir
}).forEach(file => {
extendsFiles.push(file)
components.push(normalizePath(path.join(extendsDir, file)))
})
//base目录中有,extends无的导出
glob.sync('**/index.vue', {
cwd: baseDir
}).forEach(file => {
if (!extendsFiles.includes(file)) {
components.push(normalizePath(path.join(baseDir, file)))
}
})
//platform目录中有,extends无的导出
glob.sync('**/index.vue', {
cwd: platformDir
}).forEach(file => {
if (!extendsFiles.includes(file)) {
components.push(normalizePath(path.join(platformDir, file)))
}
})
const componentsCode = components.map(component => {
return `require('${component}').default`
}).join(',')
return `
import Vue from 'vue'
import baseMixin from 'uni-mixins/base'
import animation from 'uni-mixins/animation'
[${componentsCode}].forEach(component=>{
component.mixins = component.mixins ? [].concat(baseMixin, component.mixins) : [baseMixin]
component.mixins.push(animation)
component.name = 'VUni' + component.name
component.isReserved = true
Vue.component(component.name, component)
})
`
}
+3
View File
@@ -0,0 +1,3 @@
import 'uni-sub-platform/service/index'
import * as api from 'uni-platform/service/api/index'
export default api
+66
View File
@@ -0,0 +1,66 @@
/**
* 1.导出全局对象(UniViewJSBridge,UniServiceJSBridge,uni,getApp,getCurrentPages)
* 2.引入 Vue 插件(uniVueServicePlugin,uniVueServicePlugin)
* 3.引入 Vue 组件
*/
import Vue from 'vue'
// import 'uni-platform/view/index.css'
import initVue from 'uni-core/vue'
class UniApp {
constructor () {
this._init()
}
_init () {
global.UniViewJSBridge = {
subscribe: UniViewJSBridge.subscribe,
publishHandler: UniViewJSBridge.publishHandler,
subscribeHandler: UniViewJSBridge.subscribeHandler
}
global.UniServiceJSBridge = {
subscribe: UniServiceJSBridge.subscribe,
publishHandler: UniServiceJSBridge.publishHandler,
subscribeHandler: UniServiceJSBridge.subscribeHandler
}
const {
default: uni,
getApp,
getCurrentPages
} = require('uni-platform/service/index')
// 与微信JS-SDK同名的方法
// const sameNameApis = ['setClipboardData', 'getClipboardData', 'onUserCaptureScreen', 'openBluetoothAdapter', 'startBluetoothDevicesDiscovery', 'onBluetoothDeviceFound', 'stopBluetoothDevicesDiscovery', 'onBluetoothAdapterStateChange', 'getConnectedBluetoothDevices', 'getBluetoothDevices', 'getBluetoothAdapterState', 'closeBluetoothAdapter', 'writeBLECharacteristicValue', 'readBLECharacteristicValue', 'onBLEConnectionStateChange', 'onBLECharacteristicValueChange', 'notifyBLECharacteristicValueChange', 'getBLEDeviceServices', 'getBLEDeviceCharacteristics', 'createBLEConnection', 'closeBLEConnection', 'onBeaconServiceChange', 'onBeaconUpdate', 'getBeacons', 'startBeaconDiscovery', 'stopBeaconDiscovery', 'chooseImage', 'previewImage', 'getNetworkType', 'onNetworkStatusChange', 'openLocation', 'getLocation']
// 默认会被iOS企业微信替换的方法
const sameNameApis = ['chooseImage']
sameNameApis.forEach(item => {
Object.defineProperty(uni, item, {
writable: false,
configurable: false
})
})
global.uni = uni
global.wx = global.uni
global.getApp = getApp
global.getCurrentPages = getCurrentPages
Vue.use(require('uni-service/plugins').default, {
routes: __uniRoutes
})
Vue.use(require('uni-view/plugins').default, {
routes: __uniRoutes
})
initVue(Vue)
require('uni-platform/components')
require('uni-components')
}
}
global.UniApp = UniApp
global.__uniConfig && new UniApp()
+27
View File
@@ -0,0 +1,27 @@
import {
canIUse
} from 'uni-core/service/api/base/can-i-use'
import {
upx2px
} from 'uni-core/service/api/base/upx2px'
import {
getLocation
} from 'uni-platform/service/api/location/get-location'
import {
onCompassChange,
stopCompass
} from 'uni-platform/service/api/device/compass'
import {
getSystemInfoSync
} from 'uni-platform/service/api/device/get-system-info'
// TODO route
export default {
canIUse,
upx2px,
getLocation,
onCompassChange,
stopCompass,
getSystemInfoSync
}
+54
View File
@@ -0,0 +1,54 @@
import Vue from 'vue'
// 使用白名单过滤(前期有一批自定义组件使用了 uni-)
import tags from 'uni-helpers/tags'
import 'uni-core/view/index.css'
import uni from './ui-api.js'
import {
processEvent
} from 'uni-core/view/plugins/events'
const oldIsReservedTag = Vue.config.isReservedTag
global.uni = uni
Vue.config.isReservedTag = function (tag) {
return tags.indexOf(tag) !== -1 || oldIsReservedTag(tag)
}
Vue.config.ignoredElements = tags
const oldGetTagNamespace = Vue.config.getTagNamespace
const conflictTags = ['switch', 'image', 'text', 'view']
Vue.config.getTagNamespace = function (tag) {
if (~conflictTags.indexOf(tag)) { // svg 部分标签名称与 uni 标签冲突
return false
}
return oldGetTagNamespace(tag) || false
}
const findUniTarget = function ($event, $el) {
let target = $event.target
for (; target && target !== $el; target = target.parentNode) {
if (target.tagName && target.tagName.indexOf('UNI-') === 0) {
break
}
}
return target
}
Vue.prototype.$handleEvent = function ($event) {
if ($event instanceof Event) { // 未处理的 event 对象 需要对 target 校正及包装
// 查找 uniTarget
const target = findUniTarget($event, this.$el)
$event = processEvent.call(this, $event.type, $event, {}, target || $event.target, $event.currentTarget)
}
return $event
}
require('uni-components')
+1
View File
@@ -0,0 +1 @@
"use strict";var e=require("debug"),t=require("postcss-selector-parser"),o=require("fs");function a(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=a(e),n=a(t),s=a(o);const i=r.default("automator:devtool");function c(e){e.walk((e=>{if("tag"===e.type){const t=e.value;e.value="page"===t?"uni-page-body":"uni-"+t}}))}const l=["Page.getElement","Page.getElements","Element.getElement","Element.getElements"];function p(e){try{return require(e)}catch(t){return require(require.resolve(e,{paths:[process.cwd()]}))}}/^win/.test(process.platform);const u=["chromium","firefox","webkit"];let w=!1;try{w=!!p("playwright")}catch(e){}const d=new Map;function f(e="chromium"){const t=e&&u.includes(e)?e:u[0];let o=d.get(t);return o||(o=function(e){if("webkit"===e)return h("webkit");if("firefox"===e)return h("firefox");if(w)return h("chromium");throw new Error("Playwright dependency not found, please install playwright!")}(t),d.set(t,o)),o}function h(e){const t=p("playwright");let o,a;return{type:e,provider:"playwright",async open(r,n,s){o=await t[e].launch(n.options),"firefox"===e&&(n.contextOptions.isMobile=!1),i(`browser.newContext ${JSON.stringify(n.contextOptions)}`);const c=await o.newContext(n.contextOptions);a=await c.newPage(),a.on("console",(e=>{s.emit("App.logAdded",{type:e.type(),args:[e.text()]})})),a.on("pageerror",(e=>{s.emit("App.exceptionThrown",e)})),await a.goto(n.url||r),await a.waitForTimeout(1e3)},close:()=>o.close(),screenshot(e=!1){let t={fullPage:e};return"true"===process.env.UNI_AUTOMATOR_WEB_SCREENSHOT_NO_NAVIGATION_BAR&&(t={fullPage:e,clip:{x:0,y:44,width:Number.MAX_VALUE,height:Number.MAX_VALUE}}),a.screenshot(t).then((e=>e.toString("base64")))},swipe:e=>new Promise((async t=>{const{startPoint:o,endPoint:r}=e;await a.evaluate((([e,t])=>{window.scrollBy({left:e.x-t.x,top:e.y-t.y,behavior:"smooth"})}),[o,r]),t("swipe success")})),tap:e=>new Promise((async t=>{const{x:o,y:r,duration:n}=e;await a.mouse.move(o,r),await a.mouse.down(),await a.waitForTimeout(n||0),await a.mouse.up(),t("tap success")})),keyboardInput:e=>new Promise((async t=>{await a.keyboard.type(e.text),t("keyboardInput success")}))}}let y;const m={"Tool.close":{reflect:async()=>{await y.close()}},"App.start":{reflect:async()=>{}},"App.exit":{reflect:async()=>{}},"App.enableLog":{reflect:()=>Promise.resolve()},"App.captureScreenshot":{reflect:async(e,t)=>{const o=await y.screenshot(!!t.fullPage);return i(`App.captureScreenshot ${o.length}`),{data:o}}},"App.swipe":{reflect:async(e,t)=>{const o=await y.swipe(t);return i(`App.swipe ${o.length}`),{data:o}}},"App.tap":{reflect:async(e,t)=>{const o=await y.tap(t);return i(`App.tap ${o.length}`),{data:o}}},"App.keyboardInput":{reflect:async(e,t)=>{const o=await y.keyboardInput(t);return i(`App.keyboardInput ${o.length}`),{data:o}}}};!function(e){l.forEach((t=>{e[t]=function(e){return{reflect:async(t,o)=>t(e,o,!1),params:e=>(e.selector&&(e.selector=n.default(c).processSync(e.selector)),e)}}(t)}))}(m);const g={devtools:{name:"browser",paths:[],validate:async function(e){var t;return e.options=e.options||{},e.executablePath&&!e.options.executablePath&&(e.options.executablePath=e.executablePath),e.contextOptions={viewport:Object.assign({width:375,height:667},e.options.defaultViewport||{}),hasTouch:!0,isMobile:!0,deviceScaleFactor:(null===(t=e.options.defaultViewport)||void 0===t?void 0:t.deviceScaleFactor)||2},e.options.defaultViewport=Object.assign({width:375,height:667,deviceScaleFactor:2,hasTouch:!0,isMobile:!0},e.options.defaultViewport||{}),e.teardown||(e.teardown=!1===e.options.headless?"disconnect":"close"),e},create:async function(e,t,o){t.executablePath?await new Promise(((o,a)=>{const{exec:r}=require("node:child_process");if(/^win/.test(process.platform)){const a="C:\\Users\\Public\\AppData\\Local\\chrome";s.default.existsSync(a)||s.default.mkdirSync(a,{recursive:!0}),r(`start ${t.executablePath} --user-data-dir=${a} ${e}`,(e=>{if(e)throw console.error(`open ${t.executablePath} fail, ${e}`),Error(e)})),setTimeout((()=>{o(null)}),1e3)}else r(`open -a "${t.executablePath}" ${e}`,(e=>{e&&(console.error(`open ${t.executablePath} fail, ${e}`),a(e)),o(null)}))})):(y=f(process.env.BROWSER),i("createDevtools "+(y.provider+" "+y.type+" "+JSON.stringify(t))),await y.open(e,t,o))}},shouldCompile:(e,t)=>!t.url,adapter:m};module.exports=g;
+65
View File
@@ -0,0 +1,65 @@
const fs = require('fs')
const path = require('path')
function getTemplatePath (template) {
if (template) {
const userTemplate = path.resolve(process.env.UNI_INPUT_DIR, template)
if (fs.existsSync(userTemplate)) { return userTemplate }
}
return path.resolve(process.env.UNI_CLI_CONTEXT, 'public/index.html')
}
function transform (content, platformOptions) {
if (platformOptions.darkmode === true) {
// darkmode
try {
content += fs.readFileSync(require.resolve('@dcloudio/uni-h5/dist/index.dark.css'))
} catch (error) { }
}
if (process.env.NODE_ENV === 'production') {
return content + // shadow
'body::after{position:fixed;content:\'\';left:-1000px;top:-1000px;-webkit-animation:shadow-preload .1s;-webkit-animation-delay:3s;animation:shadow-preload .1s;animation-delay:3s}@-webkit-keyframes shadow-preload{0%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}100%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}}@keyframes shadow-preload{0%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}100%{background-image:url(https://cdn.dcloud.net.cn/img/shadow-grey.png)}}'
}
return content
}
function getIndexCssPath (assetsDir, template, hashKey) {
const CopyWebpackPluginVersion = Number(require('copy-webpack-plugin/package.json').version.split('.')[0])
const VUE_APP_INDEX_CSS_HASH = process.env[hashKey]
if (VUE_APP_INDEX_CSS_HASH) {
try {
const templateContent = fs.readFileSync(getTemplatePath(template))
if (new RegExp('\\b' + hashKey + '\\b').test(templateContent)) {
return path.join(assetsDir, `[name].${VUE_APP_INDEX_CSS_HASH}${CopyWebpackPluginVersion > 7 ? '' : '.'}[ext]`)
}
} catch (e) { }
}
return assetsDir
}
module.exports = {
options: {
cssVars: {
'--status-bar-height': '0px'
},
filterTag: 'wxs',
vue: '@dcloudio/vue-cli-plugin-uni/packages/h5-vue'
},
copyWebpackOptions (platformOptions, vueOptions) {
const copyOptions = [
{
from: require.resolve('@dcloudio/uni-h5/dist/index.css'),
to: getIndexCssPath(vueOptions.assetsDir, platformOptions.template, 'VUE_APP_INDEX_CSS_HASH'),
transform (content) {
return transform(content, platformOptions)
}
},
'hybrid/html'
]
global.uniModules.forEach(module => {
copyOptions.push('uni_modules/' + module + '/hybrid/html')
})
return copyOptions
}
}
+237
View File
@@ -0,0 +1,237 @@
[{
"name": "base",
"title": "基础",
"apiList": {
"uni.getSystemInfo": true,
"uni.getSystemInfoSync": true,
"uni.canIUse": true,
"uni.upx2px": true,
"uni.navigateTo": true,
"uni.redirectTo": true,
"uni.switchTab": true,
"uni.reLaunch": true,
"uni.navigateBack": true
}
}, {
"name": "network",
"title": "网络",
"apiList": {
"uni.request": true,
"uni.connectSocket": true,
"uni.sendSocketMessage": true,
"uni.closeSocket": true,
"uni.onSocketOpen": true,
"uni.onSocketError": true,
"uni.onSocketMessage": true,
"uni.onSocketClose": true,
"uni.downloadFile": true,
"uni.uploadFile": true
}
}, {
"name": "storage",
"title": "数据缓存",
"apiList": {
"uni.setStorage": true,
"uni.setStorageSync": true,
"uni.getStorage": true,
"uni.getStorageSync": true,
"uni.removeStorage": true,
"uni.removeStorageSync": true,
"uni.clearStorage": true,
"uni.clearStorageSync": true,
"uni.getStorageInfo": true,
"uni.getStorageInfoSync": true
}
}, {
"name": "location",
"title": "位置",
"apiList": {
"uni.getLocation": true,
"uni.openLocation": true,
"uni.chooseLocation": true,
"uni.onLocationChange": true,
"uni.onLocationChangeError": true,
"uni.startLocationUpdate": true,
"uni.stopLocationUpdate": true,
"uni.offLocationChange": true,
"uni.offLocationChangeError": true
}
}, {
"name": "media",
"title": "媒体",
"apiList": {
"uni.chooseImage": true,
"uni.chooseFile": true,
"uni.previewImage": true,
"uni.getImageInfo": true,
"uni.getVideoInfo": true,
"uni.saveImageToPhotosAlbum": true,
"uni.compressImage": true,
"uni.compressVideo": true,
"uni.getRecorderManager": true,
"uni.getBackgroundAudioManager": true,
"uni.createInnerAudioContext": true,
"uni.chooseVideo": true,
"uni.saveVideoToPhotosAlbum": true,
"uni.createVideoContext": true,
"uni.createCameraContext": true,
"uni.createLivePlayerContext": true,
"uni.createLivePusherContext": true
}
}, {
"name": "device",
"title": "设备",
"apiList": {
"uni.onMemoryWarning": true,
"uni.getNetworkType": true,
"uni.onNetworkStatusChange": true,
"uni.offNetworkStatusChange": true,
"uni.onAccelerometerChange": true,
"uni.startAccelerometer": true,
"uni.stopAccelerometer": true,
"uni.onCompassChange": true,
"uni.offCompassChange": true,
"uni.startCompass": true,
"uni.stopCompass": true,
"uni.onGyroscopeChange": true,
"uni.startGyroscope": true,
"uni.stopGyroscope": true,
"uni.makePhoneCall": true,
"uni.scanCode": true,
"uni.setClipboardData": true,
"uni.getClipboardData": true,
"uni.setScreenBrightness": true,
"uni.getScreenBrightness": true,
"uni.setKeepScreenOn": true,
"uni.onUserCaptureScreen": true,
"uni.vibrateLong": true,
"uni.vibrateShort": true,
"uni.addPhoneContact": true,
"uni.openBluetoothAdapter": true,
"uni.startBluetoothDevicesDiscovery": true,
"uni.onBluetoothDeviceFound": true,
"uni.stopBluetoothDevicesDiscovery": true,
"uni.onBluetoothAdapterStateChange": true,
"uni.getConnectedBluetoothDevices": true,
"uni.getBluetoothDevices": true,
"uni.getBluetoothAdapterState": true,
"uni.closeBluetoothAdapter": true,
"uni.writeBLECharacteristicValue": true,
"uni.readBLECharacteristicValue": true,
"uni.onBLEConnectionStateChange": true,
"uni.onBLECharacteristicValueChange": true,
"uni.notifyBLECharacteristicValueChange": true,
"uni.getBLEDeviceServices": true,
"uni.getBLEDeviceCharacteristics": true,
"uni.createBLEConnection": true,
"uni.closeBLEConnection": true,
"uni.setBLEMTU": true,
"uni.getBLEDeviceRSSI": true,
"uni.onBeaconServiceChange": true,
"uni.onBeaconUpdate": true,
"uni.getBeacons": true,
"uni.startBeaconDiscovery": true,
"uni.stopBeaconDiscovery": true,
"uni.onThemeChange": true,
"uni.onUIStyleChange": true
}
}, {
"name": "ui",
"title": "界面",
"apiList": {
"uni.showToast": true,
"uni.hideToast": true,
"uni.showLoading": true,
"uni.hideLoading": true,
"uni.showModal": true,
"uni.showActionSheet": true,
"uni.setNavigationBarTitle": true,
"uni.setNavigationBarColor": true,
"uni.showNavigationBarLoading": true,
"uni.hideNavigationBarLoading": true,
"uni.setTabBarItem": true,
"uni.setTabBarStyle": true,
"uni.hideTabBar": true,
"uni.showTabBar": true,
"uni.setTabBarBadge": true,
"uni.removeTabBarBadge": true,
"uni.showTabBarRedDot": true,
"uni.hideTabBarRedDot": true,
"uni.setBackgroundColor": true,
"uni.setBackgroundTextStyle": true,
"uni.createAnimation": true,
"uni.pageScrollTo": true,
"uni.onWindowResize": true,
"uni.offWindowResize": true,
"uni.loadFontFace": true,
"uni.startPullDownRefresh": true,
"uni.stopPullDownRefresh": true,
"uni.createSelectorQuery": true,
"uni.createIntersectionObserver": true,
"uni.createMediaQueryObserver": true,
"uni.hideKeyboard": true,
"uni.onKeyboardHeightChange": true,
"uni.offKeyboardHeightChange": true
}
}, {
"name": "event",
"title": "页面通讯",
"apiList": {
"uni.$emit": true,
"uni.$on": true,
"uni.$once": true,
"uni.$off": true
}
}, {
"name": "file",
"title": "文件",
"apiList": {
"uni.saveFile": true,
"uni.getSavedFileList": true,
"uni.getSavedFileInfo": true,
"uni.removeSavedFile": true,
"uni.getFileInfo": true,
"uni.openDocument": true,
"uni.getFileSystemManager": true
}
}, {
"name": "canvas",
"title": "绘画",
"apiList": {
"uni.createOffscreenCanvas": true,
"uni.createCanvasContext": true,
"uni.canvasToTempFilePath": true,
"uni.canvasPutImageData": true,
"uni.canvasGetImageData": true
}
}, {
"name": "third",
"title": "第三方服务",
"apiList": {
"uni.getProvider": true,
"uni.login": true,
"uni.checkSession": true,
"uni.getUserInfo": true,
"uni.getUserProfile": true,
"uni.share": true,
"uni.showShareMenu": true,
"uni.hideShareMenu": true,
"uni.requestPayment": true,
"uni.subscribePush": true,
"uni.unsubscribePush": true,
"uni.onPush": true,
"uni.offPush": true,
"uni.requireNativePlugin": true,
"uni.base64ToArrayBuffer": true,
"uni.arrayBufferToBase64": true
}
}, {
"name": "ad",
"title": "广告",
"apiList": {
"uni.createRewardedVideoAd": true,
"uni.createFullScreenVideoAd": true,
"uni.'createInterstitialAd'": true,
"uni.'createInteractiveAd'": true
}
}]
@@ -0,0 +1,20 @@
# rollup-plugin-require-context
rollup plugin for resovling webpack require-context.
## usage
```javascript
import requireContext from 'rollup-plugin-require-context';
export default {
input: 'main.js',
output: {
file: 'bundle.js',
format: 'iife'
},
plugins: [
requireContext()
]
};
```
@@ -0,0 +1,38 @@
{
"name": "rollup-plugin-require-context",
"version": "1.0.0",
"description": "rollup-plugin for webpack requrie-context",
"main": "src/index.js",
"scripts": {
"brk": "node --inspect-brk example/run.js",
"example": "rollup -c example/rollup.config.js",
"test:dev": "jest --watchAll"
},
"repository": {
"type": "git",
"url": "git+https://github.com/elcarim5efil/rollup-plugin-require-context.git"
},
"keywords": [
"rollup",
"plugin",
"require-context",
"webpack-context"
],
"author": "elcarim5efil",
"license": "MIT",
"bugs": {
"url": "https://github.com/elcarim5efil/rollup-plugin-require-context/issues"
},
"homepage": "https://github.com/elcarim5efil/rollup-plugin-require-context#readme",
"dependencies": {
"acorn": "^6.1.1",
"acorn-dynamic-import": "^4.0.0",
"acorn-walk": "^6.1.1",
"rollup-pluginutils": "^2.5.0"
},
"devDependencies": {
"jest": "^24.5.0",
"rollup": "^1.7.4",
"rollup-plugin-virtual": "^1.0.1"
}
}
@@ -0,0 +1,66 @@
const Path = require('path')
const { parse } = require('acorn')
const walk = require('acorn-walk')
function stripHeadAndTailChar (str) {
return str.substring(1, str.length - 1)
}
function extract (code) {
return new Promise((resolve, reject) => {
const ast = parse(code, {
sourceType: 'module'
})
const res = []
walk.simple(ast, {
CallExpression (node) {
const {
start,
end,
callee,
arguments: argNodes
} = node
let args = []
if (
callee.type === 'MemberExpression' &&
callee.object.name === 'require' &&
callee.property.name === 'context'
) {
args = argNodes.map(a => a.value)
res.push({
start,
end,
args
})
}
}
})
resolve(res)
})
}
module.exports = async function extractArgs (code, baseDirname) {
const data = await extract(code)
return data.map(r => {
const { start, end, args } = r
const [
rawDirname = '',
rawRecursive,
rawRegexp
] = args
const dirname = Path.join(baseDirname, rawDirname)
const recursive = rawRecursive
const regexp = rawRegexp
return {
dirname,
recursive,
regexp,
start,
end
}
})
}
@@ -0,0 +1,36 @@
const Path = require('path')
const extractArgs = require('./extract-args')
const resolveRequireModules = require('./resolve-reqquire-modules')
const resolveRequireCode = require('./resolve-require-code')
module.exports = async function gernerateRequireContextCode (id, code) {
const currentCodeDirname = Path.dirname(id)
const data = await extractArgs(code, currentCodeDirname)
let head = ''
const body = data.reduceRight((res, r) => {
const {
start, end,
dirname, recursive, regexp
} = r
const modules = resolveRequireModules(dirname, recursive, regexp)
const moduleCode = resolveRequireCode(dirname, modules)
const {
importCode,
requireFnCode
} = moduleCode
head += importCode
res = [
res.slice(0, start),
requireFnCode,
res.slice(end)
].join('')
return res
}, code)
return [
head,
body
].join('\n')
}
@@ -0,0 +1,3 @@
module.exports = function hasRequireContext (code) {
return /require\.context/g.test(code)
}
@@ -0,0 +1,36 @@
const fs = require('fs')
const Path = require('path')
function readDirRecursive (dir) {
return fs.statSync(dir).isDirectory()
? Array.prototype.concat(
...fs.readdirSync(dir).map(f => readDirRecursive(Path.join(dir, f)))
)
: dir
}
function readDir (dir, recursive) {
const isDirectory = fs.statSync(dir).isDirectory()
if (recursive) {
return readDirRecursive(dir)
} else if (isDirectory) {
const files = fs.readdirSync(dir)
if (files) {
return files.map(file => Path.resolve(dir, file))
}
} else {
return [ dir ]
}
}
module.exports = function resolveRequireModules (baseDirname = './', recursive = false, regexp = /^\.\//) {
let files = readDir(baseDirname, recursive)
if (!Array.isArray(files)) {
files = [files]
}
files = files.map(file => {
const fileAbsolutePath = `./${Path.relative(baseDirname, file)}`
return fileAbsolutePath
})
return files.filter(file => regexp.test(file.replace(/\\/g, '/')))
}
@@ -0,0 +1,48 @@
const Path = require('path')
let uid = 0
function getUID () {
return uid++
}
function genImportCode (name, path) {
return `import * as ${name} from '${path}';\n`
}
function genPropsCode (key, value) {
return `'${key}': ${value},\n`
}
module.exports = function genRequireCode (baseDirname, modules) {
const uid = getUID()
let importCode = ''
let moduleProps = ''
modules.forEach((file, index) => {
const moduleName = `require_context_module_${uid}_${index}`
const moduleAbsolutePath = Path.resolve(baseDirname, file).replace(/\\/g, '/')
importCode += genImportCode(moduleName, moduleAbsolutePath)
moduleProps += genPropsCode(file.replace(/\\/g, '/'), moduleName)
})
const requireFnCode = (`
(function() {
var map = {
${moduleProps}
};
var req = function req(key) {
return map[key] || (function() { throw new Error("Cannot find module '" + key + "'.") }());
}
req.keys = function() {
return Object.keys(map);
}
return req;
})()
`)
return {
importCode,
requireFnCode
}
}
@@ -0,0 +1,17 @@
const _ = require('rollup-pluginutils')
const hasRequireContext = require('./helper/has-require-context')
const gernerateRequireContextCode = require('./helper/generate-require-context-code')
module.exports = function plugin (options = {}) {
const filter = _.createFilter(options.include || ['**/*.js'], options.exclude || 'node_modules/**')
return {
name: 'require_content',
async transform (code, id) {
if (!filter(id) || !hasRequireContext(code)) {
return
}
code = await gernerateRequireContextCode(id, code)
return code
}
}
}
+1
View File
@@ -0,0 +1 @@
[https://dcloud.io/license/uni-app.html](https://dcloud.io/license/uni-app.html)
+1070
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -0,0 +1,29 @@
{
"name": "@dcloudio/uni-h5",
"version": "2.0.2-4070620250821001",
"description": "uni-app h5",
"main": "dist/index.umd.min.js",
"repository": {
"type": "git",
"url": "git+https://github.com/dcloudio/uni-app.git",
"directory": "packages/uni-h5"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "fxy060608",
"license": "Apache-2.0",
"dependencies": {
"base64-arraybuffer": "^0.2.0",
"intersection-observer": "^0.7.0",
"pako": "^1.0.11",
"postcss-urlrewrite": "^0.3.0",
"safe-area-insets": "^1.4.1"
},
"uni-app": {
"name": "h5",
"title": "H5",
"main": "lib/h5/uni.config.js"
},
"gitHead": "83322ec9f7cc592b2052ff78370e12f4689f5966"
}
+5
View File
@@ -0,0 +1,5 @@
const path = require('path')
module.exports = {
src: path.join(__dirname, 'src'),
lib: path.join(__dirname, 'lib')
}
+1
View File
@@ -0,0 +1 @@
<svg width="21" height="37" viewBox="0 0 21 37" xmlns="http://www.w3.org/2000/svg"><title>Rectangle 1</title><path d="M17 36L0 19a2.91 2.91 0 0 1 0-1L17 1c.131-.057.5-.06 1 0l2 2c.057.522.06.899 0 1L6 18a.898.898 0 0 0 0 1l14 14c.056.098.062.474 0 1l-2 2c-.494.057-.868.06-1 0z" fill="#FFF" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 318 B

+67
View File
@@ -0,0 +1,67 @@
export default class EventChannel {
constructor (id, events) {
this.id = id
this.listener = {}
this.emitCache = {}
if (events) {
Object.keys(events).forEach(name => {
this.on(name, events[name])
})
}
}
emit (eventName, ...args) {
const fns = this.listener[eventName]
if (!fns) {
return (this.emitCache[eventName] || (this.emitCache[eventName] = [])).push(args)
}
fns.forEach(opt => {
opt.fn.apply(opt.fn, args)
})
this.listener[eventName] = fns.filter(opt => opt.type !== 'once')
}
on (eventName, fn) {
this._addListener(eventName, 'on', fn)
this._clearCache(eventName)
}
once (eventName, fn) {
this._addListener(eventName, 'once', fn)
this._clearCache(eventName)
}
off (eventName, fn) {
const fns = this.listener[eventName]
if (!fns) {
return
}
if (fn) {
for (let i = 0; i < fns.length;) {
if (fns[i].fn === fn) {
fns.splice(i, 1)
i--
}
i++
}
} else {
delete this.listener[eventName]
}
}
_clearCache (eventName) {
const cacheArgs = this.emitCache[eventName]
if (cacheArgs) {
for (; cacheArgs.length > 0;) {
this.emit.apply(this, [eventName].concat(cacheArgs.shift()))
}
}
}
_addListener (eventName, type, fn) {
(this.listener[eventName] || (this.listener[eventName] = [])).push({
fn,
type
})
}
}
+332
View File
@@ -0,0 +1,332 @@
import {
isFn,
isPlainObject
} from 'uni-shared'
import {
tryCatchFramework
} from './catch'
import {
isTaskApi,
isSyncApi,
isCallbackApi
} from './promise'
import {
getApiCallbacks
} from './utils'
import protocol from 'uni-api-protocol'
import validateParam from './params'
function invokeCallbackHandlerFail (err, apiName, callbackId) {
const errMsg = `${apiName}:fail ${err}`
if (process.env.NODE_ENV !== 'production') {
console.error(errMsg)
}
if (callbackId === -1) {
throw new Error(errMsg)
}
if (typeof callbackId === 'number') {
invokeCallbackHandler(callbackId, {
errMsg
})
}
return false
}
const callbackApiParamTypes = [{
name: 'callback',
type: Function,
required: true
}]
// 目前已用到的仅这三个
// 完整的可能包含:
// beforeValidate,
// beforeSuccess,
// afterSuccess,
// beforeFail,
// afterFail,
// beforeCancel,
// afterCancel,
// beforeAll,
// afterAll
const IGNORE_KEYS = [
'beforeValidate',
'beforeAll',
'beforeSuccess'
]
function validateParams (apiName, paramsData, callbackId) {
let paramTypes = protocol[apiName]
if (!paramTypes && isCallbackApi(apiName)) {
paramTypes = callbackApiParamTypes
}
if (paramTypes) {
if (Array.isArray(paramTypes) && Array.isArray(paramsData)) {
const paramTypeObj = Object.create(null)
const paramsDataObj = Object.create(null)
const paramsDataLength = paramsData.length
paramTypes.forEach((paramType, index) => {
paramTypeObj[paramType.name] = paramType
if (paramsDataLength > index) {
paramsDataObj[paramType.name] = paramsData[index]
}
})
paramTypes = paramTypeObj
paramsData = paramsDataObj
}
if (isFn(paramTypes.beforeValidate)) {
const err = paramTypes.beforeValidate(paramsData)
if (err) {
return invokeCallbackHandlerFail(err, apiName, callbackId)
}
}
const keys = Object.keys(paramTypes)
for (let i = 0; i < keys.length; i++) {
if (IGNORE_KEYS.indexOf(keys[i]) !== -1) {
continue
}
const err = validateParam(keys[i], paramTypes, paramsData)
if (err) {
return invokeCallbackHandlerFail(err, apiName, callbackId)
}
}
}
return true
}
let invokeCallbackId = 1
const invokeCallbacks = {}
function createKeepAliveApiCallback (apiName, callback) {
const callbackId = invokeCallbackId++
const invokeCallbackName = 'api.' + apiName + '.' + callbackId
invokeCallbacks[callbackId] = {
name: invokeCallbackName,
keepAlive: true,
callback
}
return callbackId
}
function getKeepAliveApiCallback (apiName, callback) {
for (const key in invokeCallbacks) {
const item = invokeCallbacks[key]
if (item.name.startsWith('api.' + apiName.replace(/^off/, 'on')) && item.callback === callback) {
delete invokeCallbacks[key]
return Number(key)
}
}
return 'fail'
}
function createApiCallback (apiName, params = {}, extras = {}) {
if (!isPlainObject(params)) {
return {
params
}
}
params = Object.assign({}, params)
const {
success,
fail,
cancel,
complete
} = getApiCallbacks(params)
const hasSuccess = isFn(success)
const hasFail = isFn(fail)
const hasCancel = isFn(cancel)
const hasComplete = isFn(complete)
if (!hasSuccess && !hasFail && !hasCancel && !hasComplete) { // 无回调
return {
params
}
}
const wrapperCallbacks = {}
for (const name in extras) {
const extra = extras[name]
if (isFn(extra)) {
wrapperCallbacks[name] = tryCatchFramework(extra)
}
}
const {
beforeSuccess,
afterSuccess,
beforeFail,
afterFail,
beforeCancel,
afterCancel,
beforeAll,
afterAll
} = wrapperCallbacks
const callbackId = invokeCallbackId++
const invokeCallbackName = 'api.' + apiName + '.' + callbackId
const invokeCallback = function (res) {
res.errMsg = res.errMsg || apiName + ':ok'
// 部分 api 可能返回的 errMsg 的 api 名称部分不一致,格式化为正确的
if (res.errMsg.indexOf(':ok') !== -1) {
res.errMsg = apiName + ':ok'
} else if (res.errMsg.indexOf(':cancel') !== -1) {
res.errMsg = apiName + ':cancel'
} else if (res.errMsg.indexOf(':fail') !== -1) {
let errDetail = ''
const spaceIndex = res.errMsg.indexOf(' ')
if (spaceIndex > -1) {
errDetail = res.errMsg.substr(spaceIndex)
}
res.errMsg = apiName + ':fail' + errDetail
}
isFn(beforeAll) && beforeAll(res)
const errMsg = res.errMsg
if (errMsg.indexOf(apiName + ':ok') === 0) {
isFn(beforeSuccess) && beforeSuccess(res, params)
hasSuccess && success(res)
isFn(afterSuccess) && afterSuccess(res)
} else if (errMsg.indexOf(apiName + ':cancel') === 0) {
res.errMsg = res.errMsg.replace(apiName + ':cancel', apiName + ':fail cancel')
hasFail && fail(res)
isFn(beforeCancel) && beforeCancel(res)
hasCancel && cancel(res)
isFn(afterCancel) && afterCancel(res)
} else if (errMsg.indexOf(apiName + ':fail') === 0) {
isFn(beforeFail) && beforeFail(res)
hasFail && fail(res)
isFn(afterFail) && afterFail(res)
}
hasComplete && complete(res)
isFn(afterAll) && afterAll(res)
}
invokeCallbacks[callbackId] = {
name: invokeCallbackName,
callback: invokeCallback
}
return {
params,
callbackId
}
}
function createInvokeCallback (apiName, params = {}, extras = {}) {
const {
params: args,
callbackId
} = createApiCallback(apiName, params, extras)
if (isPlainObject(args) && !validateParams(apiName, args, callbackId)) {
return {
params: args,
callbackId: false
}
}
return {
params: args,
callbackId
}
}
// onNativeEventReceive((event,data)=>{}) 需要两个参数,写死最多两个参数,避免改动太大,影响已有逻辑
export function invokeCallbackHandler (invokeCallbackId, res, extras) {
if (typeof invokeCallbackId === 'number') {
const invokeCallback = invokeCallbacks[invokeCallbackId]
if (invokeCallback) {
if (!invokeCallback.keepAlive) {
delete invokeCallbacks[invokeCallbackId]
}
return invokeCallback.callback(res, extras)
}
}
return res
}
export function removeCallbackHandler (invokeCallbackId) {
delete invokeCallbacks[invokeCallbackId]
}
export function wrapperUnimplemented (name) {
return function todo (args) {
console.error('API `' + name + '` is not yet implemented')
}
}
function wrapperExtras (name, extras) {
const protocolOptions = protocol[name]
if (protocolOptions) {
isFn(protocolOptions.beforeAll) && (extras.beforeAll = protocolOptions.beforeAll)
isFn(protocolOptions.beforeSuccess) && (extras.beforeSuccess = protocolOptions.beforeSuccess)
}
}
// 部分 API 直接实现
const unwrappers = ['getPushClientId', 'onPushMessage', 'offPushMessage']
export function wrapper (name, invokeMethod, extras = {}) {
if (unwrappers.indexOf(name) > -1 || !isFn(invokeMethod)) {
return invokeMethod
}
wrapperExtras(name, extras)
return function (...args) {
if (isSyncApi(name)) {
if (validateParams(name, args, -1)) {
return invokeMethod.apply(null, args)
}
} else if (isCallbackApi(name)) {
if (validateParams(name, args, -1)) {
return invokeMethod((name.startsWith('off') ? getKeepAliveApiCallback : createKeepAliveApiCallback)(name,
args[0]))
}
} else {
let argsObj = {}
if (args.length) {
argsObj = args[0]
}
const {
params,
callbackId
} = createInvokeCallback(name, argsObj, extras)
if (callbackId !== false) {
let res
if (isFn(params)) {
res = invokeMethod(callbackId)
} else {
res = invokeMethod(params, callbackId)
}
if (res && !isTaskApi(name)) {
res = invokeCallbackHandler(callbackId, res)
if (isPlainObject(res)) {
res.errMsg = res.errMsg || name + ':ok'
}
}
return res
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
const callbacks = {}
export default function createCallbacks (namespace) {
let scopedCallbacks = callbacks[namespace]
if (!scopedCallbacks) {
scopedCallbacks = {
id: 1,
callbacks: Object.create(null)
}
callbacks[namespace] = scopedCallbacks
}
return {
get (id) {
return scopedCallbacks.callbacks[id]
},
pop (id) {
const callback = scopedCallbacks.callbacks[id]
if (callback) {
delete scopedCallbacks.callbacks[id]
}
return callback
},
push (callback) {
const id = scopedCallbacks.id++
scopedCallbacks.callbacks[id] = callback
return id
}
}
}
+26
View File
@@ -0,0 +1,26 @@
/**
* 框架内 try-catch
*/
export function tryCatchFramework (fn) {
return function () {
try {
return fn.apply(fn, arguments)
} catch (e) {
// TODO
console.error(e)
}
}
}
/**
* 开发者 try-catch
*/
export function tryCatch (fn) {
return function () {
try {
return fn.apply(fn, arguments)
} catch (e) {
// TODO
console.error(e)
}
}
}
+24
View File
@@ -0,0 +1,24 @@
const unshift = Array.prototype.unshift
function format (args) {
unshift.call(args, '[system]')
return args
}
function createLog (method) {
return function () {
let printLog = true
if (method === 'debug' && !__uniConfig.debug) {
printLog = false
}
printLog && global.console[method].apply(global.console, format(arguments))
}
}
export default {
log: createLog('log'),
info: createLog('info'),
warn: createLog('warn'),
debug: createLog('debug'),
error: createLog('error')
}
+6
View File
@@ -0,0 +1,6 @@
export const NAVBAR_HEIGHT = 44
export const TABBAR_HEIGHT = 50
// 576:landscape phones,768:tablets,992:desktops,1200:large desktops
export const RESPONSIVE_MIN_WIDTH = 768
export const UNI_STORAGE_LOCALE = 'UNI_LOCALE'
export const ON_THEME_CHANGE = 'onThemeChange'
@@ -0,0 +1,51 @@
/**
* customElements.define
*/
(function () {
const defineProperty = Object.defineProperty
const createElement = document.createElement
const classes = new Map()
const registry = new Map()
if ('customElements' in window && customElements && customElements.define) {
return
}
function HTMLBuiltIn () {
const constructor = this.constructor
if (!classes.has(constructor)) {
throw new TypeError('Illegal constructor')
}
const is = classes.get(constructor)
const element = createElement.call(document, is)
return Object.setPrototypeOf(element, constructor.prototype)
}
defineProperty(HTMLBuiltIn.prototype = HTMLElement.prototype, 'constructor', {
value: HTMLBuiltIn
})
defineProperty(window, 'HTMLElement', {
configurable: true,
value: HTMLBuiltIn
})
defineProperty(document, 'createElement', {
configurable: true,
value: function value (name, options) {
const is = options && options.is
const Class = is ? registry.get(is) : registry.get(name)
return Class ? new Class() : createElement.call(document, name)
}
})
defineProperty(window, 'customElements', {
configurable: true,
value: {
define: function define (is, Class) {
if (registry.has(is)) {
throw new Error('the name "'.concat(is, '" has already been used with this registry'))
}
classes.set(Class, is)
registry.set(is, Class)
}
}
})
})()
+32
View File
@@ -0,0 +1,32 @@
export default function getRealRoute (fromRoute, toRoute) {
if (!toRoute) {
toRoute = fromRoute
if (toRoute.indexOf('/') === 0) {
return toRoute
}
const pages = getCurrentPages()
if (pages.length) {
fromRoute = pages[pages.length - 1].$page.route
} else {
fromRoute = ''
}
} else {
if (toRoute.indexOf('/') === 0) {
return toRoute
}
}
if (toRoute.indexOf('./') === 0) {
return getRealRoute(fromRoute, toRoute.substr(2))
}
const toRouteArray = toRoute.split('/')
const toRouteLength = toRouteArray.length
let i = 0
for (; i < toRouteLength && toRouteArray[i] === '..'; i++) {
// noop
}
toRouteArray.splice(0, i)
toRoute = toRouteArray.join('/')
const fromRouteArray = fromRoute.length > 0 ? fromRoute.split('/') : []
fromRouteArray.splice(fromRouteArray.length - i - 1, i + 1)
return '/' + fromRouteArray.concat(toRouteArray).join('/')
}
+172
View File
@@ -0,0 +1,172 @@
import {
hasOwn
}
from 'uni-shared'
export const pixelRatio = (function () {
const canvas = document.createElement('canvas')
canvas.height = canvas.width = 0
const context = canvas.getContext('2d')
const backingStore = context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1
return (window.devicePixelRatio || 1) / backingStore
})()
const forEach = function (obj, func) {
for (const key in obj) {
if (hasOwn(obj, key)) {
func(obj[key], key)
}
}
}
const ratioArgs = {
fillRect: 'all',
clearRect: 'all',
strokeRect: 'all',
moveTo: 'all',
lineTo: 'all',
arc: [0, 1, 2],
arcTo: 'all',
bezierCurveTo: 'all',
isPointinPath: 'all',
isPointinStroke: 'all',
quadraticCurveTo: 'all',
rect: 'all',
translate: 'all',
createRadialGradient: 'all',
createLinearGradient: 'all',
transform: [4, 5],
setTransform: [4, 5]
}
const proto = CanvasRenderingContext2D.prototype
proto.drawImageByCanvas = (function (_super) {
return function (canvas, srcx, srcy, srcw, srch, desx, desy, desw, desh, isScale) {
if (!this.__hidpi__) {
return _super.apply(this, arguments)
}
srcx *= pixelRatio
srcy *= pixelRatio
srcw *= pixelRatio
srch *= pixelRatio
desx *= pixelRatio
desy *= pixelRatio
desw = isScale ? desw * pixelRatio : desw
desh = isScale ? desh * pixelRatio : desh
_super.call(this, canvas, srcx, srcy, srcw, srch, desx, desy, desw, desh)
}
})(proto.drawImage)
if (pixelRatio !== 1) {
forEach(ratioArgs, function (value, key) {
proto[key] = (function (_super) {
return function () {
if (!this.__hidpi__) {
return _super.apply(this, arguments)
}
let args = Array.prototype.slice.call(arguments)
if (value === 'all') {
args = args.map(function (a) {
return a * pixelRatio
})
} else if (Array.isArray(value)) {
for (let i = 0; i < value.length; i++) {
args[value[i]] *= pixelRatio
}
}
return _super.apply(this, args)
}
})(proto[key])
})
proto.stroke = (function (_super) {
return function () {
if (!this.__hidpi__) {
return _super.apply(this, arguments)
}
this.lineWidth *= pixelRatio
_super.apply(this, arguments)
this.lineWidth /= pixelRatio
}
})(proto.stroke)
proto.fillText = (function (_super) {
return function () {
if (!this.__hidpi__) {
return _super.apply(this, arguments)
}
const args = Array.prototype.slice.call(arguments)
args[1] *= pixelRatio
args[2] *= pixelRatio
args[3] *= pixelRatio
isNaN(args[3]) && (args.length = 3)
// Safari 重新设置部分属性会导致其他值恢复默认,需获取原始值
var font = this.__font__ || this.font
this.font = font.replace(
/(\d+\.?\d*)(px|em|rem|pt)/g,
function (w, m, u) {
return (m * pixelRatio) + u
}
)
_super.apply(this, args)
this.font = font
}
})(proto.fillText)
proto.strokeText = (function (_super) {
return function () {
if (!this.__hidpi__) {
return _super.apply(this, arguments)
}
const args = Array.prototype.slice.call(arguments)
args[1] *= pixelRatio // x
args[2] *= pixelRatio // y
args[3] *= pixelRatio // maxWidth
isNaN(args[3]) && (args.length = 3)
// Safari 重新设置部分属性会导致其他值恢复默认,需获取原始值
var font = this.__font__ || this.font
this.font = font.replace(
/(\d+\.?\d*)(px|em|rem|pt)/g,
function (w, m, u) {
return (m * pixelRatio) + u
}
)
_super.apply(this, args)
this.font = font
}
})(proto.strokeText)
proto.drawImage = (function (_super) {
return function () {
if (!this.__hidpi__) {
return _super.apply(this, arguments)
}
this.scale(pixelRatio, pixelRatio)
_super.apply(this, arguments)
this.scale(1 / pixelRatio, 1 / pixelRatio)
}
})(proto.drawImage)
}
export function wrapper (canvas, hidpi = true) {
canvas.width = canvas.offsetWidth * (hidpi ? pixelRatio : 1)
canvas.height = canvas.offsetHeight * (hidpi ? pixelRatio : 1)
canvas.__hidpi__ = hidpi
// 避免低版本安卓上 context 实例被回收
canvas.__context2d__ = canvas.getContext('2d')
canvas.__context2d__.__hidpi__ = hidpi
}
+252
View File
@@ -0,0 +1,252 @@
/*
* HTML5 Parser By Sam Blowes
*
* Designed for HTML5 documents
*
* Original code by John Resig (ejohn.org)
* http://ejohn.org/blog/pure-javascript-html-parser/
* Original code by Erik Arvidsson, Mozilla Public License
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
*
* ----------------------------------------------------------------------------
* License
* ----------------------------------------------------------------------------
*
* This code is triple licensed using Apache Software License 2.0,
* Mozilla Public License or GNU Public License
*
* ////////////////////////////////////////////////////////////////////////////
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* ////////////////////////////////////////////////////////////////////////////
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Simple HTML Parser.
*
* The Initial Developer of the Original Code is Erik Arvidsson.
* Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights
* Reserved.
*
* ////////////////////////////////////////////////////////////////////////////
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ----------------------------------------------------------------------------
* Usage
* ----------------------------------------------------------------------------
*
* // Use like so:
* HTMLParser(htmlString, {
* start: function(tag, attrs, unary) {},
* end: function(tag) {},
* chars: function(text) {},
* comment: function(text) {}
* });
*
* // or to get an XML string:
* HTMLtoXML(htmlString);
*
* // or to get an XML DOM Document
* HTMLtoDOM(htmlString);
*
* // or to inject into an existing document/DOM node
* HTMLtoDOM(htmlString, document);
* HTMLtoDOM(htmlString, document.body);
*
*/
// Regular Expressions for parsing tags and attributes
var startTag =
/^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/
var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/
var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g
// Empty Elements - HTML 5
var empty = makeMap(
'area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr')
// Block Elements - HTML 5
// fixed by xxx 将 ins 标签从块级名单中移除
var block = makeMap(
'a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'
)
// Inline Elements - HTML 5
var inline = makeMap(
'abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'
)
// Elements that you can, intentionally, leave open
// (and which close themselves)
var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr')
// Attributes that have their values filled in disabled="disabled"
var fillAttrs = makeMap(
'checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected')
// Special Elements (can contain anything)
var special = makeMap('script,style')
export default function HTMLParser (html, handler) {
var index; var chars; var match; var stack = []
var last = html
stack.last = function () {
return this[this.length - 1]
}
while (html) {
chars = true
// Make sure we're not in a script or style element
if (!stack.last() || !special[stack.last()]) {
// Comment
if (html.indexOf('<!--') == 0) {
index = html.indexOf('-->')
if (index >= 0) {
if (handler.comment) { handler.comment(html.substring(4, index)) }
html = html.substring(index + 3)
chars = false
}
// end tag
} else if (html.indexOf('</') == 0) {
match = html.match(endTag)
if (match) {
html = html.substring(match[0].length)
match[0].replace(endTag, parseEndTag)
chars = false
}
// start tag
} else if (html.indexOf('<') == 0) {
match = html.match(startTag)
if (match) {
html = html.substring(match[0].length)
match[0].replace(startTag, parseStartTag)
chars = false
}
}
if (chars) {
index = html.indexOf('<')
var text = index < 0 ? html : html.substring(0, index)
html = index < 0 ? '' : html.substring(index)
if (handler.chars) { handler.chars(text) }
}
} else {
html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) {
text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2')
if (handler.chars) { handler.chars(text) }
return ''
})
parseEndTag('', stack.last())
}
if (html == last) { throw 'Parse Error: ' + html }
last = html
}
// Clean up any remaining tags
parseEndTag()
function parseStartTag (tag, tagName, rest, unary) {
tagName = tagName.toLowerCase()
if (block[tagName]) {
while (stack.last() && inline[stack.last()]) {
parseEndTag('', stack.last())
}
}
if (closeSelf[tagName] && stack.last() == tagName) {
parseEndTag('', tagName)
}
unary = empty[tagName] || !!unary
if (!unary) { stack.push(tagName) }
if (handler.start) {
var attrs = []
rest.replace(attr, function (match, name) {
var value = arguments[2] ? arguments[2]
: arguments[3] ? arguments[3]
: arguments[4] ? arguments[4]
: fillAttrs[name] ? name : ''
attrs.push({
name: name,
value: value,
escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
})
})
if (handler.start) { handler.start(tagName, attrs, unary) }
}
}
function parseEndTag (tag, tagName) {
// If no tag name is provided, clean shop
if (!tagName) { var pos = 0 }
// Find the closest opened tag of the same type
else {
for (var pos = stack.length - 1; pos >= 0; pos--) {
if (stack[pos] == tagName) { break }
}
}
if (pos >= 0) {
// Close all the open elements, up the stack
for (var i = stack.length - 1; i >= pos; i--) {
if (handler.end) { handler.end(stack[i]) }
}
// Remove the open elements from the stack
stack.length = pos
}
}
};
function makeMap (str) {
var obj = {}
var items = str.split(',')
for (var i = 0; i < items.length; i++) { obj[items[i]] = true }
return obj
}
+36
View File
@@ -0,0 +1,36 @@
{
"uni.app.quit": "Press back button again to exit",
"uni.async.error": "The connection timed out, click the screen to try again.",
"uni.showActionSheet.cancel": "Cancel",
"uni.showToast.unpaired": "Please note showToast must be paired with hideToast",
"uni.showLoading.unpaired": "Please note showLoading must be paired with hideLoading",
"uni.showModal.cancel": "Cancel",
"uni.showModal.confirm": "OK",
"uni.chooseImage.cancel": "Cancel",
"uni.chooseImage.sourceType.album": "Album",
"uni.chooseImage.sourceType.camera": "Camera",
"uni.chooseVideo.cancel": "Cancel",
"uni.chooseVideo.sourceType.album": "Album",
"uni.chooseVideo.sourceType.camera": "Camera",
"uni.chooseFile.notUserActivation": "File chooser dialog can only be shown with a user activation",
"uni.previewImage.cancel": "Cancel",
"uni.previewImage.button.save": "Save Image",
"uni.previewImage.save.success": "Saved successfully",
"uni.previewImage.save.fail": "Save failed",
"uni.setClipboardData.success": "Content copied",
"uni.scanCode.title": "Scan code",
"uni.scanCode.album": "Album",
"uni.scanCode.fail": "Recognition failure",
"uni.scanCode.flash.on": "Tap to turn light on",
"uni.scanCode.flash.off": "Tap to turn light off",
"uni.startSoterAuthentication.authContent": "Fingerprint recognition",
"uni.startSoterAuthentication.waitingContent": "Unrecognizable",
"uni.picker.done": "Done",
"uni.picker.cancel": "Cancel",
"uni.video.danmu": "Danmu",
"uni.video.volume": "Volume",
"uni.button.feedback.title": "feedback",
"uni.button.feedback.send": "send",
"uni.chooseLocation.search": "Find Place",
"uni.chooseLocation.cancel": "Cancel"
}
+36
View File
@@ -0,0 +1,36 @@
{
"uni.app.quit": "Pulse otra vez para salir",
"uni.async.error": "Se agotó el tiempo de conexión, haga clic en la pantalla para volver a intentarlo.",
"uni.showActionSheet.cancel": "Cancelar",
"uni.showToast.unpaired": "Tenga en cuenta que showToast debe estar emparejado con hideToast",
"uni.showLoading.unpaired": "Tenga en cuenta que showLoading debe estar emparejado con hideLoading",
"uni.showModal.cancel": "Cancelar",
"uni.showModal.confirm": "OK",
"uni.chooseImage.cancel": "Cancelar",
"uni.chooseImage.sourceType.album": "Álbum",
"uni.chooseImage.sourceType.camera": "Cámara",
"uni.chooseVideo.cancel": "Cancelar",
"uni.chooseVideo.sourceType.album": "Álbum",
"uni.chooseVideo.sourceType.camera": "Cámara",
"uni.chooseFile.notUserActivation": "El cuadro de diálogo del selector de archivos solo se puede mostrar con la activación del usuario",
"uni.previewImage.cancel": "Cancelar",
"uni.previewImage.button.save": "Guardar imagen",
"uni.previewImage.save.success": "Guardado exitosamente",
"uni.previewImage.save.fail": "Error al guardar",
"uni.setClipboardData.success": "Contenido copiado",
"uni.scanCode.title": "Código de escaneo",
"uni.scanCode.album": "Álbum",
"uni.scanCode.fail": "Échec de la reconnaissance",
"uni.scanCode.flash.on": "Toque para encender la luz",
"uni.scanCode.flash.off": "Toque para apagar la luz",
"uni.startSoterAuthentication.authContent": "Reconocimiento de huellas dactilares",
"uni.startSoterAuthentication.waitingContent": "Irreconocible",
"uni.picker.done": "OK",
"uni.picker.cancel": "Cancelar",
"uni.video.danmu": "Danmu",
"uni.video.volume": "Volumen",
"uni.button.feedback.title": "realimentación",
"uni.button.feedback.send": "enviar",
"uni.chooseLocation.search": "Encontrar",
"uni.chooseLocation.cancel": "Cancelar"
}
+36
View File
@@ -0,0 +1,36 @@
{
"uni.app.quit": "Appuyez à nouveau pour quitter l'application",
"uni.async.error": "La connexion a expiré, cliquez sur l'écran pour réessayer.",
"uni.showActionSheet.cancel": "Annuler",
"uni.showToast.unpaired": "Veuillez noter que showToast doit être associé à hideToast",
"uni.showLoading.unpaired": "Veuillez noter que showLoading doit être associé à hideLoading",
"uni.showModal.cancel": "Annuler",
"uni.showModal.confirm": "OK",
"uni.chooseImage.cancel": "Annuler",
"uni.chooseImage.sourceType.album": "Album",
"uni.chooseImage.sourceType.camera": "Caméra",
"uni.chooseVideo.cancel": "Annuler",
"uni.chooseVideo.sourceType.album": "Album",
"uni.chooseVideo.sourceType.camera": "Caméra",
"uni.chooseFile.notUserActivation": "La boîte de dialogue du sélecteur de fichier ne peut être affichée qu'avec une activation par l'utilisateur",
"uni.previewImage.cancel": "Annuler",
"uni.previewImage.button.save": "Guardar imagen",
"uni.previewImage.save.success": "Enregistré avec succès",
"uni.previewImage.save.fail": "Échec de la sauvegarde",
"uni.setClipboardData.success": "Contenu copié",
"uni.scanCode.title": "Code danalyse",
"uni.scanCode.album": "Album",
"uni.scanCode.fail": "Fallo de reconocimiento",
"uni.scanCode.flash.on": "Appuyez pour activer l'éclairage",
"uni.scanCode.flash.off": "Appuyez pour désactiver l'éclairage",
"uni.startSoterAuthentication.authContent": "Reconnaissance de l'empreinte digitale",
"uni.startSoterAuthentication.waitingContent": "Méconnaissable",
"uni.picker.done": "OK",
"uni.picker.cancel": "Annuler",
"uni.video.danmu": "Danmu",
"uni.video.volume": "Le Volume",
"uni.button.feedback.title": "retour d'information",
"uni.button.feedback.send": "envoyer",
"uni.chooseLocation.search": "Trouve",
"uni.chooseLocation.cancel": "Annuler"
}
+270
View File
@@ -0,0 +1,270 @@
import {
initVueI18n,
isI18nStr
} from '@dcloudio/uni-i18n'
import {
isStr
} from 'uni-shared'
import {
UNI_STORAGE_LOCALE
} from '../constants'
import en from './en.json'
import es from './es.json'
import fr from './fr.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export const LOCALE_ZH_HANS = 'zh-Hans'
export const LOCALE_ZH_HANT = 'zh-Hant'
export const LOCALE_EN = 'en'
export const LOCALE_FR = 'fr'
export const LOCALE_ES = 'es'
const messages = {}
if (__PLATFORM__ === 'h5' || __PLATFORM__ === 'app-plus') {
Object.assign(messages, {
[LOCALE_EN]: en,
[LOCALE_ES]: es,
[LOCALE_FR]: fr,
[LOCALE_ZH_HANS]: zhHans,
[LOCALE_ZH_HANT]: zhHant
})
}
export function getLocaleLanguage () {
let localeLanguage = ''
if (__PLATFORM__ === 'mp-weixin') {
const appBaseInfo = typeof wx.getAppBaseInfo === 'function' && wx.getAppBaseInfo() ? wx.getAppBaseInfo() : wx.getSystemInfoSync()
const language =
appBaseInfo && appBaseInfo.language ? appBaseInfo.language : LOCALE_EN
localeLanguage = normalizeLocale(language) || LOCALE_EN
} else {
localeLanguage =
normalizeLocale(__GLOBAL__.getSystemInfoSync().language) || LOCALE_EN
}
return localeLanguage
}
let locale
if (__PLATFORM__ === 'h5') {
locale = (navigator.cookieEnabled && window.localStorage && localStorage[UNI_STORAGE_LOCALE]) || __uniConfig.locale || navigator.language
} else if (__PLATFORM__ === 'app-plus') {
if (typeof weex === 'object') {
locale = weex.requireModule('plus').getLanguage()
} else {
locale = ''
}
} else {
locale = getLocaleLanguage()
}
function initI18nMessages () {
if (!isEnableLocale()) {
return
}
const localeKeys = Object.keys(__uniConfig.locales)
if (localeKeys.length) {
localeKeys.forEach((locale) => {
const curMessages = messages[locale]
const userMessages = __uniConfig.locales[locale]
if (curMessages) {
Object.assign(curMessages, userMessages)
} else {
messages[locale] = userMessages
}
})
}
}
initI18nMessages()
export const i18n = initVueI18n(
locale,
__PLATFORM__ === 'app-plus' || __PLATFORM__ === 'h5' ? messages : {}
)
export const t = i18n.t
export const i18nMixin = (i18n.mixin = {
beforeCreate () {
const unwatch = i18n.i18n.watchLocale(() => {
this.$forceUpdate()
})
this.$once('hook:beforeDestroy', function () {
unwatch()
})
},
methods: {
$$t (key, values) {
return t(key, values)
}
}
})
export const setLocale = i18n.setLocale
export const getLocale = i18n.getLocale
export function initAppLocale (Vue, appVm, locale) {
const state = Vue.observable({
locale: locale || i18n.getLocale()
})
const localeWatchers = []
appVm.$watchLocale = fn => {
localeWatchers.push(fn)
}
Object.defineProperty(appVm, '$locale', {
get () {
return state.locale
},
set (v) {
state.locale = v
localeWatchers.forEach(watch => watch(v))
}
})
}
export const I18N_JSON_DELIMITERS = ['%', '%']
function getLocaleMessage () {
const locale = uni.getLocale()
const locales = __uniConfig.locales
return (
locales[locale] || locales[__uniConfig.fallbackLocale] || locales[LOCALE_EN] || {}
)
}
export function formatI18n (message) {
if (isI18nStr(message, I18N_JSON_DELIMITERS)) {
return i18n.f(message, getLocaleMessage(), I18N_JSON_DELIMITERS)
}
return message
}
function resolveJsonObj (jsonObj, names) {
if (names.length === 1) {
if (jsonObj) {
const _isI18nStr = (value) => isStr(value) && isI18nStr(value, I18N_JSON_DELIMITERS)
const _name = names[0]
let filterJsonObj = []
if (Array.isArray(jsonObj) && (filterJsonObj = jsonObj.filter(item => _isI18nStr(item[_name]))).length) {
return filterJsonObj
}
const value = jsonObj[_name]
if (_isI18nStr(value)) {
return jsonObj
}
}
return
}
const name = names.shift()
return resolveJsonObj(jsonObj && jsonObj[name], names)
}
export function defineI18nProperties (obj, names) {
return names.map(name => defineI18nProperty(obj, name))
}
export function defineI18nProperty (obj, names) {
const jsonObj = resolveJsonObj(obj, names)
if (!jsonObj) {
return false
}
const prop = names[names.length - 1]
if (Array.isArray(jsonObj)) {
jsonObj
.forEach(item => defineI18nProperty(item, [prop]))
} else {
let value = jsonObj[prop]
Object.defineProperty(jsonObj, prop, {
get () {
return formatI18n(value)
},
set (v) {
value = v
}
})
}
return true
}
function isEnableLocale () {
return typeof __uniConfig !== 'undefined' && __uniConfig.locales && !!Object.keys(__uniConfig.locales).length
}
export function initNavigationBarI18n (navigationBar) {
if (isEnableLocale()) {
return defineI18nProperties(navigationBar, [
['titleText'],
['searchInput', 'placeholder'],
['buttons', 'text']
])
}
}
export function initPullToRefreshI18n (pullToRefresh) {
if (isEnableLocale()) {
const CAPTION = 'caption'
return defineI18nProperties(pullToRefresh, [
['contentdown', CAPTION],
['contentover', CAPTION],
['contentrefresh', CAPTION]
])
}
}
export function initTabBarI18n (tabBar) {
if (isEnableLocale() && tabBar.list) {
tabBar.list.forEach(item => {
defineI18nProperty(item, ['text'])
})
}
return tabBar
}
function include (str, parts) {
return !!parts.find((part) => str.indexOf(part) !== -1)
}
function startsWith (str, parts) {
return parts.find((part) => str.indexOf(part) === 0)
}
export function normalizeLocale (locale, messages) {
if (!locale) {
return
}
locale = locale.trim().replace(/_/g, '-')
if (messages && messages[locale]) {
return locale
}
locale = locale.toLowerCase()
if (locale === 'chinese') {
// 支付宝
return LOCALE_ZH_HANS
}
if (locale.indexOf('zh') === 0) {
if (locale.indexOf('-hans') > -1) {
return LOCALE_ZH_HANS
}
if (locale.indexOf('-hant') > -1) {
return LOCALE_ZH_HANT
}
if (include(locale, ['-tw', '-hk', '-mo', '-cht'])) {
return LOCALE_ZH_HANT
}
return LOCALE_ZH_HANS
}
const lang = startsWith(locale, [LOCALE_EN, LOCALE_FR, LOCALE_ES])
if (lang) {
return lang
}
}
// export function initI18n() {
// const localeKeys = Object.keys(__uniConfig.locales || {})
// if (localeKeys.length) {
// localeKeys.forEach((locale) =>
// i18n.add(locale, __uniConfig.locales[locale])
// )
// }
// }
+36
View File
@@ -0,0 +1,36 @@
{
"uni.app.quit": "再按一次退出应用",
"uni.async.error": "连接服务器超时,点击屏幕重试",
"uni.showActionSheet.cancel": "取消",
"uni.showToast.unpaired": "请注意 showToast 与 hideToast 必须配对使用",
"uni.showLoading.unpaired": "请注意 showLoading 与 hideLoading 必须配对使用",
"uni.showModal.cancel": "取消",
"uni.showModal.confirm": "确定",
"uni.chooseImage.cancel": "取消",
"uni.chooseImage.sourceType.album": "从相册选择",
"uni.chooseImage.sourceType.camera": "拍摄",
"uni.chooseVideo.cancel": "取消",
"uni.chooseVideo.sourceType.album": "从相册选择",
"uni.chooseVideo.sourceType.camera": "拍摄",
"uni.chooseFile.notUserActivation": "文件选择器对话框只能在由用户激活时显示",
"uni.previewImage.cancel": "取消",
"uni.previewImage.button.save": "保存图像",
"uni.previewImage.save.success": "保存图像到相册成功",
"uni.previewImage.save.fail": "保存图像到相册失败",
"uni.setClipboardData.success": "内容已复制",
"uni.scanCode.title": "扫码",
"uni.scanCode.album": "相册",
"uni.scanCode.fail": "识别失败",
"uni.scanCode.flash.on": "轻触照亮",
"uni.scanCode.flash.off": "轻触关闭",
"uni.startSoterAuthentication.authContent": "指纹识别中...",
"uni.startSoterAuthentication.waitingContent": "无法识别",
"uni.picker.done": "完成",
"uni.picker.cancel": "取消",
"uni.video.danmu": "弹幕",
"uni.video.volume": "音量",
"uni.button.feedback.title": "问题反馈",
"uni.button.feedback.send": "发送",
"uni.chooseLocation.search": "搜索地点",
"uni.chooseLocation.cancel": "取消"
}
+36
View File
@@ -0,0 +1,36 @@
{
"uni.app.quit": "再按一次退出應用",
"uni.async.error": "連接服務器超時,點擊屏幕重試",
"uni.showActionSheet.cancel": "取消",
"uni.showToast.unpaired": "請注意 showToast 與 hideToast 必須配對使用",
"uni.showLoading.unpaired": "請注意 showLoading 與 hideLoading 必須配對使用",
"uni.showModal.cancel": "取消",
"uni.showModal.confirm": "確定",
"uni.chooseImage.cancel": "取消",
"uni.chooseImage.sourceType.album": "從相冊選擇",
"uni.chooseImage.sourceType.camera": "拍攝",
"uni.chooseVideo.cancel": "取消",
"uni.chooseVideo.sourceType.album": "從相冊選擇",
"uni.chooseVideo.sourceType.camera": "拍攝",
"uni.chooseFile.notUserActivation": "文件選擇器對話框只能在由用戶激活時顯示",
"uni.previewImage.cancel": "取消",
"uni.previewImage.button.save": "保存圖像",
"uni.previewImage.save.success": "保存圖像到相冊成功",
"uni.previewImage.save.fail": "保存圖像到相冊失敗",
"uni.setClipboardData.success": "內容已復制",
"uni.scanCode.title": "掃碼",
"uni.scanCode.album": "相冊",
"uni.scanCode.fail": "識別失敗",
"uni.scanCode.flash.on": "輕觸照亮",
"uni.scanCode.flash.off": "輕觸關閉",
"uni.startSoterAuthentication.authContent": "指紋識別中...",
"uni.startSoterAuthentication.waitingContent": "無法識別",
"uni.picker.done": "完成",
"uni.picker.cancel": "取消",
"uni.video.danmu": "彈幕",
"uni.video.volume": "音量",
"uni.button.feedback.title": "問題反饋",
"uni.button.feedback.send": "發送",
"uni.chooseLocation.search": "搜索地點",
"uni.chooseLocation.cancel": "取消"
}
+89
View File
@@ -0,0 +1,89 @@
import {
camelize
} from 'uni-shared'
const components = ['SystemAsyncLoading', 'SystemAsyncError']
export function isPage (vm) {
if (vm.$parent && vm.$parent.$options.name === 'PageBody') {
if (components.indexOf(vm.$options.name) !== -1) {
return false
}
return true
}
return false
}
export function hasLifecycleHook (vueOptions = {}, hook) {
return Array.isArray(vueOptions[hook]) && vueOptions[hook].length
}
export function normalizeDataset (dataset = {}) {
// ios8.x,9.x Object.assign({},dataset) 始终返回 {}
// http://ask.dcloud.net.cn/question/70246
const result = JSON.parse(JSON.stringify(dataset))
if (__PLATFORM__ === 'h5') {
const keys = Object.keys(result)
const len = keys.length
if (len) {
// remove data-v-
for (let i = 0; i < len; i++) {
const key = keys[i]
const len = key.length
if (key.substr(0, 1) === 'v' && (len === 9 || len === 10)) {
delete result[key]
}
}
}
}
return result
}
export function getTargetDataset (target) {
let dataset = {}
const vm = target.__vue__
function updateDataset (vm, force) {
const $attrs = vm.$attrs
for (const key in $attrs) {
if (key.startsWith('data-')) {
const newKey = camelize(key.substr(5).toLowerCase())
const value = $attrs[key]
dataset[newKey] = force ? value : dataset[newKey] || value
}
}
}
if (vm) {
let $child = vm
while ($child && $child.$el === target) {
updateDataset($child)
$child = $child.$children[0]
}
let $parent = vm.$parent
while ($parent && $parent.$el === target) {
updateDataset($parent, true)
$parent = $parent.$parent
}
} else {
dataset = Object.assign({}, target.dataset, target.__uniDataset)
}
return normalizeDataset(dataset)
}
export function upx2px (str) {
str = str + ''
if (str.indexOf('upx') !== -1) { // upx转换
return uni.upx2px(parseInt(str) || 0)
}
return parseInt(str) || 0
}
export function findExistsPageIndex (url) {
const pages = getCurrentPages()
let len = pages.length
while (len--) {
const page = pages[len]
if (page.$page && page.$page.fullPath === url) {
return len
}
}
return -1
}
+206
View File
@@ -0,0 +1,206 @@
import {
isFn,
isPlainObject
} from 'uni-shared'
const HOOKS = [
'invoke',
'success',
'fail',
'complete',
'returnValue'
]
const globalInterceptors = {}
const scopedInterceptors = {}
function mergeHook (parentVal, childVal) {
const res = childVal
? parentVal
? parentVal.concat(childVal)
: Array.isArray(childVal)
? childVal : [childVal]
: parentVal
return res
? dedupeHooks(res)
: res
}
function dedupeHooks (hooks) {
const res = []
for (let i = 0; i < hooks.length; i++) {
if (res.indexOf(hooks[i]) === -1) {
res.push(hooks[i])
}
}
return res
}
function removeHook (hooks, hook) {
const index = hooks.indexOf(hook)
if (index !== -1) {
hooks.splice(index, 1)
}
}
function mergeInterceptorHook (interceptor, option) {
Object.keys(option).forEach(hook => {
if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) {
interceptor[hook] = mergeHook(interceptor[hook], option[hook])
}
})
}
function removeInterceptorHook (interceptor, option) {
if (!interceptor || !option) {
return
}
Object.keys(option).forEach(hook => {
if (HOOKS.indexOf(hook) !== -1 && isFn(option[hook])) {
removeHook(interceptor[hook], option[hook])
}
})
}
export function addInterceptor (method, option) {
if (typeof method === 'string' && isPlainObject(option)) {
mergeInterceptorHook(scopedInterceptors[method] || (scopedInterceptors[method] = {}), option)
} else if (isPlainObject(method)) {
mergeInterceptorHook(globalInterceptors, method)
}
}
export function removeInterceptor (method, option) {
if (typeof method === 'string') {
if (isPlainObject(option)) {
removeInterceptorHook(scopedInterceptors[method], option)
} else {
delete scopedInterceptors[method]
}
} else if (isPlainObject(method)) {
removeInterceptorHook(globalInterceptors, method)
}
}
function wrapperHook (hook, params) {
return function (data) {
return hook(data, params) || data
}
}
function isPromise (obj) {
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
}
function queue (hooks, data, params) {
let promise = false
for (let i = 0; i < hooks.length; i++) {
const hook = hooks[i]
if (promise) {
promise = Promise.resolve(wrapperHook(hook, params))
} else {
const res = hook(data, params)
if (isPromise(res)) {
promise = Promise.resolve(res)
}
if (res === false) {
return {
then () { }
}
}
}
}
return promise || {
then (callback) {
return callback(data)
}
}
}
function wrapperOptions (interceptor, options = {}) {
['success', 'fail', 'complete'].forEach(name => {
if (Array.isArray(interceptor[name])) {
const oldCallback = options[name]
options[name] = function callbackInterceptor (res) {
queue(interceptor[name], res, options).then((res) => {
/* eslint-disable no-mixed-operators */
return isFn(oldCallback) && oldCallback(res) || res
})
}
}
})
return options
}
export function wrapperReturnValue (method, returnValue) {
const returnValueHooks = []
if (Array.isArray(globalInterceptors.returnValue)) {
returnValueHooks.push(...globalInterceptors.returnValue)
}
const interceptor = scopedInterceptors[method]
if (interceptor && Array.isArray(interceptor.returnValue)) {
returnValueHooks.push(...interceptor.returnValue)
}
returnValueHooks.forEach(hook => {
returnValue = hook(returnValue) || returnValue
})
return returnValue
}
function getApiInterceptorHooks (method) {
const interceptor = Object.create(null)
Object.keys(globalInterceptors).forEach(hook => {
if (hook !== 'returnValue') {
interceptor[hook] = globalInterceptors[hook].slice()
}
})
const scopedInterceptor = scopedInterceptors[method]
if (scopedInterceptor) {
Object.keys(scopedInterceptor).forEach(hook => {
if (hook !== 'returnValue') {
interceptor[hook] = (interceptor[hook] || []).concat(scopedInterceptor[hook])
}
})
}
return interceptor
}
export function invokeApi (method, api, options, ...params) {
const interceptor = getApiInterceptorHooks(method)
if (interceptor && Object.keys(interceptor).length) {
if (Array.isArray(interceptor.invoke)) {
const res = queue(interceptor.invoke, options)
return res.then((options) => {
// 重新访问 getApiInterceptorHooks, 允许 invoke 中再次调用 addInterceptor,removeInterceptor
return api(
wrapperOptions(getApiInterceptorHooks(method), options),
...params
)
})
} else {
return api(wrapperOptions(interceptor, options), ...params)
}
}
return api(options, ...params)
}
export const promiseInterceptor = {
returnValue (res) {
if (!isPromise(res)) {
return res
}
return new Promise((resolve, reject) => {
res.then(res => {
if (!res) {
resolve(res)
return
}
if (res[0]) {
reject(res[0])
} else {
resolve(res[1])
}
})
})
}
}
+35
View File
@@ -0,0 +1,35 @@
import EventChannel from './EventChannel'
const eventChannels = {}
let id = 0
export function initEventChannel (events, cache = true) {
id++
const eventChannel = new EventChannel(id, events)
if (cache) {
eventChannels[id] = eventChannel
}
return eventChannel
}
export function getEventChannel (id) {
const eventChannel = eventChannels[id]
delete eventChannels[id]
return eventChannel
}
export default function () {
let eventChannel
return {
args (fromArgs, toArgs) {
eventChannel = initEventChannel(fromArgs.events)
if (fromArgs.url) {
fromArgs.url = fromArgs.url + (fromArgs.url.indexOf('?') === -1 ? '?' : '&') + '__id__=' + eventChannel.id
}
},
returnValue (fromRes, toRes) {
fromRes.eventChannel = eventChannel
}
}
}
+157
View File
@@ -0,0 +1,157 @@
import {
isFn,
hasOwn,
toRawType,
isPlainObject
} from 'uni-shared'
export default function validateParam (key, paramTypes, paramsData) {
const paramOptions = paramTypes[key]
const absent = !hasOwn(paramsData, key)
let value = paramsData[key]
const booleanIndex = getTypeIndex(Boolean, paramOptions.type)
if (booleanIndex > -1) {
if (absent && !hasOwn(paramOptions, 'default')) {
value = false
}
}
if (value === undefined) {
if (hasOwn(paramOptions, 'default')) {
const paramDefault = paramOptions.default
value = isFn(paramDefault) ? paramDefault() : paramDefault
paramsData[key] = value // 默认值
}
}
return assertParam(paramOptions, key, value, absent, paramsData)
}
function assertParam (
paramOptions,
name,
value,
absent,
paramsData
) {
if (paramOptions.required && absent) {
return `Missing required parameter \`${name}\``
}
if (value == null && !paramOptions.required) {
const validator = paramOptions.validator
if (validator) {
return validator(value, paramsData)
}
return
}
let type = paramOptions.type
let valid = !type || type === true
const expectedTypes = []
if (type) {
if (!Array.isArray(type)) {
type = [type]
}
for (let i = 0; i < type.length && !valid; i++) {
const assertedType = assertType(value, type[i])
expectedTypes.push(assertedType.expectedType || '')
valid = assertedType.valid
}
}
if (!valid) {
return getInvalidTypeMessage(name, value, expectedTypes)
}
const validator = paramOptions.validator
if (validator) {
return validator(value, paramsData)
}
}
const simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/
function assertType (value, type) {
let valid
const expectedType = getType(type)
if (simpleCheckRE.test(expectedType)) {
const t = typeof value
valid = t === expectedType.toLowerCase()
if (!valid && t === 'object') {
valid = value instanceof type
}
} else if (value.byteLength >= 0) {
valid = true
} else if (expectedType === 'Object') {
valid = isPlainObject(value)
} else if (expectedType === 'Array') {
valid = Array.isArray(value)
} else {
// TODO 页面传入的ArrayBuffer使用instanceof ArrayBuffer返回false,暂做此修改
valid = value instanceof type || toRawType(value) === getType(type)
}
return {
valid,
expectedType
}
}
function getType (fn) {
const match = fn && fn.toString().match(/^\s*function (\w+)/)
return match ? match[1] : ''
}
function isSameType (a, b) {
return getType(a) === getType(b)
}
function getTypeIndex (type, expectedTypes) {
if (!Array.isArray(expectedTypes)) {
return isSameType(expectedTypes, type) ? 0 : -1
}
for (let i = 0, len = expectedTypes.length; i < len; i++) {
if (isSameType(expectedTypes[i], type)) {
return i
}
}
return -1
}
function getInvalidTypeMessage (name, value, expectedTypes) {
let message = `parameter \`${name}\`.` +
` Expected ${expectedTypes.join(', ')}`
const expectedType = expectedTypes[0]
const receivedType = toRawType(value)
const expectedValue = styleValue(value, expectedType)
const receivedValue = styleValue(value, receivedType)
if (expectedTypes.length === 1 &&
isExplicable(expectedType) &&
!isBoolean(expectedType, receivedType)) {
message += ` with value ${expectedValue}`
}
message += `, got ${receivedType} `
if (isExplicable(receivedType)) {
message += `with value ${receivedValue}.`
}
return message
}
function styleValue (value, type) {
if (type === 'String') {
return `"${value}"`
} else if (type === 'Number') {
return `${Number(value)}`
} else {
return `${value}`
}
}
const explicitTypes = ['string', 'number', 'boolean']
function isExplicable (value) {
return explicitTypes.some(elem => value.toLowerCase() === elem)
}
function isBoolean (...args) {
return args.some(elem => elem.toLowerCase() === 'boolean')
}
+52
View File
@@ -0,0 +1,52 @@
import {
hasOwn,
isPlainObject
} from 'uni-shared'
/**
* mpvue event
*/
export function wrapperMPEvent (event) {
event.mp = Object.assign({
'@warning': 'mp is deprecated'
}, event)
event._processed = true
return event
}
/**
* app-plus titleNView
*/
export function mergeTitleNView (navigationBar, titleNView) {
if (isPlainObject(titleNView)) {
if (hasOwn(titleNView, 'backgroundColor')) {
navigationBar.backgroundColor = titleNView.backgroundColor
}
if (hasOwn(titleNView, 'buttons')) {
navigationBar.buttons = titleNView.buttons
}
if (hasOwn(titleNView, 'titleColor')) {
navigationBar.textColor = titleNView.titleColor
}
if (hasOwn(titleNView, 'titleText')) {
navigationBar.titleText = titleNView.titleText
}
if (hasOwn(titleNView, 'titleSize')) {
navigationBar.titleSize = titleNView.titleSize
}
if (hasOwn(titleNView, 'type')) {
navigationBar.type = titleNView.type
}
if (hasOwn(titleNView, 'searchInput') && typeof titleNView.searchInput === 'object') {
navigationBar.searchInput = Object.assign({
autoFocus: false,
align: 'center',
color: '#000000',
backgroundColor: 'rgba(255,255,255,0.5)',
borderRadius: '0px',
placeholder: '',
placeholderColor: '#CCCCCC',
disabled: false
}, titleNView.searchInput)
}
}
return navigationBar
}
+86
View File
@@ -0,0 +1,86 @@
import {
isFn
} from 'uni-shared'
import {
invokeApi,
wrapperReturnValue
} from './interceptor'
const SYNC_API_RE =
/^\$|__f__|Window$|WindowStyle$|sendHostEvent|sendNativeEvent|restoreGlobal|requireGlobal|getCurrentSubNVue|getMenuButtonBoundingClientRect|^report|interceptors|Interceptor$|getSubNVueById|requireNativePlugin|rpx2px|upx2px|hideKeyboard|canIUse|^create|Sync$|Manager$|base64ToArrayBuffer|arrayBufferToBase64|getLocale|setLocale|invokePushCallback|getWindowInfo|getDeviceInfo|getAppBaseInfo|getSystemSetting|getAppAuthorizeSetting|initUTS|requireUTS|registerUTS/
const CONTEXT_API_RE = /^create|Manager$/
// Context例外情况
const CONTEXT_API_RE_EXC = ['createBLEConnection']
const TASK_APIS = ['request', 'downloadFile', 'uploadFile', 'connectSocket']
// 同步例外情况
const ASYNC_API = ['createBLEConnection', 'createPushMessage']
const CALLBACK_API_RE = /^on|^off/
export function isContextApi (name) {
return CONTEXT_API_RE.test(name) && CONTEXT_API_RE_EXC.indexOf(name) === -1
}
export function isSyncApi (name) {
return SYNC_API_RE.test(name) && ASYNC_API.indexOf(name) === -1
}
export function isCallbackApi (name) {
return CALLBACK_API_RE.test(name) && name !== 'onPush'
}
export function isTaskApi (name) {
return TASK_APIS.indexOf(name) !== -1
}
function handlePromise (promise) {
return promise.then(data => {
return [null, data]
})
.catch(err => [err])
}
export function shouldPromise (name) {
if (
isContextApi(name) ||
isSyncApi(name) ||
isCallbackApi(name)
) {
return false
}
return true
}
/* eslint-disable no-extend-native */
if (!Promise.prototype.finally) {
Promise.prototype.finally = function (callback) {
const promise = this.constructor
return this.then(
value => promise.resolve(callback()).then(() => value),
reason => promise.resolve(callback()).then(() => {
throw reason
})
)
}
}
export function promisify (name, api) {
if (!shouldPromise(name) || !isFn(api)) {
return api
}
return function promiseApi (options = {}, ...params) {
if (isFn(options.success) || isFn(options.fail) || isFn(options.complete)) {
return wrapperReturnValue(name, invokeApi(name, api, Object.assign({}, options), ...params))
}
return wrapperReturnValue(name, handlePromise(new Promise((resolve, reject) => {
invokeApi(name, api, Object.assign({}, options, {
success: resolve,
fail: reject
}), ...params)
})))
}
}
+6
View File
@@ -0,0 +1,6 @@
const protocol = Object.create(null)
const modules = require.context('./protocol', true, /\.js$/)
modules.keys().forEach(function (key) {
Object.assign(protocol, modules(key))
})
export default protocol
+11
View File
@@ -0,0 +1,11 @@
export const base64ToArrayBuffer = [{
name: 'base64',
type: String,
required: true
}]
export const arrayBufferToBase64 = [{
name: 'arrayBuffer',
type: [ArrayBuffer, Uint8Array],
required: true
}]
@@ -0,0 +1,5 @@
export const canIUse = [{
name: 'schema',
type: String,
required: true
}]
@@ -0,0 +1,25 @@
export const $on = [{
name: 'event',
type: [String, Array],
required: true
}, {
name: 'callback',
type: Function,
required: true
}]
export const $once = $on
export const $off = [{
name: 'event',
type: [String, Array]
}, {
name: 'callback',
type: Function
}]
export const $emit = [{
name: 'event',
type: String,
required: true
}]
@@ -0,0 +1,6 @@
export const addInterceptor = [{
name: 'method',
type: [String, Object],
required: true
}]
export const removeInterceptor = addInterceptor
@@ -0,0 +1,5 @@
export const upx2px = [{
name: 'upx',
type: [Number, String],
required: true
}]
@@ -0,0 +1,131 @@
function getInt (method) {
return function (value, params) {
if (value) {
params[method] = Math.round(value)
}
}
}
export const canvasGetImageData = {
canvasId: {
type: String,
required: true
},
x: {
type: Number,
required: true,
validator: getInt('x')
},
y: {
type: Number,
required: true,
validator: getInt('y')
},
width: {
type: Number,
required: true,
validator: getInt('width')
},
height: {
type: Number,
required: true,
validator: getInt('height')
}
}
export const canvasPutImageData = {
canvasId: {
type: String,
required: true
},
data: {
type: Uint8ClampedArray,
required: true
},
x: {
type: Number,
required: true,
validator: getInt('x')
},
y: {
type: Number,
required: true,
validator: getInt('y')
},
width: {
type: Number,
required: true,
validator: getInt('width')
},
height: {
type: Number,
validator: getInt('height')
}
}
const fileTypes = {
PNG: 'png',
JPG: 'jpg',
JPEG: 'jpg'
}
export const canvasToTempFilePath = {
x: {
type: Number,
default: 0,
validator: getInt('x')
},
y: {
type: Number,
default: 0,
validator: getInt('y')
},
width: {
type: Number,
validator: getInt('width')
},
height: {
type: Number,
validator: getInt('height')
},
destWidth: {
type: Number,
validator: getInt('destWidth')
},
destHeight: {
type: Number,
validator: getInt('destHeight')
},
canvasId: {
type: String,
required: true
},
fileType: {
type: String,
validator (value, params) {
value = (value || '').toUpperCase()
params.fileType = value in fileTypes ? fileTypes[value] : fileTypes.PNG
}
},
quality: {
type: Number,
validator (value, params) {
params.quality = value > 0 && value < 1 ? value : 1
}
}
}
export const drawCanvas = {
canvasId: {
type: String,
required: true
},
actions: {
type: Array,
required: true
},
reserve: {
type: Boolean,
default: false
}
}
@@ -0,0 +1,17 @@
const validator = [{
name: 'id',
type: String,
required: true
}]
export const createAudioContext = validator
export const createVideoContext = validator
export const createMapContext = validator
export const createCanvasContext = [{
name: 'canvasId',
type: String,
required: true
}, {
name: 'componentInstance',
type: Object
}]
@@ -0,0 +1,11 @@
export const addPhoneContact = {
firstName: {
type: String,
required: true,
validator (firstName) {
if (!firstName) {
return 'addPhoneContact:fail parameter error: parameter.firstName should not be empty String;'
}
}
}
}
@@ -0,0 +1,11 @@
export const makePhoneCall = {
phoneNumber: {
type: String,
required: true,
validator (phoneNumber) {
if (!phoneNumber) {
return 'makePhoneCall:fail parameter error: parameter.phoneNumber should not be empty String;'
}
}
}
}
@@ -0,0 +1,19 @@
export const scanCode = {
onlyFromCamera: {
type: Boolean
},
scanType: {
type: Array
},
autoDecodeCharSet: {
type: Boolean
},
sound: {
type: String,
default: 'none'
},
autoZoom: {
type: Boolean,
default: true
}
}
@@ -0,0 +1,28 @@
import {
t
} from 'uni-core/helpers/i18n'
export const setClipboardData = {
data: {
type: String,
required: true
},
showToast: {
type: Boolean,
default: true
},
beforeSuccess (res, params) {
if (!params.showToast) return
const title = t('uni.setClipboardData.success')
if (title) {
uni.showToast({
title,
icon: 'success',
mask: false,
style: {
width: undefined
}
})
}
}
}
+50
View File
@@ -0,0 +1,50 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const saveFile = {
tempFilePath: {
type: String,
required: true,
validator (value, params) {
params.tempFilePath = getRealPath(value)
}
}
}
const TYPES = ['md5', 'sha1']
export const getFileInfo = {
filePath: {
type: String,
required: true,
validator (value, params) {
params.filePath = getRealPath(value)
}
},
digestAlgorithm: {
type: String,
validator (value, params) {
params.digestAlgorithm = TYPES.includes(value) ? value : TYPES[0]
},
default: TYPES[0]
}
}
export const getSavedFileInfo = {
filePath: {
type: String,
required: true,
validator (value, params) {
params.filePath = getRealPath(value)
}
}
}
export const removeSavedFile = {
filePath: {
type: String,
required: true,
validator (value, params) {
params.filePath = getRealPath(value)
}
}
}
@@ -0,0 +1,9 @@
export const openDocument = {
filePath: {
type: String,
required: true
},
fileType: {
type: String
}
}
@@ -0,0 +1,5 @@
export const chooseLocation = {
keyword: {
type: String
}
}
@@ -0,0 +1,15 @@
const coordTypes = ['wgs84', 'gcj02']
export const getLocation = {
type: {
type: String,
validator (value, params) {
value = (value || '').toLowerCase()
params.type = coordTypes.indexOf(value) < 0 ? coordTypes[0] : value
}
},
altitude: {
type: Boolean,
default: false
}
}
@@ -0,0 +1,24 @@
export const openLocation = {
latitude: {
type: Number,
required: true
},
longitude: {
type: Number,
required: true
},
scale: {
type: Number,
validator (value, params) {
value = Math.floor(value)
params.scale = value >= 5 && value <= 18 ? value : 18
},
default: 18
},
name: {
type: String
},
address: {
type: String
}
}
@@ -0,0 +1,45 @@
const MEDIA_TYPE = ['all', 'image', 'video']
const SOURCE_TYPES = ['album', 'camera']
export const chooseFile = {
count: {
type: Number,
required: false,
default: 100,
validator (count, params) {
if (count <= 0) {
params.count = 100
}
}
},
sourceType: {
type: Array,
required: false,
default: SOURCE_TYPES,
validator (sourceType, params) {
sourceType = sourceType.filter(sourceType => SOURCE_TYPES.includes(sourceType))
params.sourceType = sourceType.length ? sourceType : SOURCE_TYPES
}
},
type: {
type: String,
required: false,
default: 'all',
validator (type, params) {
if (!MEDIA_TYPE.includes(type)) params.type = MEDIA_TYPE[0]
params.type = params.type === 'all' ? params.type = '*' : params.type
}
},
extension: {
type: Array,
validator (extension, params) {
if (!extension) {
if (params.type === 'all' || params.type === '*' || !params.type) {
params.extension = ['']
} else {
params.extension = ['*']
}
} else if (extension.length === 0) { return 'param extension should not be empty.' }
}
}
}
@@ -0,0 +1,41 @@
const SIZE_TYPES = ['original', 'compressed']
const SOURCE_TYPES = ['album', 'camera']
export const chooseImage = {
count: {
type: Number,
required: false,
default: 9,
validator (count, params) {
if (count <= 0) {
params.count = 9
}
}
},
sizeType: {
type: [Array, String],
required: false,
default: SIZE_TYPES,
validator (sizeType, params) {
sizeType = typeof sizeType === 'string' ? [sizeType] : sizeType
sizeType = sizeType.filter(sizeType => SIZE_TYPES.includes(sizeType))
params.sizeType = sizeType.length ? sizeType : SIZE_TYPES
}
},
sourceType: {
type: Array,
required: false,
default: SOURCE_TYPES,
validator (sourceType, params) {
sourceType = sourceType.filter(sourceType => SOURCE_TYPES.includes(sourceType))
params.sourceType = sourceType.length ? sourceType : SOURCE_TYPES
}
},
extension: {
type: Array,
default: ['*'],
validator (extension, params) {
if (extension.length === 0) { return 'param extension should not be empty.' }
}
}
}
@@ -0,0 +1,32 @@
const SOURCE_TYPES = ['album', 'camera']
export const chooseVideo = {
sourceType: {
type: Array,
required: false,
default: SOURCE_TYPES,
validator (sourceType, params) {
sourceType = sourceType.filter(sourceType => SOURCE_TYPES.includes(sourceType))
params.sourceType = sourceType.length ? sourceType : SOURCE_TYPES
}
},
compressed: {
type: Boolean,
default: true
},
maxDuration: {
type: Number,
default: 60
},
camera: {
type: String,
default: 'back'
},
extension: {
type: Array,
default: ['*'],
validator (extension, params) {
if (extension.length === 0) { return 'param extension should not be empty.' }
}
}
}
@@ -0,0 +1,11 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const compressImage = {
src: {
type: String,
required: true,
validator (src, params) {
params.src = getRealPath(src)
}
}
}
@@ -0,0 +1,23 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const compressVideo = {
src: {
type: String,
required: true,
validator (src, params) {
params.src = getRealPath(src)
}
},
quality: {
type: String
},
bitrate: {
type: Number
},
fps: {
type: Number
},
resolution: {
type: Number
}
}
@@ -0,0 +1,11 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const getImageInfo = {
src: {
type: String,
required: true,
validator (src, params) {
params.src = getRealPath(src)
}
}
}
@@ -0,0 +1,11 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const getVideoInfo = {
src: {
type: String,
required: true,
validator (src, params) {
params.src = getRealPath(src)
}
}
}
@@ -0,0 +1,32 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const previewImage = {
urls: {
type: Array,
required: true,
validator (value, params) {
var typeError
params.urls = value.map(url => {
if (typeof url === 'string') {
return getRealPath(url)
} else {
typeError = true
}
})
if (typeError) {
return 'url is not string'
}
}
},
current: {
type: [String, Number],
validator (value, params) {
if (typeof value === 'number') {
params.current = value > 0 && value < params.urls.length ? value : 0
} else if (typeof value === 'string' && value) {
params.current = getRealPath(value)
}
},
default: 0
}
}
@@ -0,0 +1,11 @@
import getRealPath from 'uni-platform/helpers/get-real-path'
export const saveImageToPhotosAlbum = {
filePath: {
type: String,
required: true,
validator (filePath, params) {
params.filePath = getRealPath(filePath)
}
}
}
@@ -0,0 +1,12 @@
export const downloadFile = {
url: {
type: String,
required: true
},
header: {
type: Object,
validator (value, params) {
params.header = value || {}
}
}
}
@@ -0,0 +1,124 @@
import {
hasOwn,
isPlainObject,
toRawType
} from 'uni-shared'
const method = {
OPTIONS: 'OPTIONS',
GET: 'GET',
HEAD: 'HEAD',
POST: 'POST',
PUT: 'PUT',
DELETE: 'DELETE',
TRACE: 'TRACE',
CONNECT: 'CONNECT',
PATCH: 'PATCH'
}
const dataType = {
JSON: 'json'
}
const responseType = {
TEXT: 'text',
ARRAYBUFFER: 'arraybuffer'
}
const encode = encodeURIComponent
function stringifyQuery (url, data) {
let str = url.split('#')
const hash = str[1] || ''
str = str[0].split('?')
let query = str[1] || ''
url = str[0]
const search = query.split('&').filter(item => item)
query = {}
search.forEach(item => {
item = item.split('=')
query[item[0]] = item[1]
})
for (const key in data) {
if (hasOwn(data, key)) {
let v = data[key]
if (typeof v === 'undefined' || v === null) {
v = ''
} else if (isPlainObject(v)) {
v = JSON.stringify(v)
}
query[encode(key)] = encode(v)
}
}
query = Object.keys(query).map(item => `${item}=${query[item]}`).join('&')
return url + (query ? '?' + query : '') + (hash ? '#' + hash : '')
}
export const request = {
method: {
type: String,
validator (value, params) {
value = (value || '').toUpperCase()
params.method = Object.values(method).indexOf(value) < 0 ? method.GET : value
}
},
data: {
type: [Object, String, Array, ArrayBuffer],
validator (value, params) {
params.data = value || ''
}
},
url: {
type: String,
required: true,
validator (value, params) {
if (
params.method === method.GET &&
isPlainObject(params.data) &&
Object.keys(params.data).length
) { // 将 method,data 校验提前,保证 url 校验时,method,data 已被格式化
params.url = stringifyQuery(value, params.data)
}
}
},
header: {
type: Object,
validator (value, params) {
const header = params.header = value || {}
if (params.method !== method.GET) {
if (!Object.keys(header).find(key => key.toLowerCase() === 'content-type')) {
header['Content-Type'] = 'application/json'
}
}
}
},
dataType: {
type: String,
validator (value, params) {
params.dataType = (value || dataType.JSON).toLowerCase()
}
},
responseType: {
type: String,
validator (value, params) {
value = (value || '').toLowerCase()
params.responseType = Object.values(responseType).indexOf(value) < 0 ? responseType.TEXT : value
}
},
withCredentials: {
type: Boolean
},
timeout: {
type: Number
}
}
export const configMTLS = {
certificates: {
type: Array,
required: true,
validator (value) {
if (value.some(item => toRawType(item.host) !== 'String')) {
return '参数配置错误,请确认后重试'
}
}
}
}
@@ -0,0 +1,52 @@
const method = {
OPTIONS: 'OPTIONS',
GET: 'GET',
HEAD: 'HEAD',
POST: 'POST',
PUT: 'PUT',
DELETE: 'DELETE',
TRACE: 'TRACE',
CONNECT: 'CONNECT'
}
export const connectSocket = {
url: {
type: String,
required: true
},
header: {
type: Object,
validator (value, params) {
params.header = value || {}
}
},
method: {
type: String,
validator (value, params) {
value = (value || '').toUpperCase()
params.method = Object.values(method).indexOf(value) < 0 ? method.GET : value
}
},
protocols: {
// 微信文档虽然写的是数组,但是可以正常传递字符串
type: [Array, String],
validator (value, params) {
if (typeof value === 'string') {
value = [value]
}
params.protocols = (value || []).filter(str => typeof str === 'string')
}
}
}
export const sendSocketMessage = {
data: {
type: [String, ArrayBuffer]
}
}
export const closeSocket = {
code: {
type: Number
},
reason: {
type: String
}
}
@@ -0,0 +1,35 @@
// App端可以只使用files不传filePath和name
import getRealPath from 'uni-platform/helpers/get-real-path'
export const uploadFile = {
url: {
type: String,
required: true
},
files: {
type: Array
},
filePath: {
type: String,
validator (value, params) {
if (value) {
params.filePath = getRealPath(value)
}
}
},
name: {
type: String
},
header: {
type: Object,
validator (value, params) {
params.header = value || {}
}
},
formData: {
type: Object,
validator (value, params) {
params.formData = value || {}
}
}
}
@@ -0,0 +1,19 @@
const service = {
OAUTH: 'OAUTH',
SHARE: 'SHARE',
PAYMENT: 'PAYMENT',
PUSH: 'PUSH'
}
export const getProvider = {
service: {
type: String,
required: true,
validator (value, params) {
value = (value || '').toUpperCase()
if (value && Object.values(service).indexOf(value) < 0) {
return 'service error'
}
}
}
}
@@ -0,0 +1,15 @@
export const loadSubPackage = {
root: {
type: String,
required: true,
validator (value, params) {
const subPackages = __uniConfig.subPackages
if (!Array.isArray(subPackages) || subPackages.length === 0) {
return 'no subPackages'
}
if (!subPackages.find(subPackage => subPackage.root === value)) {
return 'root `' + value + '` is not found'
}
}
}
}
@@ -0,0 +1,16 @@
const provider = {
UNIVERIFY: 'univerify'
}
export const preLogin = {
provider: {
type: String,
required: true,
default: provider.UNIVERIFY,
validator (value, params) {
if (Object.values(provider).indexOf(value) < 0) {
return 'provider error'
}
}
}
}
+197
View File
@@ -0,0 +1,197 @@
import getRealRoute from '../../get-real-route'
function encodeQueryString (url) {
if (typeof url !== 'string') {
return url
}
const index = url.indexOf('?')
if (index === -1) {
return url
}
const query = url.substr(index + 1).trim().replace(/^(\?|#|&)/, '')
if (!query) {
return url
}
url = url.substr(0, index)
const params = []
query.split('&').forEach(param => {
const parts = param.replace(/\+/g, ' ').split('=')
const key = parts.shift()
const val = parts.length > 0
? parts.join('=')
: ''
params.push(key + '=' + encodeURIComponent(val))
})
return params.length ? url + '?' + params.join('&') : url
}
function createValidator (type) {
return function validator (url, params) {
// 格式化为绝对路径路由
url = getRealRoute(url)
const pagePath = url.split('?')[0]
// 匹配路由是否存在
const routeOptions = __uniRoutes.find(({
path,
alias
}) => path === pagePath || alias === pagePath)
if (!routeOptions) {
return 'page `' + url + '` is not found'
}
// 检测不同类型跳转
if (type === 'navigateTo' || type === 'redirectTo') {
if (routeOptions.meta.isTabBar) {
return `can not ${type} a tabbar page`
}
} else if (type === 'switchTab') {
if (!routeOptions.meta.isTabBar) {
return 'can not switch to no-tabBar page'
}
}
// switchTab不允许传递参数,reLaunch到一个tabBar页面是可以的
if (
(type === 'switchTab' || type === 'preloadPage') &&
routeOptions.meta.isTabBar &&
params.openType !== 'appLaunch'
) {
url = pagePath
}
// 首页自动格式化为`/`
if (routeOptions.meta.isEntry) {
url = url.replace(routeOptions.alias, '/')
}
// 参数格式化
params.url = encodeQueryString(url)
if (type === 'unPreloadPage') {
return
} else if (type === 'preloadPage') {
if (__PLATFORM__ === 'app-plus') {
if (!routeOptions.meta.isNVue) {
return 'can not preload vue page'
}
}
if (routeOptions.meta.isTabBar) {
const pages = getCurrentPages(true)
const tabBarPagePath = (routeOptions.alias || routeOptions.path).substr(1)
if (pages.find(page => page.route === tabBarPagePath)) {
return 'tabBar page `' + tabBarPagePath + '` already exists'
}
}
return
}
// 主要拦截目标为用户快速点击时触发的多次跳转,该情况,通常前后 url 是一样的
if (navigatorLock === url && params.openType !== 'appLaunch') {
return `${navigatorLock} locked`
}
// 至少 onLaunch 之后,再启用lock逻辑(onLaunch之前可能开发者手动调用路由API,来提前跳转)
// enableNavigatorLock 临时开关(不对外开放),避免该功能上线后,有部分情况异常,可以让开发者临时关闭 lock 功能
if (__uniConfig.ready && __uniConfig.enableNavigatorLock !== false) {
navigatorLock = url
}
}
}
let navigatorLock
function createProtocol (type, extras = {}) {
return Object.assign({
url: {
type: String,
required: true,
validator: createValidator(type)
},
beforeAll () {
navigatorLock = ''
}
}, extras)
}
function createAnimationProtocol (animationTypes) {
return {
animationType: {
type: String,
validator (type) {
if (type && animationTypes.indexOf(type) === -1) {
return '`' + type + '` is not supported for `animationType` (supported values are: `' + animationTypes.join(
'`|`') + '`)'
}
}
},
animationDuration: {
type: Number
}
}
}
export const redirectTo = createProtocol('redirectTo')
export const reLaunch = createProtocol('reLaunch')
export const navigateTo = createProtocol('navigateTo', createAnimationProtocol(
[
'slide-in-right',
'slide-in-left',
'slide-in-top',
'slide-in-bottom',
'fade-in',
'zoom-out',
'zoom-fade-out',
'pop-in',
'none'
]
))
export const switchTab = createProtocol('switchTab')
export const navigateBack = Object.assign({
delta: {
type: Number,
validator (delta, params) {
delta = parseInt(delta) || 1
params.delta = Math.min(getCurrentPages().length - 1, delta)
}
}
}, createAnimationProtocol(
[
'slide-out-right',
'slide-out-left',
'slide-out-top',
'slide-out-bottom',
'fade-out',
'zoom-in',
'zoom-fade-in',
'pop-out',
'none'
]
))
export const preloadPage = {
url: {
type: String,
required: true,
validator: createValidator('preloadPage')
}
}
export const unPreloadPage = {
url: {
type: String,
required: true,
validator: createValidator('unPreloadPage')
}
}
@@ -0,0 +1,34 @@
export const getStorage = {
key: {
type: String,
required: true
}
}
export const getStorageSync = [{
name: 'key',
type: String,
required: true
}]
export const setStorage = {
key: {
type: String,
required: true
},
data: {
required: true
}
}
export const setStorageSync = [{
name: 'key',
type: String,
required: true
}, {
name: 'data',
required: true
}]
export const removeStorage = getStorage
export const removeStorageSync = getStorageSync
@@ -0,0 +1,26 @@
export const loadFontFace = {
family: {
type: String,
required: true
},
source: {
type: String,
required: true
},
desc: {
type: Object,
required: false
},
success: {
type: Function,
required: false
},
fail: {
type: Function,
required: false
},
complete: {
type: Function,
required: false
}
}
@@ -0,0 +1,37 @@
const FRONT_COLORS = ['#ffffff', '#000000']
export const setNavigationBarColor = {
frontColor: {
type: String,
required: true,
validator (frontColor, params) {
if (FRONT_COLORS.indexOf(frontColor) === -1) {
return `invalid frontColor "${frontColor}"`
}
}
},
backgroundColor: {
type: String,
required: true
},
animation: {
type: Object,
default () {
return {
duration: 0,
timingFunc: 'linear'
}
},
validator (animation = {}, params) {
params.animation = {
duration: animation.duration || 0,
timingFunc: animation.timingFunc || 'linear'
}
}
}
}
export const setNavigationBarTitle = {
title: {
type: String,
required: true
}
}
@@ -0,0 +1,12 @@
export const pageScrollTo = {
scrollTop: {
type: Number
},
duration: {
type: Number,
default: 300,
validator (duration, params) {
params.duration = Math.max(0, duration)
}
}
}
+125
View File
@@ -0,0 +1,125 @@
import {
t
} from 'uni-core/helpers/i18n'
import getRealPath from 'uni-platform/helpers/get-real-path'
export const showModal = {
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
showCancel: {
type: Boolean,
default: true
},
cancelText: {
type: String,
default () {
return t('uni.showModal.cancel')
}
},
cancelColor: {
type: String,
default: '#000'
},
confirmText: {
type: String,
default () {
return t('uni.showModal.confirm')
}
},
confirmColor: {
type: String,
default: '#007aff'
},
visible: {
type: Boolean,
default: true
}
}
export const showToast = {
title: {
type: String,
default: ''
},
icon: {
default: 'success',
validator (icon, params) {
if (['success', 'loading', 'error', 'none'].indexOf(icon) === -1) {
params.icon = 'success'
}
}
},
image: {
type: String,
default: '',
validator (image, params) {
if (image) {
params.image = getRealPath(image)
}
}
},
duration: {
type: Number,
default: 1500
},
mask: {
type: Boolean,
default: false
},
visible: {
type: Boolean,
default: true
}
}
export const showLoading = {
title: {
type: String,
default: ''
},
icon: {
type: String,
default: 'loading'
},
duration: {
type: Number,
default: 100000000 // 简单处理 showLoading,直接设置个大值
},
mask: {
type: Boolean,
default: false
},
visible: {
type: Boolean,
default: true
}
}
export const showActionSheet = {
itemList: {
type: Array,
required: true,
validator (itemList, params) {
if (!itemList.length) {
return 'parameter.itemList should have at least 1 item'
}
}
},
itemColor: {
type: String,
default: '#000'
},
visible: {
type: Boolean,
default: true
},
popover: {
type: Object
}
}
+95
View File
@@ -0,0 +1,95 @@
import {
getLen
} from 'uni-shared'
import getRealPath from 'uni-platform/helpers/get-real-path'
const indexValidator = {
type: Number,
required: true
}
export const setTabBarItem = {
index: indexValidator,
text: {
type: String
},
iconPath: {
type: String
},
selectedIconPath: {
type: String
},
pagePath: {
type: String
}
}
export const setTabBarStyle = {
color: {
type: String
},
selectedColor: {
type: String
},
backgroundColor: {
type: String
},
backgroundImage: {
type: String,
validator (backgroundImage, params) {
if (backgroundImage && !(/^(linear|radial)-gradient\(.+?\);?$/.test(backgroundImage))) {
params.backgroundImage = getRealPath(backgroundImage)
}
}
},
backgroundRepeat: {
type: String
},
borderStyle: {
type: String,
validator (borderStyle, params) {
if (borderStyle) {
params.borderStyle = borderStyle === 'black' ? 'black' : 'white'
}
}
}
}
export const hideTabBar = {
animation: {
type: Boolean,
default: false
}
}
export const showTabBar = {
animation: {
type: Boolean,
default: false
}
}
export const hideTabBarRedDot = {
index: indexValidator
}
export const showTabBarRedDot = {
index: indexValidator
}
export const removeTabBarBadge = {
index: indexValidator
}
export const setTabBarBadge = {
index: indexValidator,
text: {
type: String,
required: true,
validator (text, params) {
if (getLen(text) >= 4) {
params.text = '...'
}
}
}
}
+62
View File
@@ -0,0 +1,62 @@
module.exports = [
'uni-app',
'uni-layout',
'uni-content',
'uni-main',
'uni-top-window',
'uni-left-window',
'uni-right-window',
'uni-tabbar',
'uni-page',
'uni-page-head',
'uni-page-wrapper',
'uni-page-body',
'uni-page-refresh',
'uni-actionsheet',
'uni-modal',
'uni-toast',
'uni-resize-sensor',
'uni-shadow-root',
'uni-ad',
'uni-audio',
'uni-button',
'uni-camera',
'uni-canvas',
'uni-checkbox',
'uni-checkbox-group',
'uni-cover-image',
'uni-cover-view',
'uni-editor',
'uni-form',
'uni-functional-page-navigator',
'uni-icon',
'uni-image',
'uni-input',
'uni-label',
'uni-live-player',
'uni-live-pusher',
'uni-map',
'uni-movable-area',
'uni-movable-view',
'uni-navigator',
'uni-official-account',
'uni-open-data',
'uni-picker',
'uni-picker-view',
'uni-picker-view-column',
'uni-progress',
'uni-radio',
'uni-radio-group',
'uni-rich-text',
'uni-scroll-view',
'uni-slider',
'uni-swiper',
'uni-swiper-item',
'uni-switch',
'uni-text',
'uni-textarea',
'uni-video',
'uni-view',
'uni-web-view'
]
+19
View File
@@ -0,0 +1,19 @@
import {
isFn
} from 'uni-shared'
import {
tryCatch
} from './catch'
export function getApiCallbacks (params) {
const apiCallbacks = {}
for (const name in params) {
const param = params[name]
if (isFn(param)) {
apiCallbacks[name] = tryCatch(param)
delete params[name]
}
}
return apiCallbacks
}
View File
+13
View File
@@ -0,0 +1,13 @@
const WINDOW_NAMES = ['VUniLeftWindow', 'VUniTopWindow', 'VUniRightWindow']
export function checkInWindows (vm) {
if (__PLATFORM__ !== 'h5') {
return false
}
while (vm) {
if (WINDOW_NAMES.indexOf(vm.$options.name) !== -1) {
return true
}
vm = vm.$parent
}
}
+7
View File
@@ -0,0 +1,7 @@
export { upx2px } from './upx2px'
export { upx2px as rpx2px } from './upx2px'
export * from './locale'
export * from '../service/api/base/interceptor'
+28
View File
@@ -0,0 +1,28 @@
import Vue from 'vue'
const getEmitter = (function () {
let Emitter
return function getUniEmitter () {
if (!Emitter) {
Emitter = new Vue()
}
return Emitter
}
})()
function apply (ctx, method, args) {
return ctx[method].apply(ctx, args)
}
export function $on () {
return apply(getEmitter(), '$on', [...arguments])
}
export function $off () {
return apply(getEmitter(), '$off', [...arguments])
}
export function $once () {
return apply(getEmitter(), '$once', [...arguments])
}
export function $emit () {
return apply(getEmitter(), '$emit', [...arguments])
}
+28
View File
@@ -0,0 +1,28 @@
import {
isFn
} from 'uni-shared'
import providers from 'uni-platform/runtime/api/providers'
export function getProvider ({
service,
success,
fail,
complete
}) {
let res = false
if (providers[service]) {
res = {
errMsg: 'getProvider:ok',
service,
provider: providers[service]
}
isFn(success) && success(res)
} else {
res = {
errMsg: 'getProvider:fail service not found'
}
isFn(fail) && fail(res)
}
isFn(complete) && complete(res)
}

Some files were not shown because too many files have changed in this diff Show More