agora-appbuilder-core 2.0.1 → 2.0.3-rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +2 -1
- package/package.json +1 -1
- package/template/_package-lock.json +8853 -8806
- package/template/agora-rn-uikit/.git/index +0 -0
- package/template/agora-rn-uikit/.git/logs/HEAD +2 -2
- package/template/agora-rn-uikit/.git/logs/refs/heads/ab-dev-auto +1 -1
- package/template/agora-rn-uikit/.git/logs/refs/heads/master +1 -1
- package/template/agora-rn-uikit/.git/logs/refs/remotes/origin/HEAD +1 -1
- package/template/agora-rn-uikit/.git/objects/pack/pack-2a0122bf5a3199f941e5a52535f43881623f752c.idx +0 -0
- package/template/agora-rn-uikit/.git/objects/pack/{pack-f379286d0537eb68377220b4929979324b8d5d1c.pack → pack-2a0122bf5a3199f941e5a52535f43881623f752c.pack} +0 -0
- package/template/agora-rn-uikit/.git/packed-refs +4 -2
- package/template/agora-rn-uikit/.git/refs/heads/ab-dev-auto +1 -1
- package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +21 -0
- package/template/agora-rn-uikit/src/Controls/BtnTemplate.tsx +22 -14
- package/template/agora-rn-uikit/src/Controls/ImageIcon.tsx +17 -13
- package/template/agora-rn-uikit/src/Controls/types.ts +4 -0
- package/template/agora-rn-uikit/src/Rtc/Create.tsx +117 -19
- package/template/agora-rn-uikit/src/RtcConfigure.tsx +24 -13
- package/template/{src/utils/isSafariBrowser.tsx → agora-rn-uikit/src/Utils/isSafariBrowser.ts} +3 -0
- package/template/{src → agora-rn-uikit/src}/hooks/useImageDelay.tsx +5 -2
- package/template/agora-rn-uikit/src/index.ts +2 -0
- package/template/bridge/rtc/webNg/RtcEngine.ts +73 -70
- package/template/bridge/rtc/webNg/Types.ts +59 -5
- package/template/bridge/rtm/web/Types.ts +13 -0
- package/template/bridge/rtm/web/index.ts +78 -1
- package/template/global.d.ts +2 -0
- package/template/package-lock.json +8853 -8806
- package/template/package.json +3 -4
- package/template/react-native-toast-message/src/components/base/styles.js +4 -2
- package/template/src/assets/icons.ts +41 -28
- package/template/src/components/Chat.tsx +70 -184
- package/template/src/components/ChatContext.ts +13 -2
- package/template/src/components/Controls.native.tsx +37 -76
- package/template/src/components/Controls.tsx +50 -158
- package/template/src/components/DeviceConfigure.native.tsx +5 -1
- package/template/src/components/DeviceConfigure.tsx +38 -20
- package/template/src/components/Navbar.tsx +185 -226
- package/template/src/components/ParticipantsView.tsx +176 -184
- package/template/src/components/Precall.native.tsx +83 -69
- package/template/src/components/Precall.tsx +174 -191
- package/template/src/components/RTMConfigure.tsx +264 -78
- package/template/src/components/SettingsView.tsx +9 -19
- package/template/src/components/livestream/LiveStreamContext.tsx +411 -0
- package/template/src/components/livestream/Types.ts +69 -0
- package/template/src/components/livestream/index.ts +9 -0
- package/template/src/components/livestream/views/LiveStreamControls.tsx +27 -0
- package/template/src/components/participants/AllAudienceParticipants.tsx +53 -0
- package/template/src/components/participants/AllHostParticipants.tsx +65 -0
- package/template/src/components/participants/MeParticipant.tsx +37 -0
- package/template/src/components/participants/ParticipantName.tsx +47 -0
- package/template/src/components/participants/ParticipantSectionTitle.tsx +29 -0
- package/template/src/components/participants/RemoteParticipants.tsx +69 -0
- package/template/src/components/participants/ScreenshareParticipants.tsx +28 -0
- package/template/src/components/participants/context/ParticipantContext.tsx +97 -0
- package/template/src/components/styles.ts +13 -0
- package/template/src/pages/Create.tsx +25 -14
- package/template/src/pages/VideoCall.tsx +197 -159
- package/template/src/subComponents/ChatBubble.tsx +4 -1
- package/template/src/subComponents/ChatContainer.tsx +44 -20
- package/template/src/subComponents/ChatInput.tsx +4 -12
- package/template/src/subComponents/Checkbox.native.tsx +6 -5
- package/template/src/subComponents/Checkbox.tsx +1 -0
- package/template/src/subComponents/Recording.tsx +23 -9
- package/template/src/subComponents/RemoteVideoMute.tsx +2 -3
- package/template/src/subComponents/SelectDevice.tsx +70 -35
- package/template/src/subComponents/chat/ChatParticipants.tsx +121 -0
- package/template/src/subComponents/livestream/ApprovedLiveStreamControlsView.tsx +23 -0
- package/template/src/subComponents/livestream/CurrentLiveStreamRequestsView.tsx +70 -0
- package/template/src/subComponents/livestream/controls/LocalRaiseHand.tsx +57 -0
- package/template/src/subComponents/livestream/controls/RemoteLiveStreamApprovedRequestRecall.tsx +24 -0
- package/template/src/subComponents/livestream/controls/RemoteLiveStreamRequestApprove.tsx +38 -0
- package/template/src/subComponents/livestream/controls/RemoteLiveStreamRequestReject.tsx +37 -0
- package/template/src/subComponents/livestream/index.ts +18 -0
- package/template/src/subComponents/screenshare/ScreenshareButton.tsx +80 -0
- package/template/src/subComponents/screenshare/ScreenshareConfigure.native.tsx +24 -0
- package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +200 -0
- package/template/src/subComponents/screenshare/ScreenshareContext.tsx +21 -0
- package/template/src/utils/index.tsx +48 -0
- package/template/agora-rn-uikit/.git/objects/pack/pack-f379286d0537eb68377220b4929979324b8d5d1c.idx +0 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
********************************************
|
|
3
|
+
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
+
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
+
(the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
+
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
+
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
+
any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
|
|
9
|
+
information visit https://appbuilder.agora.io.
|
|
10
|
+
*********************************************
|
|
11
|
+
*/
|
|
12
|
+
import React, {useContext} from 'react';
|
|
13
|
+
import {TouchableOpacity, StyleSheet, View, Text} from 'react-native';
|
|
14
|
+
import ColorContext from '../../components/ColorContext';
|
|
15
|
+
import {ImageIcon} from '../../../agora-rn-uikit';
|
|
16
|
+
import ScreenshareContext from './ScreenshareContext';
|
|
17
|
+
/**
|
|
18
|
+
* A component to start and stop screen sharing on web clients.
|
|
19
|
+
* Screen sharing is not yet implemented on mobile platforms.
|
|
20
|
+
* Electron has it's own screen sharing component
|
|
21
|
+
*/
|
|
22
|
+
const ScreenshareButton = () => {
|
|
23
|
+
const {screenshareActive, startUserScreenshare} =
|
|
24
|
+
useContext(ScreenshareContext);
|
|
25
|
+
const {primaryColor} = useContext(ColorContext);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<TouchableOpacity onPress={() => startUserScreenshare()}>
|
|
29
|
+
<View
|
|
30
|
+
style={
|
|
31
|
+
screenshareActive
|
|
32
|
+
? style.greenLocalButton
|
|
33
|
+
: [style.localButton, {borderColor: primaryColor}]
|
|
34
|
+
}>
|
|
35
|
+
<ImageIcon
|
|
36
|
+
name={screenshareActive ? 'screenshareOffIcon' : 'screenshareIcon'}
|
|
37
|
+
style={[style.buttonIcon]}
|
|
38
|
+
/>
|
|
39
|
+
</View>
|
|
40
|
+
<Text
|
|
41
|
+
style={{
|
|
42
|
+
textAlign: 'center',
|
|
43
|
+
marginTop: 5,
|
|
44
|
+
color: $config.PRIMARY_COLOR,
|
|
45
|
+
}}>
|
|
46
|
+
Share
|
|
47
|
+
</Text>
|
|
48
|
+
</TouchableOpacity>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const style = StyleSheet.create({
|
|
53
|
+
localButton: {
|
|
54
|
+
backgroundColor: $config.SECONDARY_FONT_COLOR,
|
|
55
|
+
borderRadius: 20,
|
|
56
|
+
borderColor: $config.PRIMARY_COLOR,
|
|
57
|
+
width: 40,
|
|
58
|
+
height: 40,
|
|
59
|
+
display: 'flex',
|
|
60
|
+
alignSelf: 'center',
|
|
61
|
+
alignItems: 'center',
|
|
62
|
+
justifyContent: 'center',
|
|
63
|
+
},
|
|
64
|
+
greenLocalButton: {
|
|
65
|
+
backgroundColor: '#4BEB5B',
|
|
66
|
+
borderRadius: 20,
|
|
67
|
+
borderColor: '#F86051',
|
|
68
|
+
width: 40,
|
|
69
|
+
height: 40,
|
|
70
|
+
alignSelf: 'center',
|
|
71
|
+
alignItems: 'center',
|
|
72
|
+
justifyContent: 'center',
|
|
73
|
+
},
|
|
74
|
+
buttonIcon: {
|
|
75
|
+
width: '90%',
|
|
76
|
+
height: '90%',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
export default ScreenshareButton;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
********************************************
|
|
3
|
+
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
+
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
+
(the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
+
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
+
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
+
any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
|
|
9
|
+
information visit https://appbuilder.agora.io.
|
|
10
|
+
*********************************************
|
|
11
|
+
*/
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import KeepAwake from 'react-native-keep-awake';
|
|
14
|
+
|
|
15
|
+
export const ScreenshareConfigure: React.FC = (props: any) => {
|
|
16
|
+
return (
|
|
17
|
+
<>
|
|
18
|
+
{props.children}
|
|
19
|
+
<KeepAwake />
|
|
20
|
+
</>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default ScreenshareConfigure;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
8
|
+
import {useParams} from '../../components/Router';
|
|
9
|
+
import ChatContext from '../../components/ChatContext';
|
|
10
|
+
import {
|
|
11
|
+
RtcContext,
|
|
12
|
+
PropsContext,
|
|
13
|
+
MinUidContext,
|
|
14
|
+
MaxUidContext,
|
|
15
|
+
} from '../../../agora-rn-uikit/src';
|
|
16
|
+
import Layout from '../LayoutEnum';
|
|
17
|
+
import {gql, useMutation} from '@apollo/client';
|
|
18
|
+
import ScreenshareContext from './ScreenshareContext';
|
|
19
|
+
|
|
20
|
+
const SET_PRESENTER = gql`
|
|
21
|
+
mutation setPresenter($uid: Int!, $passphrase: String!) {
|
|
22
|
+
setPresenter(uid: $uid, passphrase: $passphrase)
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const SET_NORMAL = gql`
|
|
27
|
+
mutation setNormal($passphrase: String!) {
|
|
28
|
+
setNormal(passphrase: $passphrase)
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
function usePrevious(value: any) {
|
|
33
|
+
const ref = useRef();
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
ref.current = value;
|
|
36
|
+
});
|
|
37
|
+
return ref.current;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const ScreenshareContextConsumer = ScreenshareContext.Consumer;
|
|
41
|
+
|
|
42
|
+
export const ScreenshareConfigure = (props: any) => {
|
|
43
|
+
const {userList} = useContext(ChatContext);
|
|
44
|
+
const [screenshareActive, setScreenshareActive] = useState(false);
|
|
45
|
+
const rtc = useContext(RtcContext);
|
|
46
|
+
const {dispatch} = rtc;
|
|
47
|
+
const max = useContext(MaxUidContext);
|
|
48
|
+
const min = useContext(MinUidContext);
|
|
49
|
+
const users = [...max, ...min];
|
|
50
|
+
const prevUsers = usePrevious({users});
|
|
51
|
+
const {phrase} = useParams<any>();
|
|
52
|
+
const {setLayout, recordingActive} = props;
|
|
53
|
+
const {channel, appId, screenShareUid, screenShareToken, encryption} =
|
|
54
|
+
useContext(PropsContext).rtcProps;
|
|
55
|
+
|
|
56
|
+
const [setPresenterQuery] = useMutation(SET_PRESENTER);
|
|
57
|
+
const [setNormalQuery] = useMutation(SET_NORMAL);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
rtc.RtcEngine.addListener('ScreenshareStopped', () => {
|
|
61
|
+
setScreenshareActive(false);
|
|
62
|
+
console.log('STOPPED SHARING');
|
|
63
|
+
setLayout((l: Layout) =>
|
|
64
|
+
l === Layout.Pinned ? Layout.Grid : Layout.Pinned,
|
|
65
|
+
);
|
|
66
|
+
setNormalQuery({variables: {passphrase: phrase}})
|
|
67
|
+
.then((res) => {
|
|
68
|
+
console.log(res.data);
|
|
69
|
+
if (res.data.stopRecordingSession === 'success') {
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.catch((err) => {
|
|
73
|
+
console.log(err);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
}, []);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (prevUsers !== undefined) {
|
|
80
|
+
let joinedUser = users.filter((person) =>
|
|
81
|
+
prevUsers?.users.every((person2) => !(person2.uid === person.uid)),
|
|
82
|
+
);
|
|
83
|
+
let leftUser = prevUsers?.users.filter((person) =>
|
|
84
|
+
users.every((person2) => !(person2.uid === person.uid)),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (joinedUser.length === 1) {
|
|
88
|
+
const newUserUid = joinedUser[0].uid;
|
|
89
|
+
if (userList[newUserUid] && userList[newUserUid].type === 1) {
|
|
90
|
+
dispatch({
|
|
91
|
+
type: 'SwapVideo',
|
|
92
|
+
value: [joinedUser[0]],
|
|
93
|
+
});
|
|
94
|
+
setLayout(Layout.Pinned);
|
|
95
|
+
} else if (newUserUid === 1) {
|
|
96
|
+
if (newUserUid !== users[0].uid) {
|
|
97
|
+
dispatch({
|
|
98
|
+
type: 'SwapVideo',
|
|
99
|
+
value: [joinedUser[0]],
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
setLayout(Layout.Pinned);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (leftUser.length === 1) {
|
|
107
|
+
const leftUserUid = leftUser[0].uid;
|
|
108
|
+
if (userList[leftUserUid] && userList[leftUserUid].type === 1) {
|
|
109
|
+
setLayout((l: Layout) =>
|
|
110
|
+
l === Layout.Pinned ? Layout.Grid : Layout.Pinned,
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}, [users, userList]);
|
|
116
|
+
|
|
117
|
+
const executeRecordingQuery = (isScreenActive: boolean) => {
|
|
118
|
+
if (!isScreenActive) {
|
|
119
|
+
// If screen share is not going on, start the screen share by executing the graphql query
|
|
120
|
+
setPresenterQuery({
|
|
121
|
+
variables: {
|
|
122
|
+
uid: screenShareUid,
|
|
123
|
+
passphrase: phrase,
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
.then((res) => {
|
|
127
|
+
if (res.data.setPresenter === 'success') {
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
.catch((err) => {
|
|
131
|
+
console.log(err);
|
|
132
|
+
});
|
|
133
|
+
} else {
|
|
134
|
+
// If recording is already going on, stop the recording by executing the graphql query.
|
|
135
|
+
setNormalQuery({variables: {passphrase: phrase}})
|
|
136
|
+
.then((res) => {
|
|
137
|
+
console.log(res.data);
|
|
138
|
+
if (res.data.stopRecordingSession === 'success') {
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
.catch((err) => {
|
|
142
|
+
console.log(err);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const stopUserScreenShare = () => {
|
|
148
|
+
if (screenshareActive) {
|
|
149
|
+
startUserScreenshare();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const startUserScreenshare = async () => {
|
|
154
|
+
const isScreenActive = screenshareActive;
|
|
155
|
+
if (recordingActive) {
|
|
156
|
+
executeRecordingQuery(isScreenActive);
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
await rtc.RtcEngine.startScreenshare(
|
|
160
|
+
screenShareToken,
|
|
161
|
+
channel,
|
|
162
|
+
null,
|
|
163
|
+
screenShareUid,
|
|
164
|
+
appId,
|
|
165
|
+
rtc.RtcEngine,
|
|
166
|
+
encryption,
|
|
167
|
+
);
|
|
168
|
+
!isScreenActive && setScreenshareActive(true);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
console.error("can't start the screen share", e);
|
|
171
|
+
setNormalQuery({variables: {passphrase: phrase}})
|
|
172
|
+
.then((res) => {
|
|
173
|
+
console.log(res.data);
|
|
174
|
+
if (res.data.stopRecordingSession === 'success') {
|
|
175
|
+
// Once the backend sucessfuly stops recording,
|
|
176
|
+
// send a control message to everbody in the channel indicating that cloud recording is now inactive.
|
|
177
|
+
// sendControlMessage(controlMessageEnum.cloudRecordingUnactive);
|
|
178
|
+
// set the local recording state to false to update the UI
|
|
179
|
+
// setScreenshareActive(false);
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
.catch((err) => {
|
|
183
|
+
console.log(err);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<ScreenshareContext.Provider
|
|
190
|
+
value={{
|
|
191
|
+
screenshareActive,
|
|
192
|
+
startUserScreenshare,
|
|
193
|
+
stopUserScreenShare,
|
|
194
|
+
}}>
|
|
195
|
+
{props.children}
|
|
196
|
+
</ScreenshareContext.Provider>
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export default ScreenshareConfigure;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
********************************************
|
|
3
|
+
Copyright © 2021 Agora Lab, Inc., all rights reserved.
|
|
4
|
+
AppBuilder and all associated components, source code, APIs, services, and documentation
|
|
5
|
+
(the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
|
|
6
|
+
accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
|
|
7
|
+
Use without a license or in violation of any license terms and conditions (including use for
|
|
8
|
+
any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
|
|
9
|
+
information visit https://appbuilder.agora.io.
|
|
10
|
+
*********************************************
|
|
11
|
+
*/
|
|
12
|
+
import {createContext} from 'react';
|
|
13
|
+
|
|
14
|
+
interface ScreenshareContext {
|
|
15
|
+
screenshareActive: boolean;
|
|
16
|
+
startUserScreenshare: () => void;
|
|
17
|
+
stopUserScreenShare: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const ScreenshareContext = createContext(null as unknown as ScreenshareContext);
|
|
21
|
+
export default ScreenshareContext;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
type Entry<T> = {
|
|
2
|
+
[K in keyof T]: [K, T[K]];
|
|
3
|
+
}[keyof T];
|
|
4
|
+
|
|
5
|
+
export function filterObject<T extends object>(
|
|
6
|
+
obj: T,
|
|
7
|
+
fn: (entry: Entry<T>, i: number, arr: Entry<T>[]) => boolean,
|
|
8
|
+
) {
|
|
9
|
+
return Object.fromEntries(
|
|
10
|
+
(Object.entries(obj) as Entry<T>[]).filter(fn),
|
|
11
|
+
) as Partial<T>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function kFormatter(num: number) {
|
|
15
|
+
return Math.abs(num) > 999
|
|
16
|
+
? Math.sign(num) * (Math.round(Math.abs(num) / 100) / 10) + 'k'
|
|
17
|
+
: Math.sign(num) * Math.abs(num);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function numFormatter(num: number) {
|
|
21
|
+
if (num === null || num === 0) {
|
|
22
|
+
return '0';
|
|
23
|
+
}
|
|
24
|
+
const value = Math.abs(num);
|
|
25
|
+
const sign = Math.sign(num);
|
|
26
|
+
let newValue = value;
|
|
27
|
+
if (value >= 1000) {
|
|
28
|
+
var suffixes = ['', 'k', 'm', 'b', 't', 't+'];
|
|
29
|
+
var suffixNum = Math.floor(('' + value).length / 3);
|
|
30
|
+
var shortValue = '';
|
|
31
|
+
for (var precision = 2; precision >= 1; precision--) {
|
|
32
|
+
shortValue = parseFloat(
|
|
33
|
+
(suffixNum != 0
|
|
34
|
+
? value / Math.pow(1000, suffixNum)
|
|
35
|
+
: value
|
|
36
|
+
).toPrecision(precision),
|
|
37
|
+
);
|
|
38
|
+
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g, '');
|
|
39
|
+
if (dotLessShortValue.length <= 2) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (shortValue % 1 != 0) shortValue = shortValue.toFixed(1);
|
|
44
|
+
newValue = shortValue + suffixes[suffixNum];
|
|
45
|
+
}
|
|
46
|
+
newValue = sign === -1 ? `-${newValue}` : `${newValue}`;
|
|
47
|
+
return newValue;
|
|
48
|
+
}
|