From 773841acef9f33c5381fee41a865c6ba09169080 Mon Sep 17 00:00:00 2001 From: nkarl <21993921+nkarl@users.noreply.github.com> Date: Sun, 17 Nov 2024 16:45:42 -0800 Subject: [PATCH] Updated the Lucid vesting app. --- code/Week03/lucid/.gitignore | 1 + code/Week03/lucid/README.md | 11 + code/Week03/lucid/package.json | 64 ++-- .../src/bootstrap-datetimepicker.min.css | 1 - code/Week03/lucid/src/index.html | 138 ++++---- code/Week03/lucid/src/index.js | 324 +++++++----------- code/Week03/lucid/src/utils.js | 125 +++++++ .../static/bootstrap-datetimepicker.min.js | 6 - code/Week03/lucid/webpack.config.js | 36 +- 9 files changed, 407 insertions(+), 299 deletions(-) create mode 100644 code/Week03/lucid/.gitignore create mode 100644 code/Week03/lucid/README.md delete mode 100644 code/Week03/lucid/src/bootstrap-datetimepicker.min.css create mode 100644 code/Week03/lucid/src/utils.js delete mode 100644 code/Week03/lucid/static/bootstrap-datetimepicker.min.js diff --git a/code/Week03/lucid/.gitignore b/code/Week03/lucid/.gitignore new file mode 100644 index 000000000..5966c578d --- /dev/null +++ b/code/Week03/lucid/.gitignore @@ -0,0 +1 @@ +**/.env diff --git a/code/Week03/lucid/README.md b/code/Week03/lucid/README.md new file mode 100644 index 000000000..a2e18ceba --- /dev/null +++ b/code/Week03/lucid/README.md @@ -0,0 +1,11 @@ +## Setup + +1. Create a `.env` file inside this directory. + +2. Inside the file, add the following line with the actual string of your Blockfrost API project id: + +```sh +BLOCKFROST_PROJECT_ID= +``` + +3. Run `npm run install && npm run start` diff --git a/code/Week03/lucid/package.json b/code/Week03/lucid/package.json index 8a8fbf110..89bf7884e 100644 --- a/code/Week03/lucid/package.json +++ b/code/Week03/lucid/package.json @@ -1,29 +1,39 @@ { - "name": "atomic", - "version": "1.0.0", - "description": "", - "private": true, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "build": "webpack", - "start": "webpack serve --open" - }, - "keywords": [], - "author": "", - "license": "MIT", - "devDependencies": { - "css-loader": "^6.7.3", - "html-webpack-plugin": "^5.5.0", - "style-loader": "^3.3.1", - "webpack": "^5.75.0", - "webpack-cli": "^5.0.1", - "webpack-dev-server": "^4.11.1" - }, - "dependencies": { - "bootstrap": "^5.2.3", - "copy-webpack-plugin": "^11.0.0", - "lucid-cardano": "^0.9.1", - "popper.js": "^1.16.1", - "web3": "^1.8.2" - } + "name": "atomic", + "version": "1.0.0", + "description": "a demo Vesting app", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack", + "start": "webpack serve --open" + }, + "keywords": [], + "author": "", + "license": "MIT", + "devDependencies": { + "@popperjs/core": "^2.11.8", + "autoprefixer": "^10.4.20", + "css-loader": "^7.1.2", + "html-webpack-plugin": "^5.6.3", + "postcss-loader": "^8.1.1", + "sass": "^1.80.4", + "sass-loader": "^16.0.2", + "style-loader": "^4.0.0", + "webpack": "^5.95.0", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^5.1.0" + }, + "dependencies": { + "bootstrap": "^5.3.3", + "copy-webpack-plugin": "^12.0.2", + "dotenv": "^16.4.5", + "dotenv-webpack": "^8.1.0", + "lucid-cardano": "^0.10.10", + "node-polyfill-webpack-plugin": "^4.0.0", + "process": "^0.11.10", + "web3": "^4.14.0" + }, + "browser": { + "path": false + } } diff --git a/code/Week03/lucid/src/bootstrap-datetimepicker.min.css b/code/Week03/lucid/src/bootstrap-datetimepicker.min.css deleted file mode 100644 index 50e9453eb..000000000 --- a/code/Week03/lucid/src/bootstrap-datetimepicker.min.css +++ /dev/null @@ -1 +0,0 @@ -.datetimepicker{padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;direction:ltr}.datetimepicker-inline{width:220px}.datetimepicker.datetimepicker-rtl{direction:rtl}.datetimepicker.datetimepicker-rtl table tr td span{float:right}.datetimepicker-dropdown,.datetimepicker-dropdown-left{top:0;left:0}[class*=" datetimepicker-dropdown"]:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute}[class*=" datetimepicker-dropdown"]:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute}[class*=" datetimepicker-dropdown-top"]:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-bottom:0}[class*=" datetimepicker-dropdown-top"]:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;border-bottom:0}.datetimepicker-dropdown-bottom-left:before{top:-7px;right:6px}.datetimepicker-dropdown-bottom-left:after{top:-6px;right:7px}.datetimepicker-dropdown-bottom-right:before{top:-7px;left:6px}.datetimepicker-dropdown-bottom-right:after{top:-6px;left:7px}.datetimepicker-dropdown-top-left:before{bottom:-7px;right:6px}.datetimepicker-dropdown-top-left:after{bottom:-6px;right:7px}.datetimepicker-dropdown-top-right:before{bottom:-7px;left:6px}.datetimepicker-dropdown-top-right:after{bottom:-6px;left:7px}.datetimepicker>div{display:none}.datetimepicker.minutes div.datetimepicker-minutes{display:block}.datetimepicker.hours div.datetimepicker-hours{display:block}.datetimepicker.days div.datetimepicker-days{display:block}.datetimepicker.months div.datetimepicker-months{display:block}.datetimepicker.years div.datetimepicker-years{display:block}.datetimepicker table{margin:0}.datetimepicker td,.datetimepicker th{text-align:center;width:20px;height:20px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border:0}.table-striped .datetimepicker table tr td,.table-striped .datetimepicker table tr th{background-color:transparent}.datetimepicker table tr td.minute:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.hour:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.day:hover{background:#eee;cursor:pointer}.datetimepicker table tr td.new,.datetimepicker table tr td.old{color:#999}.datetimepicker table tr td.disabled,.datetimepicker table tr td.disabled:hover{background:0;color:#999;cursor:default}.datetimepicker table tr td.today,.datetimepicker table tr td.today.disabled,.datetimepicker table tr td.today.disabled:hover,.datetimepicker table tr td.today:hover{background-color:#fde19a;background-image:-moz-linear-gradient(top,#fdd49a,#fdf59a);background-image:-ms-linear-gradient(top,#fdd49a,#fdf59a);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fdd49a),to(#fdf59a));background-image:-webkit-linear-gradient(top,#fdd49a,#fdf59a);background-image:-o-linear-gradient(top,#fdd49a,#fdf59a);background-image:linear-gradient(top,#fdd49a,#fdf59a);background-repeat:repeat-x;border-color:#fdf59a #fdf59a #fbed50;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25)}.datetimepicker table tr td.today.active,.datetimepicker table tr td.today.disabled,.datetimepicker table tr td.today.disabled.active,.datetimepicker table tr td.today.disabled.disabled,.datetimepicker table tr td.today.disabled:active,.datetimepicker table tr td.today.disabled:hover,.datetimepicker table tr td.today.disabled:hover.active,.datetimepicker table tr td.today.disabled:hover.disabled,.datetimepicker table tr td.today.disabled:hover:active,.datetimepicker table tr td.today.disabled:hover:hover,.datetimepicker table tr td.today.disabled:hover[disabled],.datetimepicker table tr td.today.disabled[disabled],.datetimepicker table tr td.today:active,.datetimepicker table tr td.today:hover,.datetimepicker table tr td.today:hover.active,.datetimepicker table tr td.today:hover.disabled,.datetimepicker table tr td.today:hover:active,.datetimepicker table tr td.today:hover:hover,.datetimepicker table tr td.today:hover[disabled],.datetimepicker table tr td.today[disabled]{background-color:#fdf59a}.datetimepicker table tr td.today.active,.datetimepicker table tr td.today.disabled.active,.datetimepicker table tr td.today.disabled:active,.datetimepicker table tr td.today.disabled:hover.active,.datetimepicker table tr td.today.disabled:hover:active,.datetimepicker table tr td.today:active,.datetimepicker table tr td.today:hover.active,.datetimepicker table tr td.today:hover:active{background-color:#fbf069}.datetimepicker table tr td.active,.datetimepicker table tr td.active.disabled,.datetimepicker table tr td.active.disabled:hover,.datetimepicker table tr td.active:hover{background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-ms-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datetimepicker table tr td.active.active,.datetimepicker table tr td.active.disabled,.datetimepicker table tr td.active.disabled.active,.datetimepicker table tr td.active.disabled.disabled,.datetimepicker table tr td.active.disabled:active,.datetimepicker table tr td.active.disabled:hover,.datetimepicker table tr td.active.disabled:hover.active,.datetimepicker table tr td.active.disabled:hover.disabled,.datetimepicker table tr td.active.disabled:hover:active,.datetimepicker table tr td.active.disabled:hover:hover,.datetimepicker table tr td.active.disabled:hover[disabled],.datetimepicker table tr td.active.disabled[disabled],.datetimepicker table tr td.active:active,.datetimepicker table tr td.active:hover,.datetimepicker table tr td.active:hover.active,.datetimepicker table tr td.active:hover.disabled,.datetimepicker table tr td.active:hover:active,.datetimepicker table tr td.active:hover:hover,.datetimepicker table tr td.active:hover[disabled],.datetimepicker table tr td.active[disabled]{background-color:#04c}.datetimepicker table tr td.active.active,.datetimepicker table tr td.active.disabled.active,.datetimepicker table tr td.active.disabled:active,.datetimepicker table tr td.active.disabled:hover.active,.datetimepicker table tr td.active.disabled:hover:active,.datetimepicker table tr td.active:active,.datetimepicker table tr td.active:hover.active,.datetimepicker table tr td.active:hover:active{background-color:#039}.datetimepicker table tr td span{display:block;width:23%;height:54px;line-height:54px;float:left;margin:1%;cursor:pointer;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.datetimepicker .datetimepicker-hours span{height:26px;line-height:26px}.datetimepicker .datetimepicker-hours table tr td span.hour_am,.datetimepicker .datetimepicker-hours table tr td span.hour_pm{width:14.6%}.datetimepicker .datetimepicker-hours fieldset legend,.datetimepicker .datetimepicker-minutes fieldset legend{margin-bottom:inherit;line-height:30px}.datetimepicker .datetimepicker-minutes span{height:26px;line-height:26px}.datetimepicker table tr td span:hover{background:#eee}.datetimepicker table tr td span.disabled,.datetimepicker table tr td span.disabled:hover{background:0;color:#999;cursor:default}.datetimepicker table tr td span.active,.datetimepicker table tr td span.active.disabled,.datetimepicker table tr td span.active.disabled:hover,.datetimepicker table tr td span.active:hover{background-color:#006dcc;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-ms-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.datetimepicker table tr td span.active.active,.datetimepicker table tr td span.active.disabled,.datetimepicker table tr td span.active.disabled.active,.datetimepicker table tr td span.active.disabled.disabled,.datetimepicker table tr td span.active.disabled:active,.datetimepicker table tr td span.active.disabled:hover,.datetimepicker table tr td span.active.disabled:hover.active,.datetimepicker table tr td span.active.disabled:hover.disabled,.datetimepicker table tr td span.active.disabled:hover:active,.datetimepicker table tr td span.active.disabled:hover:hover,.datetimepicker table tr td span.active.disabled:hover[disabled],.datetimepicker table tr td span.active.disabled[disabled],.datetimepicker table tr td span.active:active,.datetimepicker table tr td span.active:hover,.datetimepicker table tr td span.active:hover.active,.datetimepicker table tr td span.active:hover.disabled,.datetimepicker table tr td span.active:hover:active,.datetimepicker table tr td span.active:hover:hover,.datetimepicker table tr td span.active:hover[disabled],.datetimepicker table tr td span.active[disabled]{background-color:#04c}.datetimepicker table tr td span.active.active,.datetimepicker table tr td span.active.disabled.active,.datetimepicker table tr td span.active.disabled:active,.datetimepicker table tr td span.active.disabled:hover.active,.datetimepicker table tr td span.active.disabled:hover:active,.datetimepicker table tr td span.active:active,.datetimepicker table tr td span.active:hover.active,.datetimepicker table tr td span.active:hover:active{background-color:#039}.datetimepicker table tr td span.old{color:#999}.datetimepicker th.switch{width:145px}.datetimepicker th i{pointer-events:none}.datetimepicker tfoot tr:first-child th,.datetimepicker thead tr:first-child th{cursor:pointer}.datetimepicker tfoot tr:first-child th:hover,.datetimepicker thead tr:first-child th:hover{background:#eee}.input-append.date .add-on i,.input-group.date span,.input-prepend.date .add-on i{cursor:pointer} \ No newline at end of file diff --git a/code/Week03/lucid/src/index.html b/code/Week03/lucid/src/index.html index dcd327d16..35cd52694 100644 --- a/code/Week03/lucid/src/index.html +++ b/code/Week03/lucid/src/index.html @@ -1,83 +1,95 @@ - + - + + <%= htmlWebpackPlugin.options.title %> - - - -
+ +
+
- +
- - + + + - - + +
Cardano PubKeyHashCardano Balance (ada)PubKeyHashBalance (ADA)
- - -
+ +
+

