Rohan Sircar
3 years ago
25 changed files with 25211 additions and 155 deletions
-
3assets/app/index.html
-
26build.sbt
-
4src/main/scala/outwatch/util/MonixWebSocket.scala
-
4src/main/scala/outwatch/util/WebSocket2.scala
-
143src/main/scala/outwatchapp/MainApp.scala
-
0src/main/scala/outwatchapp/components/Chartjs.scala
-
33src/main/scala/outwatchapp/components/ChartjsDemo.scala
-
141src/main/scala/outwatchapp/components/DatatablesDemo.scala
-
492src/main/scala/outwatchapp/components/ExampleDataTable.scala
-
2src/main/scala/outwatchapp/components/Fusejs.scala
-
6src/main/scala/outwatchapp/components/RequestDemo.scala
-
104src/main/scala/outwatchapp/components/SweetAlertDemo.scala
-
30src/main/scala/outwatchapp/implicits/package.scala
-
65src/main/scala/outwatchapp/pages/HomePage.scala
-
34src/main/scala/outwatchapp/util/ParallelDemo.scala
-
14src/main/scala/outwatchapp/util/SubtleCryptoTest.scala
-
44src/main/scala/outwatchapp/util/WorkerTest.scala
-
77src/main/scala/outwatchapp/util/reactive/DedicatedWorker.scala
-
16src/main/scala/outwatchapp/util/reactive/Exceptions.scala
-
165src/main/scala/outwatchapp/util/reactive/ReconnectingWebSocket.scala
-
94src/main/scala/outwatchapp/util/reactive/WebSocket.scala
-
111src/main/scala/outwatchapp/util/reactive/WebWorker.scala
-
1src/main/scala/outwatchapp/util/reactive/package.scala
-
23690src/main/scala/outwatchapp/util/reactive/store/test.css
-
67yarn.lock
@ -0,0 +1,141 @@ |
|||||
|
package outwatchapp.components |
||||
|
|
||||
|
import scala.annotation.unused |
||||
|
import scala.scalajs.js.annotation.JSExportAll |
||||
|
import scala.scalajs.js.annotation.JSImport |
||||
|
|
||||
|
import colibri.ext.monix._ |
||||
|
import monix.bio.Task |
||||
|
import monix.eval.Coeval |
||||
|
import monix.execution.Cancelable |
||||
|
import org.scalajs.dom.raw.HTMLElement |
||||
|
import outwatch.ManagedSubscriptions.managedElement |
||||
|
import typings.datatablesNet.DataTables.ColumnSettings |
||||
|
import typings.datatablesNet.DataTables.FunctionColumnRender |
||||
|
import typings.datatablesNet.DataTables.Settings |
||||
|
import typings.datatablesNet.datatablesNetRequire |
||||
|
import typings.jquery.JQuery_ |
||||
|
import typings.jquery.{mod => $} |
||||
|
|
||||
|
import scalajs.js |
||||
|
|
||||
|
@js.native |
||||
|
@JSImport( |
||||
|
"datatables.net-bs4/css/dataTables.bootstrap4.min.css", |
||||
|
JSImport.Namespace |
||||
|
) |
||||
|
object DataTablesBs4Css extends js.Object |
||||
|
@js.native |
||||
|
@JSImport( |
||||
|
"datatables.net-bs4/js/dataTables.bootstrap4.min.js", |
||||
|
JSImport.Namespace |
||||
|
) |
||||
|
object DataTablesBs4Js extends js.Object |
||||
|
|
||||
|
object DatatablesDemo { |
||||
|
implicit def isJQueryDT[T](x: JQuery_[T]): typings.datatablesNet.JQuery = |
||||
|
x.asInstanceOf[typings.datatablesNet.JQuery] |
||||
|
|
||||
|
datatablesNetRequire |
||||
|
DataTablesBs4Css |
||||
|
DataTablesBs4Js |
||||
|
|
||||
|
@unused |
||||
|
private def _test(tableElement: HTMLElement) = $(tableElement) |
||||
|
.DataTable( |
||||
|
Settings().setColumnsVarargs( |
||||
|
ColumnSettings().setData("name").setRender(nameRenderFn) |
||||
|
) |
||||
|
) |
||||
|
.destroy() |
||||
|
|
||||
|
val nameRenderFn: FunctionColumnRender = (_data, tpe, row, d) => { |
||||
|
if (tpe.toString == "display") println("Matched") |
||||
|
else println("Did not match") |
||||
|
// this can be done with scalatags instead |
||||
|
s""" |
||||
|
<div>${_data.toString.toUpperCase}</div> |
||||
|
""" |
||||
|
// with scalatags |
||||
|
// import scalatags.Text.all._ |
||||
|
// div(_data.toString.toUpperCase).render |
||||
|
} |
||||
|
|
||||
|
@JSExportAll |
||||
|
case class TestData( |
||||
|
name: String, |
||||
|
position: String, |
||||
|
location: String, |
||||
|
id: String, |
||||
|
date: String, |
||||
|
salary: String |
||||
|
) |
||||
|
|
||||
|
val dataset = js |
||||
|
.Array( |
||||
|
TestData( |
||||
|
"Tiger Nixon", |
||||
|
"System Architect", |
||||
|
"Edinburgh", |
||||
|
"5421", |
||||
|
"2011/04/25", |
||||
|
"$320,800" |
||||
|
), |
||||
|
TestData( |
||||
|
"Garrett Winters", |
||||
|
"Accountant", |
||||
|
"Tokyo", |
||||
|
"8422", |
||||
|
"2011/07/25", |
||||
|
"$170,750" |
||||
|
), |
||||
|
TestData( |
||||
|
"Ashton Cox", |
||||
|
"Junior Technical Author", |
||||
|
"San Francisco", |
||||
|
"1562", |
||||
|
"2009/01/12", |
||||
|
"$86,000" |
||||
|
), |
||||
|
TestData( |
||||
|
"Cedric Kelly", |
||||
|
"Senior Javascript Developer", |
||||
|
"Edinburgh", |
||||
|
"6224", |
||||
|
"2012/03/29", |
||||
|
"$433,060" |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
// $(document).ready(_ => $(tableElement).DataTable()) |
||||
|
|
||||
|
def apply() = { |
||||
|
import outwatch.dsl._ |
||||
|
Coeval( |
||||
|
div( |
||||
|
table(idAttr := "myTable")(managedElement { el => |
||||
|
val dt = $(el).DataTable( |
||||
|
Settings() |
||||
|
.setColumnsVarargs( |
||||
|
ColumnSettings() |
||||
|
.setTitle("Name") |
||||
|
.setData("name") |
||||
|
.setRender(nameRenderFn), |
||||
|
ColumnSettings().setData("position"), |
||||
|
ColumnSettings().setData("location"), |
||||
|
ColumnSettings().setData("id"), |
||||
|
ColumnSettings().setData("date"), |
||||
|
ColumnSettings().setData("salary") |
||||
|
) |
||||
|
.setDom("Blfrtip") |
||||
|
.setData(dataset) |
||||
|
) |
||||
|
Cancelable { () => |
||||
|
println("Destroying") |
||||
|
dt.destroy() |
||||
|
} |
||||
|
}) |
||||
|
) |
||||
|
).to[Task] |
||||
|
} |
||||
|
} |
@ -0,0 +1,492 @@ |
|||||
|
package outwatchapp.components |
||||
|
|
||||
|
import outwatch.dsl._ |
||||
|
|
||||
|
object Table { |
||||
|
val value = table( |
||||
|
idAttr := "myTable", |
||||
|
cls := "display", |
||||
|
cls := "table", |
||||
|
// style := "width: 100%", |
||||
|
width := "100%", |
||||
|
// style("width") := "100%", |
||||
|
thead( |
||||
|
tr( |
||||
|
th("Name"), |
||||
|
th("Position"), |
||||
|
th("Office"), |
||||
|
th("Age"), |
||||
|
th("Start date"), |
||||
|
th("Salary") |
||||
|
) |
||||
|
), |
||||
|
tbody( |
||||
|
tr( |
||||
|
td("Tiger Nixon"), |
||||
|
td("System Architect"), |
||||
|
td("Edinburgh"), |
||||
|
td("61"), |
||||
|
td("2011/04/25"), |
||||
|
td("$320,800") |
||||
|
), |
||||
|
tr( |
||||
|
td("Garrett Winters"), |
||||
|
td("Accountant"), |
||||
|
td("Tokyo"), |
||||
|
td("63"), |
||||
|
td("2011/07/25"), |
||||
|
td("$170,750") |
||||
|
), |
||||
|
tr( |
||||
|
td("Ashton Cox"), |
||||
|
td("Junior Technical Author"), |
||||
|
td("San Francisco"), |
||||
|
td("66"), |
||||
|
td("2009/01/12"), |
||||
|
td("$86,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Cedric Kelly"), |
||||
|
td("Senior Javascript Developer"), |
||||
|
td("Edinburgh"), |
||||
|
td("22"), |
||||
|
td("2012/03/29"), |
||||
|
td("$433,060") |
||||
|
), |
||||
|
tr( |
||||
|
td("Airi Satou"), |
||||
|
td("Accountant"), |
||||
|
td("Tokyo"), |
||||
|
td("33"), |
||||
|
td("2008/11/28"), |
||||
|
td("$162,700") |
||||
|
), |
||||
|
tr( |
||||
|
td("Brielle Williamson"), |
||||
|
td("Integration Specialist"), |
||||
|
td("New York"), |
||||
|
td("61"), |
||||
|
td("2012/12/02"), |
||||
|
td("$372,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Herrod Chandler"), |
||||
|
td("Sales Assistant"), |
||||
|
td("San Francisco"), |
||||
|
td("59"), |
||||
|
td("2012/08/06"), |
||||
|
td("$137,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Rhona Davidson"), |
||||
|
td("Integration Specialist"), |
||||
|
td("Tokyo"), |
||||
|
td("55"), |
||||
|
td("2010/10/14"), |
||||
|
td("$327,900") |
||||
|
), |
||||
|
tr( |
||||
|
td("Colleen Hurst"), |
||||
|
td("Javascript Developer"), |
||||
|
td("San Francisco"), |
||||
|
td("39"), |
||||
|
td("2009/09/15"), |
||||
|
td("$205,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Sonya Frost"), |
||||
|
td("Software Engineer"), |
||||
|
td("Edinburgh"), |
||||
|
td("23"), |
||||
|
td("2008/12/13"), |
||||
|
td("$103,600") |
||||
|
), |
||||
|
tr( |
||||
|
td("Jena Gaines"), |
||||
|
td("Office Manager"), |
||||
|
td("London"), |
||||
|
td("30"), |
||||
|
td("2008/12/19"), |
||||
|
td("$90,560") |
||||
|
), |
||||
|
tr( |
||||
|
td("Quinn Flynn"), |
||||
|
td("Support Lead"), |
||||
|
td("Edinburgh"), |
||||
|
td("22"), |
||||
|
td("2013/03/03"), |
||||
|
td("$342,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Charde Marshall"), |
||||
|
td("Regional Director"), |
||||
|
td("San Francisco"), |
||||
|
td("36"), |
||||
|
td("2008/10/16"), |
||||
|
td("$470,600") |
||||
|
), |
||||
|
tr( |
||||
|
td("Haley Kennedy"), |
||||
|
td("Senior Marketing Designer"), |
||||
|
td("London"), |
||||
|
td("43"), |
||||
|
td("2012/12/18"), |
||||
|
td("$313,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Tatyana Fitzpatrick"), |
||||
|
td("Regional Director"), |
||||
|
td("London"), |
||||
|
td("19"), |
||||
|
td("2010/03/17"), |
||||
|
td("$385,750") |
||||
|
), |
||||
|
tr( |
||||
|
td("Michael Silva"), |
||||
|
td("Marketing Designer"), |
||||
|
td("London"), |
||||
|
td("66"), |
||||
|
td("2012/11/27"), |
||||
|
td("$198,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Paul Byrd"), |
||||
|
td("Chief Financial Officer (CFO)"), |
||||
|
td("New York"), |
||||
|
td("64"), |
||||
|
td("2010/06/09"), |
||||
|
td("$725,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Gloria Little"), |
||||
|
td("Systems Administrator"), |
||||
|
td("New York"), |
||||
|
td("59"), |
||||
|
td("2009/04/10"), |
||||
|
td("$237,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Bradley Greer"), |
||||
|
td("Software Engineer"), |
||||
|
td("London"), |
||||
|
td("41"), |
||||
|
td("2012/10/13"), |
||||
|
td("$132,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Dai Rios"), |
||||
|
td("Personnel Lead"), |
||||
|
td("Edinburgh"), |
||||
|
td("35"), |
||||
|
td("2012/09/26"), |
||||
|
td("$217,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Jenette Caldwell"), |
||||
|
td("Development Lead"), |
||||
|
td("New York"), |
||||
|
td("30"), |
||||
|
td("2011/09/03"), |
||||
|
td("$345,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Yuri Berry"), |
||||
|
td("Chief Marketing Officer (CMO)"), |
||||
|
td("New York"), |
||||
|
td("40"), |
||||
|
td("2009/06/25"), |
||||
|
td("$675,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Caesar Vance"), |
||||
|
td("Pre-Sales Support"), |
||||
|
td("New York"), |
||||
|
td("21"), |
||||
|
td("2011/12/12"), |
||||
|
td("$106,450") |
||||
|
), |
||||
|
tr( |
||||
|
td("Doris Wilder"), |
||||
|
td("Sales Assistant"), |
||||
|
td("Sydney"), |
||||
|
td("23"), |
||||
|
td("2010/09/20"), |
||||
|
td("$85,600") |
||||
|
), |
||||
|
tr( |
||||
|
td("Angelica Ramos"), |
||||
|
td("Chief Executive Officer (CEO)"), |
||||
|
td("London"), |
||||
|
td("47"), |
||||
|
td("2009/10/09"), |
||||
|
td("$1,200,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Gavin Joyce"), |
||||
|
td("Developer"), |
||||
|
td("Edinburgh"), |
||||
|
td("42"), |
||||
|
td("2010/12/22"), |
||||
|
td("$92,575") |
||||
|
), |
||||
|
tr( |
||||
|
td("Jennifer Chang"), |
||||
|
td("Regional Director"), |
||||
|
td("Singapore"), |
||||
|
td("28"), |
||||
|
td("2010/11/14"), |
||||
|
td("$357,650") |
||||
|
), |
||||
|
tr( |
||||
|
td("Brenden Wagner"), |
||||
|
td("Software Engineer"), |
||||
|
td("San Francisco"), |
||||
|
td("28"), |
||||
|
td("2011/06/07"), |
||||
|
td("$206,850") |
||||
|
), |
||||
|
tr( |
||||
|
td("Fiona Green"), |
||||
|
td("Chief Operating Officer (COO)"), |
||||
|
td("San Francisco"), |
||||
|
td("48"), |
||||
|
td("2010/03/11"), |
||||
|
td("$850,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Shou Itou"), |
||||
|
td("Regional Marketing"), |
||||
|
td("Tokyo"), |
||||
|
td("20"), |
||||
|
td("2011/08/14"), |
||||
|
td("$163,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Michelle House"), |
||||
|
td("Integration Specialist"), |
||||
|
td("Sydney"), |
||||
|
td("37"), |
||||
|
td("2011/06/02"), |
||||
|
td("$95,400") |
||||
|
), |
||||
|
tr( |
||||
|
td("Suki Burks"), |
||||
|
td("Developer"), |
||||
|
td("London"), |
||||
|
td("53"), |
||||
|
td("2009/10/22"), |
||||
|
td("$114,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Prescott Bartlett"), |
||||
|
td("Technical Author"), |
||||
|
td("London"), |
||||
|
td("27"), |
||||
|
td("2011/05/07"), |
||||
|
td("$145,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Gavin Cortez"), |
||||
|
td("Team Leader"), |
||||
|
td("San Francisco"), |
||||
|
td("22"), |
||||
|
td("2008/10/26"), |
||||
|
td("$235,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Martena Mccray"), |
||||
|
td("Post-Sales support"), |
||||
|
td("Edinburgh"), |
||||
|
td("46"), |
||||
|
td("2011/03/09"), |
||||
|
td("$324,050") |
||||
|
), |
||||
|
tr( |
||||
|
td("Unity Butler"), |
||||
|
td("Marketing Designer"), |
||||
|
td("San Francisco"), |
||||
|
td("47"), |
||||
|
td("2009/12/09"), |
||||
|
td("$85,675") |
||||
|
), |
||||
|
tr( |
||||
|
td("Howard Hatfield"), |
||||
|
td("Office Manager"), |
||||
|
td("San Francisco"), |
||||
|
td("51"), |
||||
|
td("2008/12/16"), |
||||
|
td("$164,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Hope Fuentes"), |
||||
|
td("Secretary"), |
||||
|
td("San Francisco"), |
||||
|
td("41"), |
||||
|
td("2010/02/12"), |
||||
|
td("$109,850") |
||||
|
), |
||||
|
tr( |
||||
|
td("Vivian Harrell"), |
||||
|
td("Financial Controller"), |
||||
|
td("San Francisco"), |
||||
|
td("62"), |
||||
|
td("2009/02/14"), |
||||
|
td("$452,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Timothy Mooney"), |
||||
|
td("Office Manager"), |
||||
|
td("London"), |
||||
|
td("37"), |
||||
|
td("2008/12/11"), |
||||
|
td("$136,200") |
||||
|
), |
||||
|
tr( |
||||
|
td("Jackson Bradshaw"), |
||||
|
td("Director"), |
||||
|
td("New York"), |
||||
|
td("65"), |
||||
|
td("2008/09/26"), |
||||
|
td("$645,750") |
||||
|
), |
||||
|
tr( |
||||
|
td("Olivia Liang"), |
||||
|
td("Support Engineer"), |
||||
|
td("Singapore"), |
||||
|
td("64"), |
||||
|
td("2011/02/03"), |
||||
|
td("$234,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Bruno Nash"), |
||||
|
td("Software Engineer"), |
||||
|
td("London"), |
||||
|
td("38"), |
||||
|
td("2011/05/03"), |
||||
|
td("$163,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Sakura Yamamoto"), |
||||
|
td("Support Engineer"), |
||||
|
td("Tokyo"), |
||||
|
td("37"), |
||||
|
td("2009/08/19"), |
||||
|
td("$139,575") |
||||
|
), |
||||
|
tr( |
||||
|
td("Thor Walton"), |
||||
|
td("Developer"), |
||||
|
td("New York"), |
||||
|
td("61"), |
||||
|
td("2013/08/11"), |
||||
|
td("$98,540") |
||||
|
), |
||||
|
tr( |
||||
|
td("Finn Camacho"), |
||||
|
td("Support Engineer"), |
||||
|
td("San Francisco"), |
||||
|
td("47"), |
||||
|
td("2009/07/07"), |
||||
|
td("$87,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Serge Baldwin"), |
||||
|
td("Data Coordinator"), |
||||
|
td("Singapore"), |
||||
|
td("64"), |
||||
|
td("2012/04/09"), |
||||
|
td("$138,575") |
||||
|
), |
||||
|
tr( |
||||
|
td("Zenaida Frank"), |
||||
|
td("Software Engineer"), |
||||
|
td("New York"), |
||||
|
td("63"), |
||||
|
td("2010/01/04"), |
||||
|
td("$125,250") |
||||
|
), |
||||
|
tr( |
||||
|
td("Zorita Serrano"), |
||||
|
td("Software Engineer"), |
||||
|
td("San Francisco"), |
||||
|
td("56"), |
||||
|
td("2012/06/01"), |
||||
|
td("$115,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Jennifer Acosta"), |
||||
|
td("Junior Javascript Developer"), |
||||
|
td("Edinburgh"), |
||||
|
td("43"), |
||||
|
td("2013/02/01"), |
||||
|
td("$75,650") |
||||
|
), |
||||
|
tr( |
||||
|
td("Cara Stevens"), |
||||
|
td("Sales Assistant"), |
||||
|
td("New York"), |
||||
|
td("46"), |
||||
|
td("2011/12/06"), |
||||
|
td("$145,600") |
||||
|
), |
||||
|
tr( |
||||
|
td("Hermione Butler"), |
||||
|
td("Regional Director"), |
||||
|
td("London"), |
||||
|
td("47"), |
||||
|
td("2011/03/21"), |
||||
|
td("$356,250") |
||||
|
), |
||||
|
tr( |
||||
|
td("Lael Greer"), |
||||
|
td("Systems Administrator"), |
||||
|
td("London"), |
||||
|
td("21"), |
||||
|
td("2009/02/27"), |
||||
|
td("$103,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Jonas Alexander"), |
||||
|
td("Developer"), |
||||
|
td("San Francisco"), |
||||
|
td("30"), |
||||
|
td("2010/07/14"), |
||||
|
td("$86,500") |
||||
|
), |
||||
|
tr( |
||||
|
td("Shad Decker"), |
||||
|
td("Regional Director"), |
||||
|
td("Edinburgh"), |
||||
|
td("51"), |
||||
|
td("2008/11/13"), |
||||
|
td("$183,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Michael Bruce"), |
||||
|
td("Javascript Developer"), |
||||
|
td("Singapore"), |
||||
|
td("29"), |
||||
|
td("2011/06/27"), |
||||
|
td("$183,000") |
||||
|
), |
||||
|
tr( |
||||
|
td("Donna Snider"), |
||||
|
td("Customer Support"), |
||||
|
td("New York"), |
||||
|
td("27"), |
||||
|
td("2011/01/25"), |
||||
|
td("$112,000") |
||||
|
) |
||||
|
), |
||||
|
tfoot( |
||||
|
tr( |
||||
|
th("Name"), |
||||
|
th("Position"), |
||||
|
th("Office"), |
||||
|
th("Age"), |
||||
|
th("Start date"), |
||||
|
th("Salary") |
||||
|
) |
||||
|
) |
||||
|
) |
||||
|
} |
@ -1,4 +1,4 @@ |
|||||
package outwatchapp.components.todo |
|
||||
|
package outwatchapp.components |
||||
|
|
||||
import outwatchapp.ui.components.todo.Todo |
import outwatchapp.ui.components.todo.Todo |
||||
import typings.fuseJs.mod.Fuse.IFuseOptions |
import typings.fuseJs.mod.Fuse.IFuseOptions |
@ -0,0 +1,104 @@ |
|||||
|
package outwatchapp.components |
||||
|
import scala.scalajs.js.annotation.JSImport |
||||
|
|
||||
|
import monix.bio.Task |
||||
|
import outwatchapp.implicits._ |
||||
|
import typings.sweetalert2.mod.SweetAlertIcon |
||||
|
import typings.sweetalert2.mod.SweetAlertOptions |
||||
|
import typings.sweetalert2.mod.SweetAlertPosition |
||||
|
|
||||
|
import scalajs.js |
||||
|
|
||||
|
object SweetAlertDemo { |
||||
|
@JSImport( |
||||
|
"@sweetalert2/themes/borderless/borderless.min.css", |
||||
|
JSImport.Namespace |
||||
|
) |
||||
|
@js.native |
||||
|
object SweetAlertBorderlessTheme extends js.Object |
||||
|
@JSImport("@sweetalert2/themes/dark/dark.min.css", JSImport.Namespace) |
||||
|
@js.native |
||||
|
object SweetAlertDarkTheme extends js.Object |
||||
|
@JSImport("sweetalert2/dist/sweetalert2.js", JSImport.Namespace) |
||||
|
@js.native |
||||
|
object SweetAlertJs extends js.Object |
||||
|
|
||||
|
SweetAlertDarkTheme |
||||
|
val Swal = SweetAlertJs.asInstanceOf[typings.sweetalert2.mod.default.type] |
||||
|
|
||||
|
val loginPrompt = { |
||||
|
import scalatags.JsDom.all._ |
||||
|
|
||||
|
val nameInput = input( |
||||
|
tpe := "text", |
||||
|
`id` := "loginName", |
||||
|
cls := "swal-input", |
||||
|
placeholder := "Username" |
||||
|
).render |
||||
|
val passInput = input( |
||||
|
tpe := "password", |
||||
|
`id` := "loginPass", |
||||
|
cls := "swal-input", |
||||
|
placeholder := "Password" |
||||
|
).render |
||||
|
val html = div(nameInput, passInput).render.asST |
||||
|
|
||||
|
def nameAndPass(a: js.Any) = (nameInput.value, passInput.value) |
||||
|
|
||||
|
Swal.fireL( |
||||
|
SweetAlertOptions() |
||||
|
.setTitle("Login Form") |
||||
|
.setHtml(html) |
||||
|
.setFocusConfirm(false) |
||||
|
.setConfirmButtonText("Sign In") |
||||
|
.setPreConfirm(nameAndPass _) |
||||
|
) |
||||
|
|
||||
|
} |
||||
|
|
||||
|
val successPrompt = |
||||
|
Swal.fireL( |
||||
|
SweetAlertOptions() |
||||
|
.setPosition(SweetAlertPosition.`top-end`) |
||||
|
.setIcon(SweetAlertIcon.success) |
||||
|
.setTitle("Login Success") |
||||
|
.setShowConfirmButton(false) |
||||
|
.setTimer(1500) |
||||
|
) >> Task.unit |
||||
|
|
||||
|
val failurePrompt = |
||||
|
Swal.fireL( |
||||
|
SweetAlertOptions() |
||||
|
.setPosition(SweetAlertPosition.`top-end`) |
||||
|
.setIcon(SweetAlertIcon.error) |
||||
|
.setTitle("Login Failure") |
||||
|
.setShowConfirmButton(false) |
||||
|
.setTimer(1500) |
||||
|
) >> Task.unit |
||||
|
|
||||
|
val dumbNotif = |
||||
|
Swal |
||||
|
.fireL( |
||||
|
SweetAlertOptions() |
||||
|
.setTitle("Hello there") |
||||
|
.setText("Welcome to outwatch app") |
||||
|
// .setInput(SweetAlertInput.text) |
||||
|
// .setShowCancelButton(true) |
||||
|
.setIcon(SweetAlertIcon.info) |
||||
|
// .setToast(true) |
||||
|
// .setPreConfirm { res: String => |
||||
|
// val username = Swal.getPopup().asOption |
||||
|
// username match { |
||||
|
// case Some(value) => |
||||
|
// println(s"Got value: $value") |
||||
|
// 1 |
||||
|
// case None => |
||||
|
// println("Got none") |
||||
|
// 2 |
||||
|
// } |
||||
|
// res |
||||
|
// } |
||||
|
) >> Task.unit |
||||
|
// .map(_.value.toOption) |
||||
|
|
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
package outwatchapp.util |
||||
|
import scala.concurrent.Future |
||||
|
|
||||
|
import typings.paralleljs.ParallelOptions |
||||
|
import typings.paralleljs.mod.{^ => Parallel} |
||||
|
|
||||
|
import scalajs.js |
||||
|
import scalajs.js.| |
||||
|
|
||||
|
object ParallelDemo { |
||||
|
val p = |
||||
|
new Parallel(js.Array(1, 2, 3, 4, 5), ParallelOptions().setMaxWorkers(2)) |
||||
|
// val pr = new js.Promise() |
||||
|
|
||||
|
// p.map((_: Int) * 2) |
||||
|
|
||||
|
def toFuture[A](p: Parallel[A]): Future[A] = { |
||||
|
val p2 = scala.concurrent.Promise[A]() |
||||
|
p.`then`( |
||||
|
{ (v: A) => |
||||
|
p2.success(v) |
||||
|
(): Unit | js.Thenable[Unit] |
||||
|
}, |
||||
|
{ (e: typings.std.Error) => |
||||
|
p2.failure(e match { |
||||
|
case th: Throwable => th |
||||
|
case _ => js.JavaScriptException(e) |
||||
|
}) |
||||
|
(): Unit | js.Thenable[Unit] |
||||
|
} |
||||
|
) |
||||
|
p2.future |
||||
|
} |
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
package outwatchapp.util |
||||
|
|
||||
|
// import typings.std.{SubtleCrypto => TS} |
||||
|
// import org.scalajs.dom.crypto.SubtleCrypto |
||||
|
import typings.std.global.Uint8Array |
||||
|
import typings.std.global.{SubtleCrypto => TS} |
||||
|
|
||||
|
object SubtleCryptoTest { |
||||
|
val sc = new TS() |
||||
|
// Algorithm |
||||
|
// sc.deriveKey |
||||
|
// val n = WindowBase64 |
||||
|
new Uint8Array(10) |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
// package outwatchapp.util |
||||
|
|
||||
|
// import org.scalajs.dom |
||||
|
|
||||
|
// import scala.scalajs.js |
||||
|
// import scala.scalajs.js.annotation.JSExport |
||||
|
// import org.scalajs.dom.webworkers.DedicatedWorkerGlobalScope |
||||
|
// import scala.scalajs.js.annotation.JSGlobalScope |
||||
|
// import scala.scalajs.js.annotation.JSExportTopLevel |
||||
|
|
||||
|
// // @js.native |
||||
|
// // object WorkerGlobal extends js.GlobalScope { |
||||
|
// // def addEventListener(`type`: String, f: js.Function): Unit = js.native |
||||
|
// // def postMessage(data: js.Any): Unit = js.native |
||||
|
// // } |
||||
|
|
||||
|
// @js.native |
||||
|
// @JSGlobalScope |
||||
|
// object WorkerGlobal extends DedicatedWorkerGlobalScope |
||||
|
|
||||
|
// @JSExportTopLevel("WorkerMain") |
||||
|
// object WorkerMain { |
||||
|
// @JSExport |
||||
|
// def main(): Unit = { |
||||
|
// // WorkerGlobal.addEventListener("message", onMessage _) |
||||
|
// WorkerGlobal.onmessage = onMessage _ |
||||
|
// WorkerGlobal.postMessage(s"Started") |
||||
|
// } |
||||
|
|
||||
|
// val timeMessage = """Time.*""".r |
||||
|
// var count = 0 |
||||
|
|
||||
|
// def onMessage(msg: dom.MessageEvent) = { |
||||
|
// val s = msg.data.asInstanceOf[String] |
||||
|
// s match { |
||||
|
// case timeMessage() => |
||||
|
// count += 1 |
||||
|
// if (count % 600 == 0) |
||||
|
// WorkerGlobal.postMessage("60fps") |
||||
|
// case _ => |
||||
|
// WorkerGlobal.postMessage(s"Received: $s") |
||||
|
// } |
||||
|
// } |
||||
|
// } |
@ -0,0 +1,77 @@ |
|||||
|
package outwatchapp.util.reactive |
||||
|
|
||||
|
import io.circe.Decoder |
||||
|
import io.circe.Encoder |
||||
|
import io.circe.Printer |
||||
|
import io.circe.parser._ |
||||
|
import io.circe.syntax._ |
||||
|
import monix.execution.Ack |
||||
|
import monix.execution.Cancelable |
||||
|
import monix.execution.cancelables.SingleAssignCancelable |
||||
|
import monix.reactive.Observable |
||||
|
import monix.reactive.Observer |
||||
|
import monix.reactive.OverflowStrategy |
||||
|
import org.scalajs.dom.raw.MessageEvent |
||||
|
import org.scalajs.dom.webworkers.DedicatedWorkerGlobalScope |
||||
|
import scala.concurrent.Future |
||||
|
import outwatchapp.util.reactive.Exceptions.WrongTypeException |
||||
|
// @js.native |
||||
|
// @JSGlobalScope |
||||
|
// object WorkerGlobal extends DedicatedWorkerGlobalScope |
||||
|
|
||||
|
// class DedicatedWorkerImpl[T: Encoder: Decoder](wg: DedicatedWorkerGlobalScope) { |
||||
|
// def run = Task.deferAction(implicit s => |
||||
|
// for { |
||||
|
// _ <- Task.unit |
||||
|
// sub <- Task(ConcurrentSubject.publish[T]) |
||||
|
// } yield () |
||||
|
// ) |
||||
|
// } |
||||
|
|
||||
|
object DedicatedWorker { |
||||
|
def source[T: Decoder](wg: DedicatedWorkerGlobalScope) = |
||||
|
Observable.create[T](OverflowStrategy.DropOld(50)) { sub => |
||||
|
val c = SingleAssignCancelable() |
||||
|
def onmessageFn(event: MessageEvent): Unit = { |
||||
|
event.data match { |
||||
|
case s: String => |
||||
|
decode[T](s) |
||||
|
.map { res => |
||||
|
if (sub.onNext(res) == Ack.Stop) c.cancel() |
||||
|
res |
||||
|
} |
||||
|
.left |
||||
|
.foreach(err => |
||||
|
sub.onError( |
||||
|
new Exception(s"Failed to decode $s. Error was $err") |
||||
|
) |
||||
|
) |
||||
|
case other => |
||||
|
sub.onError(WrongTypeException(s"Received wrong type: $other")) |
||||
|
} |
||||
|
} |
||||
|
wg.onmessage = onmessageFn _ |
||||
|
|
||||
|
c := Cancelable(() => wg.onmessage = _ => ()) |
||||
|
} |
||||
|
|
||||
|
def sink[T: Encoder](wg: DedicatedWorkerGlobalScope) = |
||||
|
new Observer[T] { |
||||
|
val printer = Printer.noSpaces |
||||
|
|
||||
|
override def onNext(elem: T): Future[Ack] = { |
||||
|
// wg.onoffline |
||||
|
wg.postMessage(printer.print(elem.asJson)) |
||||
|
Ack.Continue |
||||
|
} |
||||
|
|
||||
|
override def onError(ex: Throwable): Unit = ex.printStackTrace() |
||||
|
|
||||
|
override def onComplete(): Unit = println("Worker observer completed") |
||||
|
|
||||
|
} |
||||
|
|
||||
|
def apply[T: Encoder: Decoder]( |
||||
|
wg: DedicatedWorkerGlobalScope |
||||
|
): DedicatedWorker[T] = MonixProSubject.from(sink(wg), source(wg)) |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
package outwatchapp.util.reactive |
||||
|
|
||||
|
object Exceptions { |
||||
|
//cause: Option[Throwable]) extends Exception(message, cause.orNull) |
||||
|
sealed abstract class ReactiveException(val message: String) |
||||
|
extends Throwable(message) |
||||
|
final case class DecodeException(override val message: String) |
||||
|
extends ReactiveException(message) |
||||
|
final case class WrongTypeException(override val message: String) |
||||
|
extends ReactiveException(message) |
||||
|
final case class UseAfterClose(override val message: String) |
||||
|
extends ReactiveException(message) |
||||
|
final case class TerminatedException(override val message: String) |
||||
|
extends ReactiveException(message) |
||||
|
|
||||
|
} |
@ -0,0 +1,165 @@ |
|||||
|
package outwatchapp.util.reactive |
||||
|
|
||||
|
import scala.concurrent.Future |
||||
|
|
||||
|
import io.circe.Decoder |
||||
|
import io.circe.Encoder |
||||
|
import io.circe.Printer |
||||
|
import io.circe.parser._ |
||||
|
import io.circe.syntax._ |
||||
|
import monix.bio.Task |
||||
|
import monix.execution.Ack |
||||
|
import monix.execution.Cancelable |
||||
|
import monix.execution.CancelablePromise |
||||
|
import monix.execution.cancelables.SingleAssignCancelable |
||||
|
import monix.reactive.Observable |
||||
|
import monix.reactive.Observer |
||||
|
import monix.reactive.OverflowStrategy |
||||
|
import typings.reconnectingWebsocket.eventsMod.CloseEvent |
||||
|
import typings.reconnectingWebsocket.eventsMod.ErrorEvent |
||||
|
import typings.reconnectingWebsocket.eventsMod.Event |
||||
|
import typings.reconnectingWebsocket.mod.{default => RW} |
||||
|
|
||||
|
import scalajs.js |
||||
|
import typings.std.MessageEvent |
||||
|
import typings.reconnectingWebsocket.mod.Options |
||||
|
import outwatchapp.util.reactive.Exceptions.DecodeException |
||||
|
import outwatchapp.util.reactive.Exceptions.WrongTypeException |
||||
|
import monix.reactive.observers.Subscriber |
||||
|
import monix.reactive.observers.BufferedSubscriber |
||||
|
import outwatchapp.util.reactive.Exceptions.UseAfterClose |
||||
|
import monix.bio.IO |
||||
|
|
||||
|
class ReconnectingWebSocketImpl[T: Encoder: Decoder]( |
||||
|
ws: RW, |
||||
|
overflowStrategy: OverflowStrategy.Synchronous[T] |
||||
|
) { |
||||
|
val printer = Printer.noSpaces |
||||
|
|
||||
|
/** @throws ReactiveException |
||||
|
*/ |
||||
|
val source: Task[Observable[T]] = |
||||
|
Task.deferAction(implicit s => |
||||
|
for { |
||||
|
obs <- Task( |
||||
|
Observable |
||||
|
.create[T](overflowStrategy) { sub => |
||||
|
val c = SingleAssignCancelable() |
||||
|
val onmessage: js.Function1[MessageEvent[_], Unit] = |
||||
|
_.data match { |
||||
|
case s: String => |
||||
|
decode[T](s) |
||||
|
.map { res => |
||||
|
if (sub.onNext(res) == Ack.Stop) c.cancel() |
||||
|
res |
||||
|
} |
||||
|
.left |
||||
|
.foreach(err => |
||||
|
sub.onError( |
||||
|
DecodeException( |
||||
|
s"Failed to decode $s. Error was $err" |
||||
|
) |
||||
|
) |
||||
|
) |
||||
|
case other => |
||||
|
sub.onError( |
||||
|
WrongTypeException(s"Received wrong type: $other") |
||||
|
) |
||||
|
} |
||||
|
val emptyMsgFn: js.Function1[MessageEvent[_], Unit] = |
||||
|
_ => println("message fn not initialized") |
||||
|
ws.onmessage = onmessage |
||||
|
|
||||
|
val onclose: js.Function1[CloseEvent, Unit] = a => { |
||||
|
println( |
||||
|
s"Websocket closing - ${a.code} ${a.wasClean} ${a.reason}" |
||||
|
) |
||||
|
sub.onComplete() |
||||
|
} |
||||
|
ws.onclose = onclose |
||||
|
|
||||
|
val onerror: js.Function1[ErrorEvent, Unit] = (e: Event) => |
||||
|
sub.onError(new Exception(s"Error in WebSocket: $e")) |
||||
|
|
||||
|
ws.onerror = onerror |
||||
|
|
||||
|
c := Cancelable { () => ws.onmessage = emptyMsgFn } |
||||
|
} |
||||
|
.publish |
||||
|
.refCount |
||||
|
) |
||||
|
_ <- Task(obs.subscribe(Observer.empty)) |
||||
|
} yield obs |
||||
|
) |
||||
|
|
||||
|
val sink: Task[Observer[T]] = |
||||
|
Task.deferAction(implicit s => |
||||
|
Task( |
||||
|
BufferedSubscriber( |
||||
|
new Subscriber[T] { |
||||
|
import monix.execution.FutureUtils |
||||
|
import scala.concurrent.duration._ |
||||
|
override def scheduler = s |
||||
|
override def onNext(elem: T): Future[Ack] = { |
||||
|
val msg = printer.print(elem.asJson) |
||||
|
if (ws.readyState == 2 || ws.readyState == 3) |
||||
|
Ack.Stop |
||||
|
else { |
||||
|
FutureUtils |
||||
|
.delayedResult(2.second)(ws.send(msg)) |
||||
|
.flatMap(_ => Ack.Continue) |
||||
|
} |
||||
|
} |
||||
|
override def onError(ex: Throwable): Unit = s.reportFailure(ex) |
||||
|
override def onComplete(): Unit = println("CLOSING WEBSOCKET 2 ") |
||||
|
}, |
||||
|
OverflowStrategy.Default |
||||
|
) |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
} |
||||
|
object ReconnectingWebSocket { |
||||
|
sealed trait Error |
||||
|
final case object Error extends Error |
||||
|
|
||||
|
/** @throws ReactiveException |
||||
|
*/ |
||||
|
final case class Source[T](value: Observable[T]) |
||||
|
|
||||
|
/** A buffered Observer |
||||
|
* |
||||
|
* @param value |
||||
|
*/ |
||||
|
final case class Sink[T](value: Observer[T]) { |
||||
|
def send(t: T) = |
||||
|
IO.deferFuture(value.onNext(t)).flatMap { |
||||
|
case Ack.Continue => Task.unit |
||||
|
case Ack.Stop => IO.raiseError(UseAfterClose("Websocket was closed")) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private val defaultOptions = Options() |
||||
|
.setMinReconnectionDelay(5000) |
||||
|
.setMaxRetries(2) |
||||
|
.setMaxEnqueuedMessages(50) |
||||
|
|
||||
|
def onopen[A](op: => A): js.Function1[Event, Unit] = _ => op |
||||
|
|
||||
|
def apply[T <: Product: Encoder: Decoder]( |
||||
|
path: String, |
||||
|
options: Options = defaultOptions, |
||||
|
overflowStrategy: OverflowStrategy.Synchronous[T] = |
||||
|
OverflowStrategy.DropOld(50) |
||||
|
) = for { |
||||
|
websocket <- Task(new RW(path, js.undefined, options)) |
||||
|
p = CancelablePromise[Unit]() |
||||
|
_ <- Task(websocket.onopen = onopen(p.success(()))) |
||||
|
_ <- Task.deferFuture(p.future) |
||||
|
_ <- Task(websocket.onopen = onopen(())) |
||||
|
impl = new ReconnectingWebSocketImpl[T](websocket, overflowStrategy) |
||||
|
source <- impl.source |
||||
|
sink <- impl.sink |
||||
|
// _ <- Task.deferAction(implicit s => Task(source.subscribe(sink))) |
||||
|
} yield Source(source) -> Sink(sink) |
||||
|
} |
23690
src/main/scala/outwatchapp/util/reactive/store/test.css
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue