Created
January 5, 2020 21:03
-
-
Save elyphas/a79af741e174833a40e2da955603969f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package outwatch_components | |
import cats.effect.SyncIO | |
import cats.implicits._ | |
import org.scalajs | |
import org.scalajs.dom | |
import org.scalajs.dom.ext.KeyCode | |
import org.scalajs.dom.html | |
import monix.execution.Ack.Continue | |
import monix.execution.Scheduler.Implicits.global | |
import monix.reactive.Observable | |
import outwatch.reactive.SinkObserver | |
import outwatch.reactive.LiftSource | |
import monix.reactive.subjects.PublishSubject | |
import outwatch.dom._ | |
import outwatch.dom.dsl._ | |
import outwatch.dom.dsl.events.document | |
import outwatch.dom.dsl.{id, _} | |
import outwatch.ext.monix._ | |
import outwatch.ext.monix.handler._ | |
/*import scala.concurrent.duration._ | |
import scala.reflect.io.Path.string2path | |
import scala.scalajs.js.JSON | |
import outwatch.dom.helpers.EmitterBuilder*/ | |
import scala.util.Try | |
case class ColG ( field: String, title:String, styleTitle: VDomModifier, styleCell: VDomModifier, | |
typeNumber: String = "", | |
inputType: String = "input", | |
edit: Boolean = false ) | |
class Grid( colFmt: Seq[ColG], transitions: Map[Int, Int], eventsGrid: VDomModifier, eventsCell: VDomModifier, focusColOnInsert: Int) extends FormatNumber { | |
/*helpers.OutwatchTracing.patch.zipWithIndex.foreach { case (proxy, index) => | |
org.scalajs.dom.console.log(s"Snabbdom patch ($index)!", JSON.parse(JSON.stringify(proxy)), proxy) | |
}*/ | |
val hdlFieldActive = Handler.create[String]("").unsafeRunSync() | |
val hdlRowActive = PublishSubject[Int]() | |
val hdlChangingValue = PublishSubject[(String, String)]() | |
val hdlPositionCursor = Handler.create[(Int, Int)]((0, 0)).unsafeRunSync() | |
val hdlTransition = Handler.create[(Int, Int)]((0,7)).unsafeRunSync() //row, col | |
val hdlActionsGrid = PublishSubject[String]() //Handler.create[String]("").unsafeRunSync() | |
/*private def transitionOnEnter = SinkObserver.create[(Int, Int)]{ case (row, col) => | |
transitions.get(col).foreach( nextCol => hdlTransition.onNext((row, col))) | |
}*/ | |
protected val keyEnter = onKeyDown.filter(_.keyCode == KeyCode.Enter).map { case k => k.stopPropagation(); k } | |
val keyInsert = onKeyUp.filter(_.keyCode == KeyCode.Insert) | |
private def getCellFromKeyBoard(k: dom.KeyboardEvent) = k.target.asInstanceOf[html.TableCell] | |
private def getRowFromCell(c: html.TableCell) = c.parentNode.asInstanceOf[html.TableRow] | |
def getPositionCell ( k: dom.KeyboardEvent ) = { | |
val cell = getCellFromKeyBoard(k) | |
val row = getRowFromCell(cell) | |
(cell.cellIndex, row.rowIndex) | |
} | |
def getPositionCellEnter = keyEnter.map(getPositionCell) | |
//private def insertRow = SinkObserver.create[(Int, Int)]{ case (row, col) => hdlTransition.onNext(Some(row, focusColOnInsert))} | |
/*def getPositionCellInsert = keyInsert.map(getPositionCell) --> hdlTransition.contramap[(Int, Int)]{case (r, c) => Some(r, focusColOnInsert)}*/ | |
//def onInsertRow = keyInsert.map(getPositionCell) --> hdlTransition.contramap[(Int, Int)]{case (r, c) => (r, focusColOnInsert)} | |
val mountCellFocus = SinkObserver.create[(dom.Element, String, String)] { case (elem, inputType, idTxt) => | |
if (idTxt == elem.id) { | |
val txt = if ( inputType == "input" ) elem.asInstanceOf[html.Input] else elem.asInstanceOf[html.TextArea] | |
val range = dom.document.createRange() | |
val sel = scalajs.dom.window.getSelection() | |
sel.removeAllRanges() | |
range.selectNodeContents(txt) | |
sel.addRange(range) | |
txt.focus | |
} | |
} | |
def contentTd(idTd: String, valor: String, col: Int, row: Int) = { | |
val field = colFmt(col) | |
val idTxt = idTd + "txtEditable" | |
val tabIdx = ((row + 1) * 10) + col | |
val eventOnChanging = if (field.inputType == "checkbox") onChangingValueChk else onChangingValueTxt | |
val valorVDom = if (field.inputType == "checkbox") VDomModifier(checked := valor.toBoolean) else VDomModifier(value:=valor) | |
val domMount = SyncIO(onDomMount | |
.transformLifted( (e: Observable[(dom.Element)]) => | |
e.combineLatest(hdlTransition.distinctUntilChanged)) | |
.map { case (elem, (rowAct, colum) ) => | |
(elem, field.inputType, "r" + (rowAct-1) + "c" + colum + "txtEditable") | |
} --> mountCellFocus | |
) | |
/*val domMount = SyncIO( | |
onDomMount.transform( _.lift[Observable].combineLatest(hdlTransition.distinctUntilChanged)) | |
.map { case (elem, (rowAct, colum) ) => | |
(elem, field.inputType, "r" + (rowAct-1) + "c" + colum + "txtEditable") | |
} --> mountCellFocus | |
)*/ | |
val vdomM = VDomModifier( key := idTxt, id := idTxt, cls:="editCell", tabIndex := tabIdx, field.styleCell, | |
//value := txt, | |
valorVDom, | |
eventsCell, | |
focusUpatePositionCursor, | |
focusCelUpdateField, focusCelUpdateRow, eventOnChanging, | |
domMount, | |
) | |
//Ya tenemos components para input y textArea. | |
if (field.edit) { | |
if (field.inputType == "TextArea") textArea(vdomM) | |
else if (field.inputType == "input") input(vdomM) | |
else input(`type` := "checkbox", vdomM) | |
} else { | |
val texto = if (field.typeNumber == "money") fmtMiles(valor.toDouble) | |
else if (field.typeNumber == "amount") fmtMiles(valor.toDouble, 0) | |
else valor | |
label(texto, field.styleCell) | |
} | |
} | |
def newCell(txt: String, col: Int, row: Int) = { | |
val idTd = "r" + row + "c" + col | |
val eventsTd = VDomModifier( hiddeGridCatalogsLostFocus) | |
td( id := idTd, key := idTd, cls := "tdCell", contentTd(idTd, txt, col, row), eventsTd, colFmt(col).styleCell) | |
} | |
def showDetails( l: Map[Int, Map[String, String]]) = | |
l.toSeq.sortBy( _._1 ) map { case (idRow: Int, fields: Map[String, String]) => | |
tr ( id := "row" + idRow.toString, | |
colFmt.zipWithIndex.map { case (col: ColG, ii: Int) => newCell(fields.getOrElse(col.field, ""), col = ii, row = idRow)}) | |
} | |
val onChangingValueTxt = SyncIO ( onInput.value.transformLifted( (e: Observable[(String)]) => | |
e.distinctUntilChanged | |
.withLatestFrom(hdlFieldActive){ case (txt: String, field: String) => | |
(field, txt.toUpperCase)}) --> hdlChangingValue) | |
/*val onChangingValueTxt = SyncIO ( onInput.value.transform ( | |
_.lift[Observable].distinctUntilChanged | |
.withLatestFrom(hdlFieldActive){ case (txt: String, field: String) => | |
(field, txt.toUpperCase)}) --> hdlChangingValue)*/ | |
val onChangingValueChk = SyncIO ( | |
onInput.checked.transformLifted( (e: Observable[Boolean]) => | |
e.distinctUntilChanged | |
.withLatestFrom(hdlFieldActive){ case (chk: Boolean, field: String) => | |
(field, chk.toString) | |
} | |
) --> hdlChangingValue ) | |
/*val onChangingValueChk = SyncIO ( onInput | |
.checked.transform ( | |
_.lift[Observable] | |
.distinctUntilChanged | |
.withLatestFrom(hdlFieldActive){ case (chk: Boolean, field: String) => | |
(field, chk.toString)}) --> hdlChangingValue) */ /** Despues se tiene que utilizar el typo de datos que le corresponde. */ | |
private val focusCel = onFocus.map{ f => | |
f.stopPropagation() | |
f.preventDefault() | |
f.currentTarget.asInstanceOf[html.Input] | |
} | |
private val focusUpatePositionCursor = SyncIO(focusCel.map { case txt => | |
val rect = txt.getBoundingClientRect() | |
(rect.bottom.toInt, rect.left.toInt) } --> hdlPositionCursor.contramap[(Int,Int)]{ case (bottom, left) => (bottom, left)} | |
) | |
private val focusCelUpdateField = SyncIO( focusCel.map { case txt => | |
val cel = txt.parentElement.asInstanceOf[html.TableCell] | |
colFmt.zipWithIndex.filter{ case (_, idx) => idx == cel.cellIndex }.map { case (col, _) => col.field }.head | |
} --> hdlFieldActive.contramap[String]{ field => field}) | |
private val focusCelUpdateRow = SyncIO(focusCel.map { case txt => | |
val row = txt.parentElement.parentElement.asInstanceOf[html.TableRow] | |
row.rowIndex | |
} --> hdlRowActive.contramap[Int]{row => row}) | |
/*private val focusCelUpdateTransition = SyncIO( | |
focusCel.transform(_.lift[Observable].withLatestFrom(hdlTransition){ case (txt, (_, col)) => | |
val row = txt.parentElement.parentElement.asInstanceOf[html.TableRow] | |
(row.rowIndex, col) | |
}) --> hdlTransition.contramap[(Int, Int)]{ case (row, col) => (row, col)})*/ | |
val actionsGrid = SyncIO( | |
onKeyUp.map { k => | |
k.keyCode match { | |
case KeyCode.Insert => "Insert" | |
case KeyCode.Delete => "Delete" | |
case _ => "Nothing" | |
} | |
} --> hdlActionsGrid | |
) | |
protected val hiddeGridCatalogsLostFocus = SyncIO(onBlur.use((0,0)) --> hdlPositionCursor.contramap[(Int,Int)](pos => pos)) | |
protected val onEscape = onKeyDown.filter(_.keyCode == KeyCode.Escape) | |
protected val restarPosition = onEscape.use((0,0)) --> hdlPositionCursor.contramap[(Int,Int)](pos => pos) | |
protected val restarCatalog = onEscape.use(("","")) --> hdlChangingValue.contramap[(String, String)](catalog => catalog) | |
/*protected val hiddeGridCatalogs = onKeyDown.filter(_.keyCode == KeyCode.Escape).foreach { k => | |
hdlChangingValue.onNext(("","")) | |
hdlPositionCursor.onNext((0,0)) | |
}*/ | |
def render(items: Map[Int, Map[String, String]]) = table( | |
id := "tblGrid", cls := "tblGrid", | |
thead(tr(colFmt.map(t => td(t.title, t.styleTitle)))), | |
tbody( | |
eventsGrid, | |
actionsGrid, | |
showDetails(items), | |
//hiddeGridCatalogs, | |
restarCatalog, restarPosition | |
) | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment