diff --git a/README-EN.md b/README-EN.md index 354f1d0..815441b 100644 --- a/README-EN.md +++ b/README-EN.md @@ -70,6 +70,16 @@ window.scratchConfig = { enable: true, // enable backpack api: "/api/teaching/scratch/backpack", //backpack API }, + cloudData:{ + enable: true, //enable cloud data + id: "create", //default cloud data ID + api: "127.0.0.1:1234/api/websocket/scratch/cloudData" //cloud data API + }, + projectInfo: {//project info + projectName: "", + authorUsername: "admin", + authorAvatar: './static/avatar.png', + }, logo: { show: true, //is visible url: "./static/logo.png", //logo url, support base64 images @@ -349,6 +359,9 @@ window.scratch.pushSoundLibrary( ) ``` +#### set cloud data ID +`window.scratch.setCloudId(id)` + # Appendix ## block catagory code diff --git a/README.md b/README.md index e87d7d3..0fbcb68 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,16 @@ https://www.213.name/archives/1739 enable: true, // 是否启用背包 api: "/api/teaching/scratch/backpack", //背包API接口 }, + cloudData:{ + enable: true, //是否开启云变量功能 + id: "create", //默认云变量ID,可使用window.scratch.setCloudId更换ID + api: "127.0.0.1:1234/api/websocket/scratch/cloudData" //云变量API地址 + }, + projectInfo: {//作品信息 + projectName: "", + authorUsername: "admin", + authorAvatar: './static/avatar.png', + }, logo: { show: true, //是否显示 url: "./static/logo.png", //logo地址,支持base64图片 @@ -367,6 +377,9 @@ window.scratch.pushSoundsLibrary( ) ``` +#### 设置云变量ID +`window.scratch.setCloudId(id)` + # 附录 ## Scratch项目结构 diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index 43dfac4..7e420a8 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -74,7 +74,6 @@ const GUIComponent = props => { canSave, canCreateCopy, canShare, - canUseCloud, children, connectionModalVisible, costumeLibraryVisible, @@ -300,7 +299,6 @@ const GUIComponent = props => { { loginMenuOpen: loginMenuOpen(state), projectTitle: state.scratchGui.projectTitle, sessionExists: state.session && typeof state.session.session !== 'undefined', - username: window.scratchConfig.menuBar.userAvatar.username || '', - avatar: window.scratchConfig.menuBar.userAvatar.avatar || null, + username: window.scratchConfig.session.username || '', + avatar: window.scratchConfig.session.avatar || null, onAvatarClick: window.scratchConfig.menuBar.userAvatar.handleClick, userOwnsProject: ownProps.authorUsername && user && (ownProps.authorUsername === user.username), diff --git a/src/components/prompt/prompt.jsx b/src/components/prompt/prompt.jsx index d60af1f..513bece 100644 --- a/src/components/prompt/prompt.jsx +++ b/src/components/prompt/prompt.jsx @@ -38,6 +38,7 @@ const PromptComponent = props => ( className={styles.modalContent} contentLabel={props.title} onRequestClose={props.onCancel} + id={"cloudData"} > diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx index fee9d26..afd3c60 100644 --- a/src/containers/blocks.jsx +++ b/src/containers/blocks.jsx @@ -465,7 +465,7 @@ class Blocks extends React.Component { optVarType !== this.ScratchBlocks.BROADCAST_MESSAGE_VARIABLE_TYPE && p.prompt.title !== this.ScratchBlocks.Msg.RENAME_VARIABLE_MODAL_TITLE && p.prompt.title !== this.ScratchBlocks.Msg.RENAME_LIST_MODAL_TITLE; - p.prompt.showCloudOption = (optVarType === this.ScratchBlocks.SCALAR_VARIABLE_TYPE) && this.props.canUseCloud; + p.prompt.showCloudOption = (optVarType === this.ScratchBlocks.SCALAR_VARIABLE_TYPE) && window.scratchConfig.cloudData.enable; this.setState(p); } handleConnectionModalStart (extensionId) { @@ -512,7 +512,6 @@ class Blocks extends React.Component { /* eslint-disable no-unused-vars */ const { anyModalVisible, - canUseCloud, customProceduresVisible, extensionLibraryVisible, options, @@ -575,7 +574,6 @@ class Blocks extends React.Component { Blocks.propTypes = { anyModalVisible: PropTypes.bool, - canUseCloud: PropTypes.bool, customProceduresVisible: PropTypes.bool, extensionLibraryVisible: PropTypes.bool, isRtl: PropTypes.bool, diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx index fa64cc9..bc23f75 100644 --- a/src/containers/gui.jsx +++ b/src/containers/gui.jsx @@ -164,6 +164,7 @@ class GUI extends React.Component { /* eslint-disable no-unused-vars */ assetHost, cloudHost, + cloudId, error, isError, isScratchDesktop, @@ -196,6 +197,7 @@ GUI.propTypes = { assetHost: PropTypes.string, children: PropTypes.node, cloudHost: PropTypes.string, + cloudId: PropTypes.string, error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), fetchingProject: PropTypes.bool, intl: intlShape, diff --git a/src/lib/alerts/index.jsx b/src/lib/alerts/index.jsx index dbd4f2c..c447b9c 100644 --- a/src/lib/alerts/index.jsx +++ b/src/lib/alerts/index.jsx @@ -179,19 +179,20 @@ const alerts = [ description="Info about cloud variable limitations" id="gui.alerts.cloudInfo" values={{ - learnMoreLink: ( - - - - ) + learnMoreLink: "" + // ( + // + // + // + // ) }} /> ), diff --git a/src/lib/cloud-manager-hoc.jsx b/src/lib/cloud-manager-hoc.jsx index 01ca252..11df513 100644 --- a/src/lib/cloud-manager-hoc.jsx +++ b/src/lib/cloud-manager-hoc.jsx @@ -28,6 +28,55 @@ const cloudManagerHOC = function (WrappedComponent) { 'handleCloudDataUpdate' ]); + this.enable = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.enable || false + this.token = window.scratchConfig && window.scratchConfig.session && window.scratchConfig.session.token, + this.username = window.scratchConfig && window.scratchConfig.session && window.scratchConfig.session.username || ''; + this.authorUsername = window.scratchConfig && window.scratchConfig.projectInfo && window.scratchConfig.projectInfo.authorUsername, + this.cloudId = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.id + this.cloudHost = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.api + + + //动态设置是否开启云变量 + let that = this + document.addEventListener("setEnableCouldData",function(e){ + that.enable = e.detail.enable; + window.scratchConfig.cloudData.enable = e.detail.enable; + that.handleCloudDataUpdate(that.enable) + }) + + window.scratch.setEnableCouldData = function(enable){ + var event = new CustomEvent('setEnableCouldData', {"detail": {enable: enable}}); + document.dispatchEvent(event); + } + + //动态设置cloudId + document.addEventListener("setCloudId",function(e){ + if(that.cloudId != e.detail.id){ + window.scratchConfig.cloudData.id = e.detail.id; + that.cloudId = e.detail.id; + that.handleCloudDataUpdate(that.enable) + } + }) + + window.scratch.setCloudId = function(id){ + var event = new CustomEvent('setCloudId', {"detail": {id: id}}); + document.dispatchEvent(event); + } + + //设置authorUsername + document.addEventListener("setAuthorUsername",function(e){ + if(that.authorUsername != e.detail.authorUsername){ + window.scratchConfig.projectInfo.authorUsername = e.detail.authorUsername; + that.authorUsername = e.detail.authorUsername; + that.handleCloudDataUpdate(that.enable) + } + }) + + window.scratch.setAuthorUsername = function(authorUsername){ + var event = new CustomEvent('setAuthorUsername', {"detail": {authorUsername: authorUsername}}); + document.dispatchEvent(event); + } + this.props.vm.on('HAS_CLOUD_DATA_UPDATE', this.handleCloudDataUpdate); } componentDidMount () { @@ -52,14 +101,25 @@ const cloudManagerHOC = function (WrappedComponent) { this.disconnectFromCloud(); } canUseCloud (props) { - return !!(props.cloudHost && props.username && props.vm && props.projectId && props.hasCloudPermission); + // return !!(props.cloudHost && props.username && props.vm && props.projectId && props.hasCloudPermission); + // console.log(props.vm); + // console.log(props.projectId); + // console.log(props.hasCloudPermission); + return this.enable; } - shouldConnect (props) { - return !this.isConnected() && this.canUseCloud(props) && - props.isShowingWithId && props.vm.runtime.hasCloudData() && - props.canModifyCloudData; + shouldConnect (props) { + console.log("should connnet"); + console.log(this.enable); + console.log(props.vm.runtime.hasCloudData()); + // return !this.isConnected() && this.canUseCloud(props) && + // props.isShowingWithId && props.vm.runtime.hasCloudData() && + // props.canModifyCloudData; + //如果开启了云变量,且项目包含云变量 + return this.enable && props.vm.runtime.hasCloudData(); } shouldDisconnect (props, prevProps) { + //如果关闭了云变量,且项目不包含云变量 + return !this.canUseCloud(props)||!props.vm.runtime.hasCloudData(); return this.isConnected() && ( // Can no longer use cloud or cloud provider info is now stale !this.canUseCloud(props) || @@ -75,10 +135,11 @@ const cloudManagerHOC = function (WrappedComponent) { } connectToCloud () { this.cloudProvider = new CloudProvider( - this.props.cloudHost, + this.cloudHost, this.props.vm, - this.props.username, - this.props.projectId); + this.authorUsername, + this.token, + this.cloudId); this.props.vm.setCloudProvider(this.cloudProvider); } disconnectFromCloud () { @@ -100,9 +161,8 @@ const cloudManagerHOC = function (WrappedComponent) { const { /* eslint-disable no-unused-vars */ canModifyCloudData, - cloudHost, projectId, - username, + // username, hasCloudPermission, isShowingWithId, onShowCloudInfo, @@ -112,7 +172,6 @@ const cloudManagerHOC = function (WrappedComponent) { } = this.props; return ( @@ -122,20 +181,16 @@ const cloudManagerHOC = function (WrappedComponent) { CloudManager.propTypes = { canModifyCloudData: PropTypes.bool.isRequired, - cloudHost: PropTypes.string, hasCloudPermission: PropTypes.bool, isShowingWithId: PropTypes.bool.isRequired, onShowCloudInfo: PropTypes.func, projectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - username: PropTypes.string, vm: PropTypes.instanceOf(VM).isRequired }; CloudManager.defaultProps = { - cloudHost: null, hasCloudPermission: false, onShowCloudInfo: () => {}, - username: null }; const mapStateToProps = (state, ownProps) => { @@ -144,7 +199,7 @@ const cloudManagerHOC = function (WrappedComponent) { isShowingWithId: getIsShowingWithId(loadingState), projectId: state.scratchGui.projectState.projectId, // if you're editing someone else's project, you can't modify cloud data - canModifyCloudData: (!state.scratchGui.mode.hasEverEnteredEditor || ownProps.canSave) + canModifyCloudData: (!state.scratchGui.mode.hasEverEnteredEditor || ownProps.canSave), }; }; diff --git a/src/lib/cloud-provider.js b/src/lib/cloud-provider.js index ce26082..f60fb69 100644 --- a/src/lib/cloud-provider.js +++ b/src/lib/cloud-provider.js @@ -13,9 +13,10 @@ class CloudProvider { * @param {string} projectId The id associated with the project containing * cloud data. */ - constructor (cloudHost, vm, username, projectId) { + constructor (cloudHost, vm, username, token, projectId) { this.vm = vm; this.username = username; + this.token = token; this.projectId = projectId; this.cloudHost = cloudHost; @@ -113,6 +114,10 @@ class CloudProvider { value: message.value }; break; + } + //初始化云变量 + case 'init': { + } } return varData; @@ -130,6 +135,7 @@ class CloudProvider { msg.method = methodName; msg.user = this.username; msg.project_id = this.projectId; + msg.token = this.token // Optional string params can use simple falsey undefined check if (dataName) msg.name = dataName; @@ -221,6 +227,7 @@ class CloudProvider { this.connection = null; this.vm = null; this.username = null; + this.token = null; this.projectId = null; if (this._connectionTimeout) { clearTimeout(this._connectionTimeout); diff --git a/src/playground/index.ejs b/src/playground/index.ejs index 0cd8225..1b29134 100644 --- a/src/playground/index.ejs +++ b/src/playground/index.ejs @@ -25,6 +25,16 @@ enable: true, // 是否启用背包 api: "/api/teaching/scratch/backpack", //背包API接口 }, + cloudData:{ + enable: true, //是否开启云变量功能 + id: "create", //默认云变量ID,可使用window.scratch.setCloudId更换ID + api: "127.0.0.1:1234/api/websocket/scratch/cloudData" //云变量API地址 + }, + projectInfo: {//作品信息 + projectName: "", + authorUsername: "admin", + authorAvatar: './static/avatar.png', + }, logo: { show: true, //是否显示 url: window.location.protocol+"//"+window.location.host + "/static/logo.png", //logo地址,支持base64图片 @@ -194,6 +204,21 @@ }, } + //api + /** + * window.scratch.loadPorject(url, callback) + * window.scratch.getProjectFile(callback(file)) + * window.scratch.getProjectCover(callback(file)) + * window.scratch.getProjectName() + * window.scratch.setProjectName(projectName) + * window.scratch.setPlayerOnly(isPlayerOnly) + * window.scratch.setFullScreen(isFullScreen) + * + * window.scratch.setEnableCouldData(isEnable) //设置是否开启云变量(会开启或关闭当前连接) + * window.scratch.setCloudId(id) //设置云变量ID(会触发一次重连) + * window.scratch.setAuthorUsername(authorUsername) //设置作者用户名 + * window.vm.runtime.hasCloudData() //是否包含云变量 + */ diff --git a/src/playground/render-gui.jsx b/src/playground/render-gui.jsx index 28e50fe..2b57719 100644 --- a/src/playground/render-gui.jsx +++ b/src/playground/render-gui.jsx @@ -23,6 +23,10 @@ const handleTelemetryModalOptOut = () => { log('User opted out of telemetry'); }; +const onVmInit = (vm) =>{ + console.log("scratch vm init"); + console.log(vm); +} /* * Render the GUI playground. This is a separate function because importing anything * that instantiates the VM causes unsupported browsers to crash @@ -46,6 +50,8 @@ export default appTarget => { const backpackShow = window.scratchConfig.session && window.scratchConfig.session.token && window.scratchConfig && window.scratchConfig.backpack && window.scratchConfig.backpack.enable || false + const cloudHost = window.scratchConfig && window.scratchConfig.cloudData && window.scratchConfig.cloudData.api + const scratchDesktopMatches = window.location.href.match(/[?&]isScratchDesktop=([^&]+)/); let simulateScratchDesktop; @@ -82,7 +88,11 @@ export default appTarget => { backpackVisible={backpackShow} // showComingSoon backpackApi={backpackApi} + // canUseCloud={canUseCloud} + hasCloudPermission={true} + canSave={false} + onVmInit={onVmInit} onClickLogo={onClickLogo} />, appTarget);