mirror of
https://github.com/ocogeclub/ocoge.git
synced 2024-11-25 08:59:49 +00:00
update: index.html
separated css and js from index.html
This commit is contained in:
parent
e2698596b8
commit
d8b1f5b47d
396
index.css
Normal file
396
index.css
Normal file
@ -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;
|
||||||
|
}
|
950
index.html
950
index.html
@ -8,406 +8,9 @@
|
|||||||
</link>
|
</link>
|
||||||
<link rel="stylesheet" href="./fonts/css/all.min.css">
|
<link rel="stylesheet" href="./fonts/css/all.min.css">
|
||||||
</link>
|
</link>
|
||||||
<style id="webmakerstyle">
|
<link rel="stylesheet" href="./index.css">
|
||||||
@font-face {
|
</link>
|
||||||
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;
|
|
||||||
font-family: "Noto Sans CJK JP Regular", sans-serif;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Makes our label white. */
|
|
||||||
.blocklyTreeLabel {
|
|
||||||
font-family: 'Noto Sans CJK JP Light';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
@ -1314,557 +917,10 @@
|
|||||||
<script src="./google-blockly/msg/js/ja.js"></script>
|
<script src="./google-blockly/msg/js/ja.js"></script>
|
||||||
<script src="./scripts/custom-dialog.js"></script>
|
<script src="./scripts/custom-dialog.js"></script>
|
||||||
<script src="./scripts/ugj_blocks.js"></script>
|
<script src="./scripts/ugj_blocks.js"></script>
|
||||||
|
<script src="./scripts/ugj_script.js"></script>
|
||||||
<script src="./scripts/beautify.min.js"></script>
|
<script src="./scripts/beautify.min.js"></script>
|
||||||
<script src="./scripts/prettify.js"></script>
|
<script src="./scripts/prettify.js"></script>
|
||||||
<script src="./.shared/skyway_key.js"></script>
|
<script src="./.shared/skyway_key.js"></script>
|
||||||
<script>
|
|
||||||
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,
|
|
||||||
'fontStyle': { "family": "Noto Sans CJK JP Light" },
|
|
||||||
'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, '&').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: '#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 '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//# sourceURL=userscript.js
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
543
scripts/ugj_script.js
Normal file
543
scripts/ugj_script.js
Normal file
@ -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, '&').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 '';
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user