From d8b1f5b47d593086749b8daf7eb7b6237ecb4fd1 Mon Sep 17 00:00:00 2001 From: ocogeclub Date: Thu, 21 Jan 2021 21:46:24 +0900 Subject: [PATCH] update: index.html separated css and js from index.html --- index.css | 396 ++++++++++++++++++ index.html | 950 +----------------------------------------- scripts/ugj_script.js | 543 ++++++++++++++++++++++++ 3 files changed, 942 insertions(+), 947 deletions(-) create mode 100644 index.css create mode 100644 scripts/ugj_script.js diff --git a/index.css b/index.css new file mode 100644 index 0000000..2b4883d --- /dev/null +++ b/index.css @@ -0,0 +1,396 @@ +@font-face { + font-family: "Source Code Pro JP"; + src: url("./fonts/SourceHanCodeJP.otf"); +} + +@font-face { + font-family: "Pakchee R"; + src: url("./fonts/Pakchee-R.otf"); +} + +#conmenu { + width: 130px; + background-color: white; + border: 1px solid #999999; + display: none; + position: fixed; + font-size: small; + padding-top: 4px; + padding-bottom: 4px; +} + +#conmenu.on { + display: block; +} + +#conmenu ul { + list-style: none; + margin: 0px; + padding: 0px; +} + +#conmenu li { + padding-left: 4px; + transition: 0.2s linear; +} + +a.conCopy { + text-decoration: none; + display: block; + color: black; + transition: 0.2s linear; +} + +#conmenu ul :hover { + background-color: gainsboro; +} + +#codeDlg { + border-color: lightskyblue; + border-width: 1px; +} + +#dlgTitle { + font-weight: bolder; + color: steelblue; +} + +#dlgContent { + padding: 8px; + border-radius: 8px; + font-family: "Source Code Pro JP"; + font-size: smaller; + max-width: 1024px; + max-height: 768px; + overflow: auto; +} + +.dlgCli { + font-size: smaller; +} + +.prettyprint ol { + padding-left: 36px; +} + +.prettyprint ol.linenums>li { + list-style-type: decimal; + /* 1行ごとに行番号を表示 */ + border-left: solid 1px #ebb15e; + /* 区切り線を表示 */ + padding-left: 0.5rem; + /* 間隔の調整(必要であれば) */ +} + +#inputForm { + display: none; +} + +.inputDiv { + position: relative; + display: inline-block; +} + +#inputBox { + width: 454px; + font-size: 1em; + color: #666; + height: 26px; + padding-left: 10px; + padding-right: 28px; + padding-top: 0px; + border-radius: 20px; + border: solid; + border-width: 1px; + border-color: #ccf; + outline: none; + transition: 0.3s linear; +} + +#inputBox:hover { + border-color: #88f; +} + +#inputBox:focus { + border-color: #88f; + box-shadow: 0px 0px 4px 1px #ccc; +} + +.inputBtn { + position: absolute; + right: 1px; + top: 0px; + color: #99f; + font-weight: 400; + font-size: 1.4em; + padding: 0px; + border: none; + outline: none; + background-color: transparent; + border-radius: 16px; + height: 28px; + width: 28px; + cursor: pointer; +} + +.inputBtn:hover { + font-weight: 900; +} + +.display { + top: 6px; + border-radius: 6px; + position: absolute; +} + +#maindisplay { + display: none; +} + +#subdisplay { + display: none; +} + +.subdisplay { + width: 160px; + height: 120px; + position: absolute; + right: 12px; + bottom: 12px; + border-radius: 4px; + border: solid 4px white; +} + +#canvas_bg { + background-color: white; +} + +#canvas { + position: absolute; + top: 6; + left: 6; +} + +.game_fg { + background-color: rgba(255, 255, 255, 0.6); +} + +#gcanvas { + background-color: rgba(255, 255, 255, 0.6); + display: none; +} + +#display_area { + position: relative; + left: 0px; + width: 480px; + height: 360px; + padding: 6px; + background-color: #eef; + border-radius: 8px; + margin-top: 2px; + margin-bottom: 8px; +} + +.rightPane { + position: absolute; + right: 8px; + top: 48px; + width: 500px; +} + +#blackboard { + display: none; + width: 480px; + height: 396px; + background-color: #333; + color: #ddd; + font-family: "Source Code Pro JP"; + font-size: 0.9em; + padding-left: 8px; + padding-top: 4px; + border: 3px double #eee; + overflow: auto; + border-radius: 8px; + margin-top: 0px; + margin-bottom: 0px; +} + +html, +body { + height: 100%; + margin: 0; +} + +body { + background-color: #fff; + overflow: hidden; +} + +#blocklyArea { + height: 99%; +} + +/* ツールボックス関連 */ +/* スクロールバー非表示(撮影用) */ +div#blocklyDiv .blocklyToolboxDiv::-webkit-scrollbar { + display: none; +} + +/* ツールボックスの行の高さ・ホバー時の変化速度 */ +.blocklyTreeRow { + /* height: 36px !important; */ + transition-property: all; + transition: 0.2s linear; +} + +/* ホバー時に影をつける */ +.blocklyTreeRow:hover { + box-shadow: 1px 1px 4px steelblue; +} + +/* ツールボックスフォント */ +/* .blocklyTreeLabel { + font-family: "Noto Sans CJK JP Light", sans-serif; +} */ +/* Adds padding around the group of categories and separators. */ +.blocklyToolboxContents { + padding: .5em; +} + +/* Adds space between the categories, rounds the corners and adds space around the label. */ +.blocklyTreeRow { + padding: 3px; + margin-bottom: .5em; + border-radius: 4px; +} + +/* Changes color of the icon to white. */ +.customIcon { + color: white; + padding-top: 4px; +} + +/* Stacks the icon on top of the label. */ +.blocklyTreeRowContentContainer { + display: flex; + flex-direction: column; + align-items: center; +} + +.blocklyTreeRow { + height: initial; +} + +/* Override Flyout BGColor */ +/* .blocklyFlyoutBackground { +fill: lavender; +} */ +/* Override Flyout TextColor */ +/* .blocklyFlyoutLabelText { +fill: steelblue !important; +} */ + +/* ツールバー */ +div.toolbar { + height: 42px; + position: relative; + background-color: #4d97ff; +} + +div.toolbar-left { + margin-left: 8px; + margin-top: -4px; + display: inline-block; + color: white; +} + +.appTitle { + font-family: "Pakchee R"; + font-weight: normal; + font-size: x-large; + padding-left: 10px; + letter-spacing: 12px; +} + +.o { + color: pink; +} + +.co { + color: aliceblue; +} + +.ge { + color: lemonchiffon; +} + +.ga { + color: palegreen; +} + +.homelink { + text-decoration: none; +} + +.iconbutton { + color: white; + border: none; + background-color: transparent; + padding: 4px; + transition-property: all; + transition: 0.2s linear; + font-size: large; + outline: none; + text-decoration: none; +} + +.iconbutton:active { + transform: translate(1px, 2px); +} + +.redo { + vertical-align: middle; + margin-top: 1px; +} + +div.toolbar-right { + position: absolute; + right: 2px; + margin-top: 5px; + display: inline-block; + /* text-align: right; */ + width: 500px; +} + +/* ツールバーボタン */ +.toolbarButton { + background-color: white; + border: none; + color: #4d97ff; + font-size: 12px; + border-radius: 4px; + transition-property: all; + transition: 0.2s linear; + width: 72px; + height: 30px; + outline: none; +} + +.toolbarButton:hover { + background-color: #9fecff; + color: white; +} + +.toolbarButton:active { + transform: translate(1px, 2px); +} + +.ocgButton { + margin-right: 4px; + margin-bottom: 6px; +} + +.ocgButton:hover { + box-shadow: 1px 1px 6px gray; +} diff --git a/index.html b/index.html index 3b6aa4c..6213bf0 100644 --- a/index.html +++ b/index.html @@ -8,406 +8,9 @@ - @@ -1314,557 +917,10 @@ + - \ No newline at end of file diff --git a/scripts/ugj_script.js b/scripts/ugj_script.js new file mode 100644 index 0000000..cd158f9 --- /dev/null +++ b/scripts/ugj_script.js @@ -0,0 +1,543 @@ +const testfunc = () => { + elec.openURL('http://ocoge.club'); +} + +//============ User Customize Start =============== +// テーマ +// カスタムブロックカラー定義 +Blockly.HSV_SATURATION = 0.55; +Blockly.HSV_VALUE = 0.75; +var gpio_color = '0'; +var multimedia_color = '240'; +var network_color = '340'; +var special_color = '20'; +var snippets_color = '90'; + +// Blockly.Msg.UGJ_GPIO_HUE = 0;//FF7799 +// Blockly.Msg.UGJ_MULTIMEDIA_HUE = 240;//CF63CF +// Blockly.Msg.UGJ_NETWORK_HUE = 340;//"#54C4EA" +// Blockly.Msg.UGJ_SPECIAL_HUE = 20;//"#0FBD8C" +// Blockly.Msg.UGJ_SNIPPETS_HUE = 90; + +var theme = Blockly.Theme.defineTheme('ocoge', { + 'base': Blockly.Themes.Classic, + 'startHats': true, + 'componentStyles': { + 'toolboxBackgroundColour': 'aliceblue', + 'flyoutBackgroundColour': 'lavender', + 'toolboxForegroundColour': 'white', + 'flyoutForegroundColour': 'steelblue' + }, + 'blockStyles': { + 'gpio_blocks': { + "colourPrimary": gpio_color + }, + 'multimedia_blocks': { + "colourPrimary": multimedia_color + }, + 'network_blocks': { + "colourPrimary": network_color + }, + 'special_blocks': { + "colourPrimary": special_color + }, + 'snippets_blocks': { + "colourPrimary": snippets_color + } + }, + 'categoryStyles': { + "gpio_category": { + "colour": gpio_color + }, + "multimedia_category": { + "colour": multimedia_color + }, + "network_category": { + "colour": network_color + }, + "special_category": { + "colour": special_color + }, + "snippets_category": { + "colour": snippets_color + } + }, +}); + +// Customize messages +Blockly.Msg["CONTROLS_IF_MSG_THEN"] = "ならば"; +Blockly.Msg["CONTROLS_REPEAT_INPUT_DO"] = ""; +Blockly.Msg["MATH_CHANGE_TITLE"] = "変数 %1 を %2 増やす"; +Blockly.Msg["VARIABLES_SET"] = "変数 %1 を %2 にする"; +Blockly.Msg["TEXT_PRINT_TITLE"] = "ダイアログに %1 を表示"; + +// Customize Toolbox +class CustomCategory extends Blockly.ToolboxCategory { + /** Constructor for a custom category. @override */ + constructor(categoryDef, toolbox, opt_parent) { + super(categoryDef, toolbox, opt_parent); + } + /** @override */ + addColourBorder_(colour) { + this.rowDiv_.style.backgroundColor = colour; + } + /** @override */ + setSelected(isSelected) { + // We do not store the label span on the category, so use getElementsByClassName. + var labelDom = this.rowDiv_.getElementsByClassName('blocklyTreeLabel')[0]; + if (isSelected) { + // Change the background color of the div to white. + this.rowDiv_.style.backgroundColor = 'white'; + // Set the colour of the text to the colour of the category. + labelDom.style.color = this.colour_; + this.iconDom_.style.color = this.colour_; + } else { + // Set the background back to the original colour. + this.rowDiv_.style.backgroundColor = this.colour_; + // Set the text back to white. + labelDom.style.color = 'white'; + this.iconDom_.style.color = 'white'; + } + // This is used for accessibility purposes. + Blockly.utils.aria.setState(/** @type {!Element} */(this.htmlDiv_), + Blockly.utils.aria.State.SELECTED, isSelected); + } +} +Blockly.registry.register( + Blockly.registry.Type.TOOLBOX_ITEM, + Blockly.ToolboxCategory.registrationName, + CustomCategory, true); +//============ User Customize End =============== + + +//canvasの準備 +const ugj_canvasBgImg = imgSrc => { + let el = document.getElementById('canvas_bg'); + let ctx = el.getContext('2d'); + let img = new Image(); + img.src = imgSrc; + // img.onload = () => ctx.drawImage(img, 140, 80); // ミミィ + img.onload = () => ctx.drawImage(img, 140, 0); // こげちー +}; +// マスコット +// ugj_canvasBgImg("./img/mimmy.png?" + new Date().getTime()); // ミミィ +ugj_canvasBgImg("./img/cogechee.png?" + new Date().getTime()); // こげちー + +// HTML部品のインスタンス - 画面上の必要な部品はすべてここで取得しておく +ugjel_displayArea = document.getElementById('display_area'); // ディスプレイ部 +ugjel_blackboard = document.getElementById('blackboard'); // 黒板 +ugjel_inputForm = document.getElementById('inputForm'); // 入力フォーム +ugjel_inputBox = document.getElementById('inputBox'); // 入力フィールド + +// その他のプロパティ +ugj_inputEvLstnrID = 0; // 入力フォームの動的イベントリスナの最新のID +ugj_sounds = (names => { // サウンドファイルのいろいろの配列の初期化 + let sounds = []; + names.forEach(value => { + let filepath = `./sounds/${value}.wav`; + sounds[value] = { 'file': filepath, 'audio': new Audio(filepath) }; + }); + return sounds; +})(['meow', 'bounce', 'type_chime', 'type_dink', 'type_tap', 'type_space', 'type_return']); // サウンドファイルのベース名のリスト + +// メソッド + +// サウンド再生 - 連続再生のため、再生開始後すぐにオーディオ要素を再生成する +const ugj_soundPlay = soundName => { + ugj_sounds[soundName]['audio'].play(); + ugj_sounds[soundName]['audio'] = new Audio(ugj_sounds[soundName]['file']); +}; + +// OK,Cancel 2択のダイアログを表示 +const ugj_confirm = (title, message, callback) => { + CustomDialog.show(title, message, { + showOkay: true, + onOkay: () => callback(true), + showCancel: true, + onCancel: () => callback(false) + }); +}; + +const ugj_htmlEntities = str =>// HTMLエンティティのエスケープ + String(str).replace(//g, '>').replace(/"/g, '"');//.replace(/&/g, '&').replace(/ /g, ' '); + +// 新規ワークスペース +const ugj_newWorkspace = () => { + ugj_confirm('新規ワークスペース', '保存していない内容はすべて破棄されます。よろしいですか?', okey => { + if (okey) { + workspace.clear(); + elec.newFile(); + } + }); +} + +// ワークスペースをファイルに保存・読込 +const ugj_saveWorkspaceToFile = () => { + let xml = Blockly.Xml.workspaceToDom(workspace); + let xml_text = Blockly.Xml.domToText(xml); + if (elec.saveWsFile(xml_text) === false) { + alert('保存できませんでした。'); + } +} +const ugj_loadWorkspaceFromFile = () => { + let xml_text = elec.loadWsFile(); + if (xml_text.length > 0) { + let xml = Blockly.Xml.textToDom(xml_text); + Blockly.Xml.domToWorkspace(xml, workspace); + } +} + +// ワークスペースを別名で保存 +const ugj_saveWorkspaceAs = () => { + elec.newFile(); + ugj_saveWorkspaceToFile(); +} + +// ワークスペースをローカルストレージに保存・読込 +const ugj_saveWorkspace = () => { + // Workspace + let xml = Blockly.Xml.workspaceToDom(workspace); + let xml_text = Blockly.Xml.domToText(xml); + localStorage.setItem("abrage.xml", xml_text); +} +const ugj_loadWorkspace = () => { + // Workspace + let xml_text = localStorage.getItem("abrage.xml"); + if (xml_text.length != 0) { + let xml = Blockly.Xml.textToDom(xml_text); + Blockly.Xml.domToWorkspace(xml, workspace); + } +} + +// ワークスペースからコードを生成して必要であれば整形処理をする +const ugj_createCode = (args) => { + addAsync = args.async || false; + beautify = args.beautify || false; + + let code = Blockly.JavaScript.workspaceToCode(workspace); + + // 追加モジュールのrequire + let requires = [ + ['_gpio_', false, `const pi = require('ocoge_pigpiod');\n`], + ['_axios_', false, `const axios = require('axios');\n`], + ['_sendmail', false, `const nodemailer = require('nodemailer');\n`], + ['_cloudspeech_', false, `const speech = require('@google-cloud/speech');\nconst recorder = require('node-record-lpcm16');\n`], + ['_httpserver', false, `const http = require('http');\n`], + ['_file_', false, `const fs = require('fs');\n`], + // ['_bme280', false, `const BME280 = require('bme280-sensor');`], + ['_dht', false, `const dht = require("node-dht-sensor").promises;`], + ['_socket_', false, `const net = require('net');`] + ]; + let blockArray = workspace.getAllBlocks(); + blockArray.forEach(value => { + for (var i = 0, l = requires.length; i < l; i++) { + if (value.type.indexOf(requires[i][0]) >= 0) requires[i][1] = true; + } + }); + for (var i = 0, l = requires.length; i < l; i++) { + if (requires[i][1]) code = requires[i][2] + code; + } + + // await使用のため、必要に応じてコード全体をasync付き即時関数でラップ + if (addAsync) { + code = [ + '(async () => {', + code, + '})();' + ].join('\n'); + } + + // コードを綺麗に + if (beautify) code = js_beautify(code, { indent_size: 2 }); + + return code; +} + +// ブロックスクリプト実行 +const ugj_runCode = () => { + document.activeElement.blur(); //実行ボタンからフォーカスを外す:エンターキー押下が悪さをするため + let code = ugj_createCode({ 'async': true }); + try { + eval(code); + } catch (e) { + alert(e); + } +} + +// JavaScriptコードをダイアログで表示・保存 +// エレメントのオブジェクトとかコールバックとか +// 色々この中で完結させてみる +const ugj_showCode = () => { + const dialog = document.getElementById('codeDlg'); + const content = document.getElementById('dlgContent'); + const btn_close = document.getElementById('dlgClose'); + const btn_export = document.getElementById('dlgExport'); + const chkbox_cli = document.getElementById('dlgCli'); + + let code = ugj_createCode({ 'beautify': true }); + code = ugj_htmlEntities(code); + content.innerHTML = PR.prettyPrintOne(code, 'js', true); + + dialog.showModal(); + + const close_cb = () => { + dialog.close(); + btn_close.removeEventListener('click', close_cb); + btn_export.removeEventListener('click', export_cb); + } + const export_cb = () => { + code = ugj_createCode({ 'async': true, 'beautify': true }); + // blackboardWrite()をconsole.log()に書き換え、 + // document... と ugj_... と elec... をコメントアウト(ブラウザ関連部分の追放という意味では不完全なので注意) + if (chkbox_cli.checked) + code = code.replace(/const appendDiv[^#]*\/\/#/gm, 'const blackboardWrite = text => console.log(text);').replace(/(^(?=.*document.)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*ugj_)[^;]*;)/gm, '/* $1 */').replace(/(^(?=.*elec.)[^;]*;)/gm, '/* $1 */'); + if (elec.saveFile(code, 'js') === false) { + alert('保存できませんでした。'); + } + close_cb(); + } + btn_close.addEventListener('click', close_cb); + btn_export.addEventListener('click', export_cb); +} + + +// フキダシ +ugj_fdTimeoutID = null; +ugj_fdRecentBox = null; +const ugj_fukidashi = (text, sec) => { + // Canvas Context + const context = document.getElementById('canvas').getContext('2d'); + // 吹き出しを消去する関数 + const clearFd = (x, y, w, h) => context.clearRect(x, y, w, h); + // 前回の思い出を忘れる + if (ugj_fdRecentBox !== null) { + clearFd(ugj_fdRecentBox.x, ugj_fdRecentBox.y, ugj_fdRecentBox.w, ugj_fdRecentBox.h); + clearTimeout(ugj_fdTimeoutID); + ugj_fdRecentBox = null; + } + + // 基本設定 + let rtopX = 170; // フキダシ右上 X座標 + let rtopY = 40; // フキダシ右上 Y座標 + let boxWidth = 140; + let padding = 5; + let radius = 5;// 円弧の半径 + + // 吹き出しの背景色 + context.fillStyle = "#b7e6ff"; + + // テキスト設定 + let limitedWidth = boxWidth - (padding * 2); + let size = 14; + context.font = size + "px ''"; + + // テキスト調整 行に分解 + let lineTextList = text.split("\n"); + let newLineTextList = []; + lineTextList.forEach((lineText) => { + if (context.measureText(lineText).width > limitedWidth) { + characterList = lineText.split("");// 1文字ずつ分割 + let preLineText = ""; + lineText = ""; + characterList.forEach((character) => { + lineText += character; + if (context.measureText(lineText).width > limitedWidth) { + newLineTextList.push(preLineText); + lineText = character; + } + preLineText = lineText; + }); + } + newLineTextList.push(lineText); + }); + let lineLength = newLineTextList.length; + + // 角丸 + let width = boxWidth;// 枠の幅 + let height = (size * lineLength) + (padding * 3); // 枠の高さ + let toRadianCoefficient = Math.PI / 180; // 角度からラジアンへの変換係数 + // 角丸原点(左上座標) + let boxOrigin = { + "x": rtopX - width, + "y": rtopY, + } + // 円弧から円弧までの直線は自動で引かれます、角度は回り方によって変わります。 + // arc(中心x, 中心y, 半径, 開始角度, 終了角度, 反時計回り) + context.beginPath(); + context.arc(boxOrigin.x + radius, boxOrigin.y + radius, radius, 180 * toRadianCoefficient, 270 * toRadianCoefficient, false);// 左上 + context.arc(boxOrigin.x + width - radius, boxOrigin.y + radius, radius, 270 * toRadianCoefficient, 0, false);// 右上 + context.arc(boxOrigin.x + width - radius, boxOrigin.y + height - radius, radius, 0, 90 * toRadianCoefficient, false);// 右下 + context.arc(boxOrigin.x + radius, boxOrigin.y + height - radius, radius, 90 * toRadianCoefficient, 180 * toRadianCoefficient, false);// 左下 + context.closePath(); + context.fill(); + + // 矢印(ヒゲ) + let arrow = { + "x": rtopX - width / 2 + 40, + "y": rtopY + height + 10, + "width": 10, + "height": 10, + } + context.beginPath(); + context.moveTo(arrow.x, arrow.y); + context.lineTo(arrow.x, arrow.y - arrow.height); + context.lineTo(arrow.x - arrow.width, arrow.y - arrow.height); + context.fill(); + + // テキスト描画 + context.fillStyle = "#000000"; + newLineTextList.forEach((lineText, index) => { + context.fillText(lineText, boxOrigin.x + padding, boxOrigin.y + padding + (size * (index + 1))); + }); + + // 描画した吹き出しの位置情報を保存 + ugj_fdRecentBox = { x: boxOrigin.x, y: boxOrigin.y, w: width, h: height + arrow.height }; + // 指定時間後に消去(0以下で自動消去なし) + if (sec > 0) { + ugj_fdTimeoutID = setTimeout(() => { + clearFd(boxOrigin.x, boxOrigin.y, width, height + arrow.height); + }, sec * 1000); + } + + // return [boxOrigin.x, boxOrigin.y, width, height+arrow.height]; + // https://qiita.com/horikeso/items/95595f379a8dfa63c34a +} + +//===================================== +//======= Blockly GUI codes =========== +// Use in a block or block definition: + +// Resizable workspace injection script +var blocklyArea = document.getElementById('blocklyArea'); +var blocklyDiv = document.getElementById('blocklyDiv'); +// var workspace = Blockly.inject(blocklyDiv, +// {toolbox: document.getElementById('toolbox')}); +var workspace = Blockly.inject(blocklyDiv, + { + toolbox: document.getElementById('toolbox'), + theme: theme, + + scrollbars: true, + grid: { + spacing: 20, + length: 1, + colour: '#fff',//888 + snap: true + }, + zoom: { startScale: 1.0, controls: true }, + trashcan: true, + media: './google-blockly/media/' + }); +var onresize = function (e) { + // Compute the absolute coordinates and dimensions of blocklyArea. + var element = blocklyArea; + var x = 0; + var y = 0; + do { + x += element.offsetLeft; + y += element.offsetTop; + element = element.offsetParent; + } while (element); + // Position blocklyDiv over blocklyArea. + blocklyDiv.style.left = x + 'px'; + blocklyDiv.style.top = y + 'px'; + blocklyDiv.style.width = blocklyArea.offsetWidth + 'px'; + blocklyDiv.style.height = blocklyArea.offsetHeight + 'px'; + Blockly.svgResize(workspace); +}; +window.addEventListener('resize', onresize, false); +onresize(); +Blockly.svgResize(workspace); +//===================================== +//===================================== + + +// ワークスペースの未保存の変更のフラグ +const ugj_wsUpdateCB = event => { + if (event.type != Blockly.Events.UI) { + elec.setWsChanged(true); + } +} + +// ウィンドウロード・アンロード時 +window.onload = () => { + var menu = document.getElementById('conmenu'); //独自コンテキストメニュー + var area = document.getElementById('dlgContent'); //対象エリア + var body = document.body; //bodyエリア + body.oncontextmenu = () => false; + //右クリック時に独自コンテキストメニューを表示する + area.addEventListener('contextmenu', function (e) { + menu.style.left = e.pageX + 'px'; + menu.style.top = e.pageY + 'px'; + menu.classList.add('on'); + }); + //左クリック時に独自コンテキストメニューを非表示にする + body.addEventListener('click', function () { + if (menu.classList.contains('on')) { + menu.classList.remove('on'); + } + }); + + // ワークスペースといくつかの環境のオートリストア + ugj_loadWorkspace(); + elec.loadPrefsFromLS(); + setTimeout(() => { // 環境設定のロードが終わってからイベントリスナを作成 + workspace.addChangeListener(ugj_wsUpdateCB); + }, 100); +} +window.onbeforeunload = () => { + ugj_saveWorkspace(); + elec.savePrefsToLS(); +} + +// Electron動作とブラウザ動作を自動で仕分け +if (typeof require == 'function') { + // requireが使える = Electron + var elec = require('./scripts/eleclib'); + console.log('elec loaded.'); +} else { + //ブラウザ動作 + //requireのダミー + var require = (e) => { + alert(`この機能またはブロック [${e}] は web 版ではご利用になれません。\n詳しくはお問い合わせください。`); + // if (e=='elec' || e=='ocoge' || e=='child_process' || e=='@google-cloud/speech' || e=='nodemailer' || e=='fs' ) + // alert(`この機能またはブロックは web 版ではご利用になれません。\n詳しくはお問い合わせください。`); + // else return; + } + //elecを名前空間で置き換え + var elec = {}; + elec.saveFile = () => require('elec'); + elec.savePrefsToLS = () => { ; } + elec.loadPrefsFromLS = () => { ; } + elec.newFile = () => { ; } + elec.setWsChanged = () => { ; } + + //ワークスペースのダウンロード + elec.saveWsFile = xml_text => { + let blob = new Blob([xml_text], { "type": "text/xml" }); + const downLoadLink = document.createElement("a"); + document.body.appendChild(downLoadLink); + downLoadLink.download = 'workspace.xml'; + downLoadLink.href = URL.createObjectURL(blob); + downLoadLink.click(); + downLoadLink.parentElement.removeChild(downLoadLink); + return true; + } + //ワークスペースのインポート + elec.loadWsFile = () => { + const fileInputEl = document.createElement('input'); + document.body.appendChild(fileInputEl); + fileInputEl.type = 'file'; + fileInputEl.addEventListener('change', ev => { + let reader = new FileReader(); + reader.readAsText(ev.target.files[0]); + reader.addEventListener('load', () => { + let xml = Blockly.Xml.textToDom(reader.result); + Blockly.Xml.domToWorkspace(xml, workspace); + }); + }); + fileInputEl.click(); + fileInputEl.parentElement.removeChild(fileInputEl); + return ''; + } +} \ No newline at end of file