+
- - + + - +
+

+
+
+ + + + + + + + + + + + + +
UTxO's on Cardano
RefStakeholderADADeadline
- - - - - - - - - - - - -
UTxO's on Cardano
RefBeneficiaryLovelaceDeadline
+
+ +
+
+
+
- + - +
Cardano transactions
Transaction hashCompleted Transaction Hash
-
- - - - \ No newline at end of file + diff --git a/code/Week03/lucid/src/index.js b/code/Week03/lucid/src/index.js index 85dec4e6b..0339752bb 100644 --- a/code/Week03/lucid/src/index.js +++ b/code/Week03/lucid/src/index.js @@ -1,236 +1,170 @@ +if (!navigator.userAgent.includes('Chrome')) { + window.alert("App supports Chromium-based browsers. App has been terminated."); + window.stop(); +} + import 'bootstrap'; import 'bootstrap/dist/css/bootstrap.min.css'; -import './bootstrap-datetimepicker.min.css'; import * as L from 'lucid-cardano'; +import * as Utils from './utils.js'; const vestingScript = { type: "PlutusV2", script: "590b30590b2d0100003232323322323233223232323232323233223233223232323232323232333222323232322323222323253353232323253355335323235002222222222222533533355301a12001321233001225335002210031001002502c25335333573466e3c0380040ec0e84d40b8004540b4010840ec40e4d401488009400440b04cd5ce2491f62656e65666963696172792773207369676e6174757265206d697373696e670002b15335323232350022235002223500522350022253335333501900b00600215335001153350051333501800b00300710361333501800b00300710361333501800b00300735500322222222222200533501433501635029350052200102d335015502802d123333333300122333573466e1c0080040bc0b8894cd4ccd5cd19b8700200102f02e101515335333573466e240080040bc0b8404c405088ccd5cd19b8800200102f02e22333573466e240080040bc0b888ccd5cd19b8900200102e02f22333573466e200080040b80bc894cd4ccd5cd19b8900200102f02e10011002225335333573466e240080040bc0b84008400440b04cd5ce248114646561646c696e65206e6f7420726561636865640002b102b135001220023333573466e1cd55cea80224000466442466002006004646464646464646464646464646666ae68cdc39aab9d500c480008cccccccccccc88888888888848cccccccccccc00403403002c02802402001c01801401000c008cd408c090d5d0a80619a8118121aba1500b33502302535742a014666aa04eeb94098d5d0a804999aa813bae502635742a01066a0460606ae85401cccd5409c0c5d69aba150063232323333573466e1cd55cea80124000466a0486464646666ae68cdc39aab9d5002480008cd40a8cd40edd69aba15002303e357426ae8940088c98c8100cd5ce02182101f09aab9e5001137540026ae854008c8c8c8cccd5cd19b8735573aa0049000119a81499a81dbad35742a004607c6ae84d5d1280111931902019ab9c04304203e135573ca00226ea8004d5d09aba2500223263203c33573807e07c07426aae7940044dd50009aba1500533502375c6ae854010ccd5409c0b48004d5d0a801999aa813bae200135742a004605e6ae84d5d1280111931901c19ab9c03b03a036135744a00226ae8940044d5d1280089aba25001135744a00226ae8940044d5d1280089aba25001135744a00226ae8940044d55cf280089baa00135742a008603e6ae84d5d1280211931901519ab9c02d02c0283333573466e1cd55ce9baa0054800080ac8c98c80a4cd5ce0160158139999ab9a3370e6aae7540192000233221233001003002375c6ae854018dd69aba135744a00c464c6405066ae700ac0a809840a44c98c809ccd5ce2490350543500029135573ca00226ea80044d55cf280089baa00132001355023221122253350011350032200122133350052200230040023335530071200100500400112223500222350032253335333500800700400215335003100110261025102612223232323253335006215333500621533350082130044984c00d261533350072130044984c00d26100d100b1533350072130044984c00d261533350062130044984c00d26100c1533350052100a100b100915333500521533350072130054984c011261533350062130054984c01126100c100a1533350062130054984c011261533350052130054984c01126100b2533350052153335007215333500721333500b00a002001161616100b153335006215333500621333500a009002001161616100a10092533350042153335006215333500621333500a009002001161616100a1533350052153335005213335009008002001161616100910082533350032153335005215333500521333500900800200116161610091533350042153335004213335008007002001161616100810072533350022153335004215333500421333500800700200116161610081533350032153335003213335007006002001161616100710061235001222222220071222003122200212220011221233001003002122123300100300212212330010030021232230023758002640026aa034446666aae7c004940288cd4024c010d5d080118019aba200201a232323333573466e1cd55cea80124000466442466002006004601c6ae854008c014d5d09aba2500223263201833573803603402c26aae7940044dd50009191919191999ab9a3370e6aae75401120002333322221233330010050040030023232323333573466e1cd55cea80124000466442466002006004602e6ae854008cd403c058d5d09aba2500223263201d33573804003e03626aae7940044dd50009aba150043335500875ca00e6ae85400cc8c8c8cccd5cd19b875001480108c84888c008010d5d09aab9e500323333573466e1d4009200223212223001004375c6ae84d55cf280211999ab9a3370ea00690001091100191931900f99ab9c02202101d01c01b135573aa00226ea8004d5d0a80119a805bae357426ae8940088c98c8064cd5ce00e00d80b89aba25001135744a00226aae7940044dd5000899aa800bae75a224464460046eac004c8004d5405c88c8cccd55cf80112804119a8039991091980080180118031aab9d5002300535573ca00460086ae8800c0604d5d080088910010910911980080200189119191999ab9a3370ea002900011a80398029aba135573ca00646666ae68cdc3a801240044a00e464c6402866ae7005c0580480444d55cea80089baa0011212230020031122001232323333573466e1d400520062321222230040053007357426aae79400c8cccd5cd19b875002480108c848888c008014c024d5d09aab9e500423333573466e1d400d20022321222230010053007357426aae7940148cccd5cd19b875004480008c848888c00c014dd71aba135573ca00c464c6402466ae7005405004003c0380344d55cea80089baa001232323333573466e1cd55cea80124000466442466002006004600a6ae854008dd69aba135744a004464c6401c66ae700440400304d55cf280089baa0012323333573466e1cd55cea800a400046eb8d5d09aab9e500223263200c33573801e01c01426ea80048c8c8c8c8c8cccd5cd19b8750014803084888888800c8cccd5cd19b875002480288488888880108cccd5cd19b875003480208cc8848888888cc004024020dd71aba15005375a6ae84d5d1280291999ab9a3370ea00890031199109111111198010048041bae35742a00e6eb8d5d09aba2500723333573466e1d40152004233221222222233006009008300c35742a0126eb8d5d09aba2500923333573466e1d40192002232122222223007008300d357426aae79402c8cccd5cd19b875007480008c848888888c014020c038d5d09aab9e500c23263201533573803002e02602402202001e01c01a26aae7540104d55cf280189aab9e5002135573ca00226ea80048c8c8c8c8cccd5cd19b875001480088ccc888488ccc00401401000cdd69aba15004375a6ae85400cdd69aba135744a00646666ae68cdc3a80124000464244600400660106ae84d55cf280311931900719ab9c01101000c00b135573aa00626ae8940044d55cf280089baa001232323333573466e1d400520022321223001003375c6ae84d55cf280191999ab9a3370ea004900011909118010019bae357426aae7940108c98c802ccd5ce00700680480409aab9d50011375400224464646666ae68cdc3a800a40084a00c46666ae68cdc3a8012400446a010600c6ae84d55cf280211999ab9a3370ea00690001091100111931900619ab9c00f00e00a009008135573aa00226ea8004484888c00c010448880048c8cccd5cd19b8750014800880188cccd5cd19b8750024800080188c98c8018cd5ce00480400200189aab9d37540029309100109100089000a490350543100112323001001223300330020020011", }; +const blockfrost = { + url: "https://cardano-preview.blockfrost.io/api/v0", + id: process.env.BLOCKFROST_PROJECT_ID +} + const VestingDatum = L.Data.Object({ - beneficiary: L.Data.String, - deadline: L.Data.BigInt, + stakeholder: L.Data.Bytes(), + deadline: L.Data.Integer(), }); -function removeChildren(elt) { - while (elt.firstChild) { - elt.removeChild(elt.lastChild); - } -} - -async function loadCardano() { +/** + * NOTE: Connects the Nami wallet. + */ +async function connectNami() { const nami = window.cardano.nami; - if (!nami) { - setTimeout(loadCardano); + if (nami === undefined) { + alert("The Nami wallet is not found. Consider installing the Chrome extension."); + setTimeout(connectNami); } else { - const api = await nami.enable(); - console.log('nami enabled'); - const lucid = await L.Lucid.new( - new L.Blockfrost("https://cardano-preview.blockfrost.io/api/v0", "preview1JXEDVldkIyBkxEUrEx3n9ll4afFK1Xj"), - "Preview", - ); - console.log('lucid active'); - lucid.selectWallet(api); - return lucid; - } -} - -async function submitCardanoTx(signedTx) { - const tid = await signedTx.submit(); - console.log("Cardano tx submitted: " + tid); - addLinkToTable("cardanoTxTable", "https://preview.cardanoscan.io/transaction/" + tid, tid); -} - -async function signAndSubmitCardanoTx(tx) { - try { - const signedTx = await tx.sign().complete(); - await submitCardanoTx(signedTx); - } catch (err) { - alert(`Cardano transaction:\ninfo: ${err.info}\nmessage: ${err.message}`); - throw (err); + const namiApi = await nami.enable(); + return await L.Lucid.new( + new L.Blockfrost(blockfrost.url, blockfrost.id), + "Preview" + ).then(a => a.selectWallet(namiApi)); } } -async function getCardanoPKH() { - const addr = await lucid.wallet.address(); - const details = await L.getAddressDetails(addr); - return details.paymentCredential.hash; -} - -async function getStatus() { - const pkh = await getCardanoPKH(); - const utxos = await lucid.wallet.getUtxos(); - const lovelace = utxos.reduce((acc, utxo) => acc + utxo.assets.lovelace, 0n); - - const vestings = await vestingUTxOs(); - - return { - cardanoPKH: pkh, - cardanoBalance: lovelace, - vestingUTxOs: vestings, - }; -} - -function addCell(tr, content) { - const td = document.createElement('td'); - tr.appendChild(td); - td.appendChild(document.createTextNode(content)); +/** + * Loads the panel that contains wallet . + */ +async function loadWalletDetails(wallet) { + const { pkh: pkh, balance: balance } = + await Utils.queryWalletDetails(wallet); + + const nodePKH = window.document.getElementById('cardanoPKH'); + Utils.removeChildren(nodePKH); + nodePKH.appendChild(window.document.createTextNode(pkh)); + + const nodeBalance = window.document.getElementById('cardanoBalance'); + const ada = Number(balance) / 1_000_000; + Utils.removeChildren(nodeBalance); + nodeBalance.appendChild(window.document.createTextNode(ada)); } -function addLinkToTable(tableId, href, text) { - const txTable = document.getElementById('cardanoTxTable'); - const tr = document.createElement('tr'); - txTable.appendChild(tr); - const td = document.createElement('td'); - tr.appendChild(td); - const a = document.createElement('a'); - td.appendChild(a); - a.setAttribute('href', href); - a.setAttribute('target', '_blank'); - a.appendChild(document.createTextNode(text)); -} +/** + * Loads the panel that contains vesting Tx at the contract's address. + */ +async function loadVestingUTxOsTable(contractAddr, Datum) { + const vestingUTxOs = await Utils.getVestingUTxOs(contractAddr, Datum); -function addCopyCell(row, text) { - const td = document.createElement("td"); - row.appendChild(td); - const span = document.createElement("span"); - td.appendChild(span); - const uid = String(Math.random()).slice(2); - span.setAttribute("id", uid); - span.appendChild(document.createTextNode(text)); - const button = document.createElement("button"); - td.appendChild(button); - button.setAttribute("type", "button"); - button.classList.add("btn"); - button.classList.add("btn-outline-primary"); - button.classList.add("btn-sm"); - button.addEventListener("click", () => onCopy(uid)); -} + const vestingUTxOsTable = window.document.getElementById('vestingUTxOsTable'); + Utils.removeChildren(vestingUTxOsTable); -async function setStatus() { - const status = await getStatus(); - - const cardanoPKH = document.getElementById('cardanoPKH'); - removeChildren(cardanoPKH); - cardanoPKH.appendChild(document.createTextNode(status.cardanoPKH)); - - const cardanoBalance = document.getElementById('cardanoBalance'); - const ada = Number(status.cardanoBalance) / 1000000; - removeChildren(cardanoBalance); - cardanoBalance.appendChild(document.createTextNode(ada)); - - const vestingUTxOsTable = document.getElementById('vestingUTxOsTable'); - removeChildren(vestingUTxOsTable); - for (const x of status.vestingUTxOs) { - const tr = document.createElement('tr'); + // generates the UTxOs table for the Tx at that contract address. + for (const x of vestingUTxOs) { + const tr = window.document.createElement('tr'); vestingUTxOsTable.appendChild(tr); - addCopyCell(tr, x.utxo.txHash + '#' + x.utxo.outputIndex); - addCopyCell(tr, x.datum.beneficiary); - addCell(tr, x.utxo.assets.lovelace); - addCell(tr, new Date(Number(x.datum.deadline))); + Utils.addCell(tr, x.utxo.txHash + '#' + x.utxo.outputIndex, true); + Utils.addCell(tr, x.datum.stakeholder, true); + Utils.addCell(tr, x.utxo.assets.lovelace); + Utils.addCell(tr, new Date(Number(x.datum.deadline))); } } -async function vestingUTxOs() { - const utxos = await lucid.utxosAt(vestingAddress); - const res = []; - for (const utxo of utxos) { - const datum = utxo.datum; - if (datum) { - try { - const d = L.Data.from(datum, VestingDatum); - res.push({ - utxo: utxo, - datum: d - }); - } catch (err) { - } - } +/** + * NOTE: VESTING + */ +async function onVest() { + const nodeStakeholder = window.document.getElementById('vestStakeholderText'); + const stakeholder = nodeStakeholder.value; + // + const nodeAmount = window.document.getElementById('vestAmountText'); + const amount = BigInt(parseInt(nodeAmount.value)); + + const nodeDeadline = window.document.getElementById('vestDeadlineText'); + const deadline = BigInt(Date.parse(nodeDeadline.value)); + + const plutusDatum = { + stakeholder: stakeholder, + deadline: deadline } - return res; -} -async function findUTxO(ref) { - const chunks = ref.split('#'); - const tid = chunks[0]; - const ix = parseInt(chunks[1]); - const utxos = await vestingUTxOs(); - for (const utxo of utxos) { - if (utxo.utxo.txHash == tid && utxo.utxo.outputIndex == ix) { - return utxo; - } - } - return null; -} + const cborDatum = L.Data.to(plutusDatum, VestingDatum); + const tx = + await lucid + .newTx() + .payToContract( + vestingAddress, + { inline: cborDatum }, + { lovelace: amount }) + .complete(); -async function onVest() { - const beneficiaryText = document.getElementById('vestBeneficiaryText'); - const beneficiary = beneficiaryText.value; - const amountText = document.getElementById('vestAmountText'); - const amount = BigInt(parseInt(vestAmountText.value)); - const deadlineText = document.getElementById('vestDeadlineText'); - const deadline = BigInt(Date.parse(deadlineText.value)); - - const d = { - beneficiary: beneficiary, - deadline: deadline, - }; - const datum = L.Data.to(d, VestingDatum); - const tx = await lucid - .newTx() - .payToContract(vestingAddress, { inline: datum }, { lovelace: amount }) - .complete(); - signAndSubmitCardanoTx(tx); - - beneficiaryText.value = ""; - amountText.value = ""; - deadlineText.value = ""; + Utils.signAndSubmitCardanoTx(tx); + + beneficiaryNode.value = ""; + nodeAmount.value = ""; + nodeDeadline.value = ""; } +/** + * NOTE: CLAIMING + */ async function onClaim() { - const pkh = await getCardanoPKH(); + const cardanoPKH = await Utils.getCardanoPKH(wallet); - const referenceText = document.getElementById('claimReferenceText'); - const reference = referenceText.value; + const nodeRef = window.document.getElementById('claimReferenceText'); + const refTx = nodeRef.value; - const utxo = await findUTxO(reference); + const utxo = await Utils.findUTxO(refTx, vestingAddress, VestingDatum); if (utxo) { - const tx = await lucid - .newTx() - .collectFrom([utxo.utxo], L.Data.to(new L.Constr(0, []))) - .attachSpendingValidator(vestingScript) - .addSignerKey(pkh) - .validFrom(Number(utxo.datum.deadline)) - .complete(); - signAndSubmitCardanoTx(tx); + const tx = + await lucid + .newTx() + .collectFrom( + [utxo.utxo], + L.Data.to(new L.Constr(0, []))) + .attachSpendingValidator(vestingScript) + .addSignerKey(cardanoPKH) + .validFrom(Number(utxo.datum.deadline)) + .complete(); + + Utils.signAndSubmitCardanoTx(tx); } else { console.log("UTxO not found"); } - referenceText.value = ""; -} - -function onCopy(elt) { - navigator.clipboard.writeText(document.getElementById(elt).firstChild.textContent); + nodeRef.value = ""; } -window.L = L; -window.lucid = await loadCardano(); -const vestingAddress = lucid.utils.validatorToAddress(vestingScript); - -$(function () { - $(".dtp").datetimepicker({ - minuteStep: 1, - autoclose: true, - format: 'yyyy-mm-dd hh:ii' - }); -}); - -setStatus(); -setInterval(setStatus, 5000); - -document.getElementById("vestButton").addEventListener("click", onVest); -document.getElementById("claimButton").addEventListener("click", onClaim); -document.getElementById('cardanoPKHButton').addEventListener("click", () => onCopy("cardanoPKH")); \ No newline at end of file +/** + * NOTE: App Run. + */ +window.lucid = await connectNami(); + +const wallet = lucid.wallet; +const vestingAddress = window.lucid.utils.validatorToAddress(vestingScript); + +loadWalletDetails(wallet); +loadVestingUTxOsTable(vestingAddress, VestingDatum); + +/** + * NOTE: Additional event listeners. + */ +window.document + .getElementById("vestButton") + .addEventListener("click", onVest); +window.document + .getElementById("claimButton") + .addEventListener("click", onClaim); +window.document + .getElementById("vestDeadlineText") + .addEventListener("change", + () => window.document.getElementById('vestDeadlineText').style.color = "black"); +//window.document.getElementById('cardanoPKHButton').addEventListener("click", () => onCopy("cardanoPKH")); diff --git a/code/Week03/lucid/src/utils.js b/code/Week03/lucid/src/utils.js new file mode 100644 index 000000000..f519e6969 --- /dev/null +++ b/code/Week03/lucid/src/utils.js @@ -0,0 +1,125 @@ +import * as L from 'lucid-cardano'; + +/** + * NOTE: Wallet actions + */ +export async function queryWalletDetails(wallet) { + const pkh = await getCardanoPKH(wallet); + const utxos = await wallet.getUtxos(); + /* DEBUG */ console.log("show details of utxos from pkh"); + /* DEBUG */ console.log(utxos); + const balance = utxos.reduce((acc, utxo) => acc + utxo.assets.lovelace, 0n); + + return { + pkh: pkh, + balance: balance, + }; +} + +export async function getCardanoPKH(wallet) { + const addr = await wallet.address(); + const details = L.getAddressDetails(addr); + /* DEBUG */ console.log("show address details"); + /* DEBUG */ console.log(details); + return details.paymentCredential.hash; +} + +/** + * NOTE: Smart Contract actions + */ +export async function getVestingUTxOs(address, Datum) { + const utxos = await window.lucid.utxosAt(address); + /* DEBUG */ console.log("show detailed utxos from the contract addr"); + /* DEBUG */ console.log(utxos); + let res = []; + for (const utxo of utxos) { + const datum = utxo.datum; + if (datum) { + try { + const d = L.Data.from(datum, Datum); + res.push({ utxo: utxo, datum: d }); + } catch (err) { + console.log("error: unable to convert from CBOR object (could be a Map object)"); + } + } + } + /* DEBUG */ console.log("show detailed _valid_ utxos from the contract addr", res); + return res; +} + +/** + * NOTE: Tx actions + */ +async function submitCardanoTx(signedTx) { + const tid = await signedTx.submit(); + /* DEBUG */ console.log("show Cardano tx submitted: " + tid); + addTxLinkToTable("https://preview.cardanoscan.io/transaction/" + tid, tid); +} + +export async function signAndSubmitCardanoTx(tx) { + try { + const signedTx = await tx.sign().complete(); + /* DEBUG */ console.log("show signedTx object", signedTx); + await submitCardanoTx(signedTx); + } catch (err) { + alert(`Cardano transaction:\ninfo: ${err.info}\nmessage: ${err.message}`); + throw (err); + } +} + +export async function findUTxO(refTx, contractAddress, Datum) { + const [tid, idx] = refTx.split('#'); + const utxos = await utils.getVestingUTxOs(contractAddress, Datum); + for (const utxo of utxos) { + if (utxo.utxo.txHash == tid && + utxo.utxo.outputIndex == parseInt(idx)) { + return utxo; + } + } + return null; +} + + +/** + * NOTE: DOM node actions + */ +export function removeChildren(node) { + while (node.firstChild) { + node.removeChild(node.lastChild); + } +} + +export function addCell(tr, content, copyEnabled = false) { + const td = window.document.createElement('td'); + tr.appendChild(td); + + if (copyEnabled) { + const node = window.document.createElement("p"); + td.appendChild(node); + const uid = "uid_" + String(Math.random()).slice(2); + node.setAttribute("id", uid); + + node.appendChild(window.document.createTextNode(content)); + node.addEventListener( + "click", + () => navigator.clipboard.writeText(window.document.getElementById(uid).firstChild.textContent) + ); + } else { + td.appendChild(window.document.createTextNode(content)); + } +} + +function addTxLinkToTable(href, txIdText) { + const txTable = window.document.getElementById("completedTxTable"); + + const tr = window.document.createElement('tr'); + txTable.appendChild(tr); + const td = window.document.createElement('td'); + tr.appendChild(td); + const a = window.document.createElement('a'); + td.appendChild(a); + + a.setAttribute('href', href); + a.setAttribute('target', '_blank'); + a.appendChild(window.document.createTextNode(txIdText)); +} diff --git a/code/Week03/lucid/static/bootstrap-datetimepicker.min.js b/code/Week03/lucid/static/bootstrap-datetimepicker.min.js deleted file mode 100644 index 197681493..000000000 --- a/code/Week03/lucid/static/bootstrap-datetimepicker.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/* - * https://github.com/simplicitesoftware/bootstrap-datetimepicker - * @version 1.0.6 - * @license Apache-2.0 - */ -!function($){if(!("indexOf"in Array.prototype)){Array.prototype.indexOf=function(find,i){if(i===undefined)i=0;if(i<0)i+=this.length;if(i<0)i=0;for(var n=this.length;i=this.startDate&&d<=this.endDate){this.date=d;this.setValue();this.viewDate=this.date;this.fill()}else{this.element.trigger({type:"outOfRange",date:d,startDate:this.startDate,endDate:this.endDate})}},setFormat:function(format){this.format=DPGlobal.parseFormat(format,this.formatType);var element;if(this.isInput){element=this.element}else if(this.component){element=this.element.find("input")}if(element&&element.val()){this.setValue()}},setValue:function(){var formatted=this.getFormattedDate();if(!this.isInput){if(this.component)this.element.find("input").val(formatted);this.element.data("date",formatted)}else{this.element.val(formatted)}if(this.linkField)$("#"+this.linkField).val(this.getFormattedDate(this.linkFormat))},getFormattedDate:function(format){if(format==undefined)format=this.format;return DPGlobal.formatDate(this.date,format,this.language,this.formatType)},setInitialDate:function(initialDate){this.initialDate=initialDate||new Date;this.update();this.updateNavArrows()},setStartDate:function(startDate){this.startDate=startDate||-Infinity;if(this.startDate!==-Infinity)this.startDate=DPGlobal.parseDate(this.startDate,this.format,this.language,this.formatType);this.update();this.updateNavArrows()},setEndDate:function(endDate){this.endDate=endDate||Infinity;if(this.endDate!==Infinity)this.endDate=DPGlobal.parseDate(this.endDate,this.format,this.language,this.formatType);this.update();this.updateNavArrows()},setDaysOfWeekDisabled:function(daysOfWeekDisabled){this.daysOfWeekDisabled=daysOfWeekDisabled||[];if(!$.isArray(this.daysOfWeekDisabled))this.daysOfWeekDisabled=this.daysOfWeekDisabled.split(/,\s*/);this.daysOfWeekDisabled=$.map(this.daysOfWeekDisabled,function(d){return parseInt(d,10)});this.update();this.updateNavArrows()},setMinutesDisabled:function(minutesDisabled){this.minutesDisabled=minutesDisabled||[];if(!$.isArray(this.minutesDisabled))this.minutesDisabled=this.minutesDisabled.split(/,\s*/);this.minutesDisabled=$.map(this.minutesDisabled,function(d){return parseInt(d,10)});this.update();this.updateNavArrows()},setHoursDisabled:function(hoursDisabled){this.hoursDisabled=hoursDisabled||[];if(!$.isArray(this.hoursDisabled))this.hoursDisabled=this.hoursDisabled.split(/,\s*/);this.hoursDisabled=$.map(this.hoursDisabled,function(d){return parseInt(d,10)});this.update();this.updateNavArrows()},place:function(){if(this.isInline)return;if(this.picker.css("position")=="fixed")return;if(!this.zIndex){var index_highest=1e4;this.zIndex=index_highest+10}var offset,top,left,containerOffset;if(this.container instanceof $){containerOffset=this.container.offset()}else{containerOffset=$(this.container).offset()}if(this.component){offset=this.component.offset();left=offset.left;if(this.pickerPosition=="bottom-left"||this.pickerPosition=="top-left")left+=this.component.outerWidth()-this.picker.outerWidth()}else{offset=this.element.offset();left=offset.left}var bodyWidth=window.innerWidth||document.body.clientWidth;if(left+220>bodyWidth)left=bodyWidth-220;if(this.pickerPosition=="top-left"||this.pickerPosition=="top-right")top=offset.top-this.picker.outerHeight();else top=offset.top+this.height;top=top-containerOffset.top;left=left-containerOffset.left;this.picker.css({top:top,left:left,zIndex:this.zIndex})},update:function(){var date,fromArgs=false;if(arguments&&arguments.length&&(typeof arguments[0]==="string"||arguments[0]instanceof Date)){date=arguments[0];fromArgs=true}else{date=(this.isInput?this.element.val():this.element.find("input").val())||this.element.data("date")||this.initialDate;if(typeof date=="string"||date instanceof String)date=date.replace(/^\s+|\s+$/g,"")}if(!date){date=new Date;fromArgs=false}this.date=DPGlobal.parseDate(date,this.format,this.language,this.formatType);if(fromArgs)this.setValue();if(this.datethis.endDate){this.viewDate=new Date(this.endDate)}else{this.viewDate=new Date(this.date)}this.fill()},fillDow:function(){var dowCnt=this.weekStart,html="";while(dowCnt'+dates[this.language].daysMin[dowCnt++%7]+""}html+="";this.picker.find(".datetimepicker-days thead").append(html)},fillMonths:function(){var html="",i=0;while(i<12){html+=''+dates[this.language].monthsShort[i++]+""}this.picker.find(".datetimepicker-months td").html(html)},fill:function(){if(this.date==null||this.viewDate==null){return}var d=new Date(this.viewDate),year=d.getUTCFullYear(),month=d.getUTCMonth(),dayMonth=d.getUTCDate(),hours=d.getUTCHours(),minutes=d.getUTCMinutes(),startYear=this.startDate!==-Infinity?this.startDate.getUTCFullYear():-Infinity,startMonth=this.startDate!==-Infinity?this.startDate.getUTCMonth():-Infinity,endYear=this.endDate!==Infinity?this.endDate.getUTCFullYear():Infinity,endMonth=this.endDate!==Infinity?this.endDate.getUTCMonth():Infinity,currentDate=new UTCDate(this.date.getUTCFullYear(),this.date.getUTCMonth(),this.date.getUTCDate()).valueOf(),today=new Date;this.picker.find(".datetimepicker-days thead th:eq(1)").text(dates[this.language].months[month]+" "+year);if(this.formatViewType=="time"){var formatted=this.getFormattedDate();this.picker.find(".datetimepicker-hours thead th:eq(1)").text(formatted);this.picker.find(".datetimepicker-minutes thead th:eq(1)").text(formatted)}else{this.picker.find(".datetimepicker-hours thead th:eq(1)").text(dayMonth+" "+dates[this.language].months[month]+" "+year);this.picker.find(".datetimepicker-minutes thead th:eq(1)").text(dayMonth+" "+dates[this.language].months[month]+" "+year)}this.picker.find("tfoot th.today").text(dates[this.language].today).toggle(this.todayBtn!==false);this.updateNavArrows();this.fillMonths();var prevMonth=UTCDate(year,month-1,28,0,0,0,0),day=DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(),prevMonth.getUTCMonth());prevMonth.setUTCDate(day);prevMonth.setUTCDate(day-(prevMonth.getUTCDay()-this.weekStart+7)%7);var nextMonth=new Date(prevMonth);nextMonth.setUTCDate(nextMonth.getUTCDate()+42);nextMonth=nextMonth.valueOf();var html=[];var clsName;while(prevMonth.valueOf()")}clsName="";if(prevMonth.getUTCFullYear()year||prevMonth.getUTCFullYear()==year&&prevMonth.getUTCMonth()>month){clsName+=" new"}if(this.todayHighlight&&prevMonth.getUTCFullYear()==today.getFullYear()&&prevMonth.getUTCMonth()==today.getMonth()&&prevMonth.getUTCDate()==today.getDate()){clsName+=" today"}if(prevMonth.valueOf()==currentDate){clsName+=" active"}if(prevMonth.valueOf()+864e5<=this.startDate||prevMonth.valueOf()>this.endDate||$.inArray(prevMonth.getUTCDay(),this.daysOfWeekDisabled)!==-1){clsName+=" disabled"}html.push(''+prevMonth.getUTCDate()+"");if(prevMonth.getUTCDay()==this.weekEnd){html.push("")}prevMonth.setUTCDate(prevMonth.getUTCDate()+1)}this.picker.find(".datetimepicker-days tbody").empty().append(html.join(""));html=[];var txt="",meridian="",meridianOld="";var hoursDisabled=this.hoursDisabled||[];for(var i=0;i<24;i++){if(hoursDisabled.indexOf(i)!==-1)continue;var actual=UTCDate(year,month,dayMonth,i);clsName="";if(actual.valueOf()+36e5<=this.startDate||actual.valueOf()>this.endDate){clsName+=" disabled"}else if(hours==i){clsName+=" active"}if(this.showMeridian&&dates[this.language].meridiem.length==2){meridian=i<12?dates[this.language].meridiem[0]:dates[this.language].meridiem[1];if(meridian!=meridianOld){if(meridianOld!=""){html.push("")}html.push('
'+meridian.toUpperCase()+"")}meridianOld=meridian;txt=i%12?i%12:12;html.push(''+txt+"");if(i==23){html.push("
")}}else{txt=i+":00";html.push(''+txt+"")}}this.picker.find(".datetimepicker-hours td").html(html.join(""));html=[];txt="",meridian="",meridianOld="";var minutesDisabled=this.minutesDisabled||[];for(var i=0;i<60;i+=this.minuteStep){if(minutesDisabled.indexOf(i)!==-1)continue;var actual=UTCDate(year,month,dayMonth,hours,i,0);clsName="";if(actual.valueOf()this.endDate){clsName+=" disabled"}else if(Math.floor(minutes/this.minuteStep)==Math.floor(i/this.minuteStep)){clsName+=" active"}if(this.showMeridian&&dates[this.language].meridiem.length==2){meridian=hours<12?dates[this.language].meridiem[0]:dates[this.language].meridiem[1];if(meridian!=meridianOld){if(meridianOld!=""){html.push("")}html.push('
'+meridian.toUpperCase()+"")}meridianOld=meridian;txt=hours%12?hours%12:12;html.push(''+txt+":"+(i<10?"0"+i:i)+"");if(i==59){html.push("
")}}else{txt=i+":00";html.push(''+hours+":"+(i<10?"0"+i:i)+"")}}this.picker.find(".datetimepicker-minutes td").html(html.join(""));var currentYear=this.date.getUTCFullYear();var months=this.picker.find(".datetimepicker-months").find("th:eq(1)").text(year).end().find(".month").removeClass("active");if(currentYear==year){months.eq(this.date.getUTCMonth()).addClass("active")}if(yearendYear){months.addClass("disabled")}if(year==startYear){months.slice(0,startMonth).addClass("disabled")}if(year==endYear){months.slice(endMonth+1).addClass("disabled")}html="";year=parseInt(year/10,10)*10;var yearCont=this.picker.find(".datetimepicker-years").find("th:eq(1)").text(year+"-"+(year+9)).end().find("td");year-=1;for(var i=-1;i<11;i++){html+='endYear?" disabled":"")+'">'+year+"";year+=1}yearCont.html(html);this.place()},updateNavArrows:function(){var d=new Date(this.viewDate),year=d.getUTCFullYear(),month=d.getUTCMonth(),day=d.getUTCDate(),hour=d.getUTCHours();switch(this.viewMode){case 0:if(this.startDate!==-Infinity&&year<=this.startDate.getUTCFullYear()&&month<=this.startDate.getUTCMonth()&&day<=this.startDate.getUTCDate()&&hour<=this.startDate.getUTCHours()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(this.endDate!==Infinity&&year>=this.endDate.getUTCFullYear()&&month>=this.endDate.getUTCMonth()&&day>=this.endDate.getUTCDate()&&hour>=this.endDate.getUTCHours()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break;case 1:if(this.startDate!==-Infinity&&year<=this.startDate.getUTCFullYear()&&month<=this.startDate.getUTCMonth()&&day<=this.startDate.getUTCDate()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(this.endDate!==Infinity&&year>=this.endDate.getUTCFullYear()&&month>=this.endDate.getUTCMonth()&&day>=this.endDate.getUTCDate()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break;case 2:if(this.startDate!==-Infinity&&year<=this.startDate.getUTCFullYear()&&month<=this.startDate.getUTCMonth()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(this.endDate!==Infinity&&year>=this.endDate.getUTCFullYear()&&month>=this.endDate.getUTCMonth()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break;case 3:case 4:if(this.startDate!==-Infinity&&year<=this.startDate.getUTCFullYear()){this.picker.find(".prev").css({visibility:"hidden"})}else{this.picker.find(".prev").css({visibility:"visible"})}if(this.endDate!==Infinity&&year>=this.endDate.getUTCFullYear()){this.picker.find(".next").css({visibility:"hidden"})}else{this.picker.find(".next").css({visibility:"visible"})}break}},mousewheel:function(e){e.preventDefault();e.stopPropagation();if(this.wheelPause)return;this.wheelPause=true;var originalEvent=e.originalEvent;var delta=originalEvent.wheelDelta;var mode=delta>0?1:delta===0?0:-1;if(this.wheelViewModeNavigationInverseDirection)mode=-mode;this.showMode(mode);setTimeout($.proxy(function(){this.wheelPause=false},this),this.wheelViewModeNavigationDelay)},click:function(e){e.stopPropagation();e.preventDefault();var target=$(e.target).closest("span, td, th, legend");if(target.is("."+this.icontype)){target=$(target).parent().closest("span, td, th, legend")}if(target.length==1){if(target.is(".disabled")){this.element.trigger({type:"outOfRange",date:this.viewDate,startDate:this.startDate,endDate:this.endDate});return}switch(target[0].nodeName.toLowerCase()){case"th":switch(target[0].className){case"switch":this.showMode(1);break;case"prev":case"next":var dir=DPGlobal.modes[this.viewMode].navStep*(target[0].className=="prev"?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveHour(this.viewDate,dir);break;case 1:this.viewDate=this.moveDate(this.viewDate,dir);break;case 2:this.viewDate=this.moveMonth(this.viewDate,dir);break;case 3:case 4:this.viewDate=this.moveYear(this.viewDate,dir);break}this.fill();this.element.trigger({type:target[0].className+":"+this.convertViewModeText(this.viewMode),date:this.viewDate,startDate:this.startDate,endDate:this.endDate});break;case"today":var date=new Date;date=UTCDate(date.getFullYear(),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds(),0);if(datethis.endDate)date=this.endDate;this.viewMode=this.startViewMode;this.showMode(0);this._setDate(date);this.fill();if(this.autoclose){this.hide()}break}break;case"span":if(!target.is(".disabled")){var year=this.viewDate.getUTCFullYear(),month=this.viewDate.getUTCMonth(),day=this.viewDate.getUTCDate(),hours=this.viewDate.getUTCHours(),minutes=this.viewDate.getUTCMinutes(),seconds=this.viewDate.getUTCSeconds();if(target.is(".month")){this.viewDate.setUTCDate(1);month=target.parent().find("span").index(target);day=this.viewDate.getUTCDate();this.viewDate.setUTCMonth(month);this.element.trigger({type:"changeMonth",date:this.viewDate});if(this.viewSelect>=3){this._setDate(UTCDate(year,month,day,hours,minutes,seconds,0))}}else if(target.is(".year")){this.viewDate.setUTCDate(1);year=parseInt(target.text(),10)||0;this.viewDate.setUTCFullYear(year);this.element.trigger({type:"changeYear",date:this.viewDate});if(this.viewSelect>=4){this._setDate(UTCDate(year,month,day,hours,minutes,seconds,0))}}else if(target.is(".hour")){hours=parseInt(target.text(),10)||0;if(target.hasClass("hour_am")||target.hasClass("hour_pm")){if(hours==12&&target.hasClass("hour_am")){hours=0}else if(hours!=12&&target.hasClass("hour_pm")){hours+=12}}this.viewDate.setUTCHours(hours);this.element.trigger({type:"changeHour",date:this.viewDate});if(this.viewSelect>=1){this._setDate(UTCDate(year,month,day,hours,minutes,seconds,0))}}else if(target.is(".minute")){minutes=parseInt(target.text().substr(target.text().indexOf(":")+1),10)||0;this.viewDate.setUTCMinutes(minutes);this.element.trigger({type:"changeMinute",date:this.viewDate});if(this.viewSelect>=0){this._setDate(UTCDate(year,month,day,hours,minutes,seconds,0))}}if(this.viewMode!=0){var oldViewMode=this.viewMode;this.showMode(-1);this.fill();if(oldViewMode==this.viewMode&&this.autoclose){this.hide()}}else{this.fill();if(this.autoclose){this.hide()}}}break;case"td":if(target.is(".day")&&!target.is(".disabled")){var day=parseInt(target.text(),10)||1;var year=this.viewDate.getUTCFullYear(),month=this.viewDate.getUTCMonth(),hours=this.viewDate.getUTCHours(),minutes=this.viewDate.getUTCMinutes(),seconds=this.viewDate.getUTCSeconds();if(target.is(".old")){if(month===0){month=11;year-=1}else{month-=1}}else if(target.is(".new")){if(month==11){month=0;year+=1}else{month+=1}}this.viewDate.setUTCFullYear(year);this.viewDate.setUTCMonth(month,day);this.element.trigger({type:"changeDay",date:this.viewDate});if(this.viewSelect>=2){this._setDate(UTCDate(year,month,day,hours,minutes,seconds,0))}}var oldViewMode=this.viewMode;this.showMode(-1);this.fill();if(oldViewMode==this.viewMode&&this.autoclose){this.hide()}break}}},_setDate:function(date,which){if(!which||which=="date")this.date=date;if(!which||which=="view")this.viewDate=date;this.fill();this.setValue();var element;if(this.isInput){element=this.element}else if(this.component){element=this.element.find("input")}if(element){element.change();if(this.autoclose&&(!which||which=="date")){}}this.element.trigger({type:"changeDate",date:this.date});if(date==null)this.date=this.viewDate},moveMinute:function(date,dir){if(!dir)return date;var new_date=new Date(date.valueOf());new_date.setUTCMinutes(new_date.getUTCMinutes()+dir*this.minuteStep);return new_date},moveHour:function(date,dir){if(!dir)return date;var new_date=new Date(date.valueOf());new_date.setUTCHours(new_date.getUTCHours()+dir);return new_date},moveDate:function(date,dir){if(!dir)return date;var new_date=new Date(date.valueOf());new_date.setUTCDate(new_date.getUTCDate()+dir);return new_date},moveMonth:function(date,dir){if(!dir)return date;var new_date=new Date(date.valueOf()),day=new_date.getUTCDate(),month=new_date.getUTCMonth(),mag=Math.abs(dir),new_month,test;dir=dir>0?1:-1;if(mag==1){test=dir==-1?function(){return new_date.getUTCMonth()==month}:function(){return new_date.getUTCMonth()!=new_month};new_month=month+dir;new_date.setUTCMonth(new_month);if(new_month<0||new_month>11)new_month=(new_month+12)%12}else{for(var i=0;i=this.startDate&&date<=this.endDate},keydown:function(e){if(this.picker.is(":not(:visible)")){if(e.keyCode==27)this.show();return}var dateChanged=false,dir,day,month,newDate,newViewDate;switch(e.keyCode){case 27:this.hide();e.preventDefault();break;case 37:case 39:if(!this.keyboardNavigation)break;dir=e.keyCode==37?-1:1;viewMode=this.viewMode;if(e.ctrlKey){viewMode+=2}else if(e.shiftKey){viewMode+=1}if(viewMode==4){newDate=this.moveYear(this.date,dir);newViewDate=this.moveYear(this.viewDate,dir)}else if(viewMode==3){newDate=this.moveMonth(this.date,dir);newViewDate=this.moveMonth(this.viewDate,dir)}else if(viewMode==2){newDate=this.moveDate(this.date,dir);newViewDate=this.moveDate(this.viewDate,dir)}else if(viewMode==1){newDate=this.moveHour(this.date,dir);newViewDate=this.moveHour(this.viewDate,dir)}else if(viewMode==0){newDate=this.moveMinute(this.date,dir);newViewDate=this.moveMinute(this.viewDate,dir)}if(this.dateWithinRange(newDate)){this.date=newDate;this.viewDate=newViewDate;this.setValue();this.update();e.preventDefault();dateChanged=true}break;case 38:case 40:if(!this.keyboardNavigation)break;dir=e.keyCode==38?-1:1;viewMode=this.viewMode;if(e.ctrlKey){viewMode+=2}else if(e.shiftKey){viewMode+=1}if(viewMode==4){newDate=this.moveYear(this.date,dir);newViewDate=this.moveYear(this.viewDate,dir)}else if(viewMode==3){newDate=this.moveMonth(this.date,dir);newViewDate=this.moveMonth(this.viewDate,dir)}else if(viewMode==2){newDate=this.moveDate(this.date,dir*7);newViewDate=this.moveDate(this.viewDate,dir*7)}else if(viewMode==1){if(this.showMeridian){newDate=this.moveHour(this.date,dir*6);newViewDate=this.moveHour(this.viewDate,dir*6)}else{newDate=this.moveHour(this.date,dir*4);newViewDate=this.moveHour(this.viewDate,dir*4)}}else if(viewMode==0){newDate=this.moveMinute(this.date,dir*4);newViewDate=this.moveMinute(this.viewDate,dir*4)}if(this.dateWithinRange(newDate)){this.date=newDate;this.viewDate=newViewDate;this.setValue();this.update();e.preventDefault();dateChanged=true}break;case 13:if(this.viewMode!=0){var oldViewMode=this.viewMode;this.showMode(-1);this.fill();if(oldViewMode==this.viewMode&&this.autoclose){this.hide()}}else{this.fill();if(this.autoclose){this.hide()}}e.preventDefault();break;case 9:this.hide();break}if(dateChanged){var element;if(this.isInput){element=this.element}else if(this.component){element=this.element.find("input")}if(element){element.change()}this.element.trigger({type:"changeDate",date:this.date})}},showMode:function(dir){if(dir){var newViewMode=Math.max(0,Math.min(DPGlobal.modes.length-1,this.viewMode+dir));if(newViewMode>=this.minView&&newViewMode<=this.maxView){this.element.trigger({type:"changeMode",date:this.viewDate,oldViewMode:this.viewMode,newViewMode:newViewMode});this.viewMode=newViewMode}}this.picker.find(">div").hide().filter(".datetimepicker-"+DPGlobal.modes[this.viewMode].clsName).css("display","block");this.updateNavArrows()},reset:function(e){this._setDate(null,"date")},convertViewModeText:function(viewMode){switch(viewMode){case 4:return"decade";case 3:return"year";case 2:return"month";case 1:return"day";case 0:return"hour"}}};var old=$.fn.datetimepicker;$.fn.datetimepicker=function(option){var args=Array.apply(null,arguments);args.shift();var internal_return;this.each(function(){var $this=$(this),data=$this.data("datetimepicker"),options=typeof option=="object"&&option;if(!data){$this.data("datetimepicker",data=new Datetimepicker(this,$.extend({},$.fn.datetimepicker.defaults,options)))}if(typeof option=="string"&&typeof data[option]=="function"){internal_return=data[option].apply(data,args);if(internal_return!==undefined){return false}}});if(internal_return!==undefined)return internal_return;else return this};$.fn.datetimepicker.defaults={};$.fn.datetimepicker.Constructor=Datetimepicker;var dates=$.fn.datetimepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],meridiem:["am","pm"],suffix:["st","nd","rd","th"],today:"Today"}};var DPGlobal={modes:[{clsName:"minutes",navFnc:"Hours",navStep:1},{clsName:"hours",navFnc:"Date",navStep:1},{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(year){return year%4===0&&year%100!==0||year%400===0},getDaysInMonth:function(year,month){return[31,DPGlobal.isLeapYear(year)?29:28,31,30,31,30,31,31,30,31,30,31][month]},getDefaultFormat:function(type,field){if(type=="standard"){if(field=="input")return"yyyy-mm-dd hh:ii";else return"yyyy-mm-dd hh:ii:ss"}else if(type=="php"){if(field=="input")return"Y-m-d H:i";else return"Y-m-d H:i:s"}else{throw new Error("Invalid format type.")}},validParts:function(type){if(type=="standard"){return/hh?|HH?|p|P|ii?|ss?|dd?|DD?|mm?|MM?|yy(?:yy)?/g}else if(type=="php"){return/[dDjlNwzFmMnStyYaABgGhHis]/g}else{throw new Error("Invalid format type.")}},nonpunctuation:/[^ -\/:-@\[-`{-~\t\n\rTZ]+/g,parseFormat:function(format,type){var separators=format.replace(this.validParts(type),"\0").split("\0"),parts=format.match(this.validParts(type));if(!separators||!separators.length||!parts||parts.length==0){throw new Error("Invalid date format.")}return{separators:separators,parts:parts}},parseDate:function(date,format,language,type){if(date instanceof Date){var dateUTC=new Date(date.valueOf()-date.getTimezoneOffset()*6e4);dateUTC.setMilliseconds(0);return dateUTC}if(/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(date)){format=this.parseFormat("yyyy-mm-dd",type)}if(/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}$/.test(date)){format=this.parseFormat("yyyy-mm-dd hh:ii",type)}if(/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}\:\d{1,2}[Z]{0,1}$/.test(date)){format=this.parseFormat("yyyy-mm-dd hh:ii:ss",type)}if(/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(date)){var part_re=/([-+]\d+)([dmwy])/,parts=date.match(/([-+]\d+)([dmwy])/g),part,dir;date=new Date;for(var i=0;i"+''+''+''+"",contTemplate:'',footTemplate:''};DPGlobal.template='
'+'
'+''+DPGlobal.headTemplate+DPGlobal.contTemplate+DPGlobal.footTemplate+"
"+"
"+'
'+''+DPGlobal.headTemplate+DPGlobal.contTemplate+DPGlobal.footTemplate+"
"+"
"+'
'+''+DPGlobal.headTemplate+""+DPGlobal.footTemplate+"
"+"
"+'
'+''+DPGlobal.headTemplate+DPGlobal.contTemplate+DPGlobal.footTemplate+"
"+"
"+'
'+''+DPGlobal.headTemplate+DPGlobal.contTemplate+DPGlobal.footTemplate+"
"+"
";$.fn.datetimepicker.DPGlobal=DPGlobal;$.fn.datetimepicker.noConflict=function(){$.fn.datetimepicker=old;return this};$(document).on("focus.datetimepicker.data-api click.datetimepicker.data-api",'[data-provide="datetimepicker"]',function(e){var $this=$(this);if($this.data("datetimepicker"))return;e.preventDefault();$this.datetimepicker("show")});$(function(){$('[data-provide="datetimepicker-inline"]').datetimepicker()})}(window.jQuery); \ No newline at end of file diff --git a/code/Week03/lucid/webpack.config.js b/code/Week03/lucid/webpack.config.js index f358013d1..5b4d40623 100644 --- a/code/Week03/lucid/webpack.config.js +++ b/code/Week03/lucid/webpack.config.js @@ -1,6 +1,9 @@ const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); +const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); +const { ProvidePlugin } = require('webpack'); +const dotenv = require('dotenv-webpack'); module.exports = { experiments: { @@ -11,22 +14,23 @@ module.exports = { entry: './src/index.js', devtool: 'inline-source-map', devServer: { - static: './dist', + static: path.join(__dirname, 'dist'), port: 9081, + hot: true }, plugins: [ new HtmlWebpackPlugin({ title: 'Vesting', template: './src/index.html' }), - new CopyWebpackPlugin({ - patterns: [{ - from: 'static' - }] - }) + new NodePolyfillPlugin(), + new ProvidePlugin({ + process: 'process/browser.js' + }), + new dotenv(), ], output: { - filename: 'main.js', + filename: 'index.js', path: path.resolve(__dirname, 'dist'), clean: true, }, @@ -34,14 +38,28 @@ module.exports = { rules: [ { test: /\.css$/, - use: ['style-loader', 'css-loader'] + use: [ + { loader: 'style-loader' }, + { loader: 'css-loader', options: { importLoaders: 1 } }, + { + loader: 'postcss-loader', options: { + postcssOptions: { + plugins: () => [ + require('autoprefixer') + ] + } + } + }, + { loader: 'sass-loader' } + ] } ], }, resolve: { alias: { 'jquery': path.join(__dirname, 'node_modules/jquery/src/jquery') - } + }, + extensions: ['.tsx', '.ts', '.js', '.jsx'], } };