class DirItem(e): def __init__(self, obj): super().__init__("div") self.container = Div("diritem") for field in DIR_ITEM_FIELDS: self[field[1]] = obj[field[0]] fdiv = Div(field[1]) self[field[1] + "div"] = fdiv self.container.a(fdiv) if self.isdir: self.container.ac("isdir") self.filenamelabel = Div().html(self.filename) self.filenamediv.a([self.filenamelabel]) self.deletebutton = None if self.filename == "..": self.filenamediv.ac("parent") else: self.deletebutton = Button("Delete").ac("delete") self.isdirdiv.a(self.deletebutton) self.mtimediv.html( __new__(Date(self.mtime * 1000)).toLocaleString()) if self.isdir: self.sizediv.html("dir") else: self.editbutton = Button("Edit") self.filenamediv.a(self.editbutton) self.sizediv.html(self.size) if self.rwx: self.rwxdiv.html(self.rwx) self.a(self.container)
def setstore(self, store): self.store = store self.container.x() self.pieces = {} for pieceletter in self.store.split(""): p = piecelettertopiece(pieceletter) if p.color == self.color: if p.kind in self.pieces: self.pieces[p.kind]["mul"] += 1 else: pcdiv = Div().pr().w(self.piecesize).h(self.piecesize) pdiv = Div().pa().cp().ac(getclassforpiece(p, self.parent.piecestyle)).w(self.piecesize).h(self.piecesize) pdivcopy = Div().pa().cp().ac(getclassforpiece(p, self.parent.piecestyle)).w(self.piecesize).h(self.piecesize) pdiv.t(0).l(0).sa("draggable", True).ae("dragstart", self.dragstartfactory(p, pdiv, pdivcopy)) pcdiv.a(pdiv) self.pieces[p.kind] = { "mul": 1, "p": p, "pcdiv": pcdiv } for pkind, pdesc in self.pieces.items(): muldiv = Div().pa().w(self.muldivsize).h(self.muldivsize).fs(self.muldivsize * 1.3).html("{}".format(pdesc["mul"])) muldiv.l(self.piecesize - self.muldivsize).t(0).ac("storemuldiv") pdesc["pcdiv"].a(muldiv) self.container.a(pdesc["pcdiv"]) return self
class LogItem(e): def __init__(self, args = {}): super().__init__("div") self.text = args.get("text", "") self.kind = args.get("kind", "normal") self.prompt = args.get("prompt", None) self.container = Div("logitem") self.container.ac(self.kind) self.promptspan = Span().ac("prompt") if self.prompt: self.promptspan.html(self.prompt) self.textspan = Span().html(escapeHTML(self.text)).ac(self.kind) self.container.a([self.promptspan, self.textspan]) self.a(self.container)
class SplitPane(e): def resize(self, width = None, height = None): if not ( width is None ): self.width = max(width, self.minwidth) if not ( height is None ): self.height = height self.contentheight = max(self.height - self.controlheight, self.mincontentheight) self.height = self.controlheight + self.contentheight self.container.w(self.width).h(self.height) self.controlpanel.w(self.width).h(self.controlheight) self.contentdiv.w(self.width).h(self.contentheight) sbw = getScrollBarWidth() self.contentinnerwidth = self.width - sbw self.contentinnerheight = self.contentheight - sbw self.contentdiv.x().a(self.contentelement) try: self.contentelement.resize(self.contentinnerwidth, self.contentinnerheight) except: pass return self def setcontentelement(self, contentelement): self.contentelement = contentelement self.resize(self.width, self.height) return self def resizetowindow(self): self.resize(window.innerWidth, window.innerHeight) return self def __init__(self, args = {}): super().__init__("div") self.controlheight = args.get("controlheight", 100) self.container = Div(["splitpane", "container"]) self.controlpanel = Div(["splitpane", "controlpanel"]) self.contentdiv = Div(["splitpane", "contentdiv"]) self.container.a([self.controlpanel, self.contentdiv]) self.contentelement = Div() self.minwidth = args.get("minwidth", 400) self.mincontentheight = args.get("mincontentheight", 200) self.resize(args.get("width", 600), args.get("height", 400)) self.fillwindow = args.get("fillwindow", False) if self.fillwindow: window.addEventListener("resize", self.resizetowindow) self.resizetowindow() self.a(self.container)
def buildsquares(self): self.container.x() self.sqdivs = {} self.sqhdivs = {} for sq in self.squarelist(): sqclass = cpick(self.islightsquare(sq), "boardsquarelight", "boardsquaredark") sqdiv = Div().ac(["boardsquare", sqclass]).w(self.squaresize).h(self.squaresize) sqhdiv = Div().pa().w(self.squaresize).h(self.squaresize) self.sqdivs[sq.hashkey()] = sqdiv self.sqhdivs[sq.hashkey()] = { "div": sqhdiv, "cumop": 0.0 } fasq = self.flipawaresquare(sq) sqdiv.pv(self.squarecoordsvect(fasq)) sqhdiv.pv(self.squarecoordsvect(fasq)) sqdiv.ae("dragover", self.piecedragoverfactory(sq)) sqdiv.ae("drop", self.piecedropfactory(sq)) sqhdiv.ae("dragover", self.piecedragoverfactory(sq)) sqhdiv.ae("drop", self.piecedropfactory(sq)) self.container.a([sqdiv, sqhdiv]) p = self.getpieceatsquare(sq) if p.ispiece(): pdiv = Div().ac("boardpiece").w(self.piecesize).h(self.piecesize).pv(self.piececoordsvect(fasq)) pdiv.ac(getclassforpiece(p, self.piecestyle)).sa("draggable", True) pdiv.ae("dragstart", self.piecedragstartfactory(sq, pdiv)) pdiv.ae("drag", self.piecedragfactory()) pdiv.ae("dragend", self.piecedragendfactory(sq, pdiv)) pdiv.ae("dragover", self.piecedragoverfactory(sq)) pdiv.ae("drop", self.piecedropfactory(sq)) pdiv.zi(10) if self.variantkey == "threeCheck": if ( p.kind == "k" ): mul = self.getthreelifesforcolor(p.color) lifesdiv = Div().pa().t(- self.squaresize / 10).l(self.squaresize / 2 + self.squaresize / 10).w(self.squaresize / 2).h(self.squaresize / 2) lifesdiv.ac("boardthreechecklifesdiv").fs(self.squaresize / 1.5).html("{}".format(mul)) lifesdiv.c(["#ff0", "#ff0"][p.color]) pdiv.a(lifesdiv) self.container.a(pdiv)
class ProcessInput(e): def onenter(self): self.textinput.rc("textinputediting") if self.entercallback: self.entercallback() def getText(self): return self.textinput.getText() def setText(self, content): self.textinput.setText(content) return self def __init__(self, args = {}): super().__init__("div") self.container = Div("processinput") self.buttonlabel = args.get("buttonlabel", "Submit") self.entercallback = args.get("entercallback", None) self.textinput = TextInput().setentercallback(self.entercallback) self.submitbutton = Button(self.buttonlabel, self.onenter) self.container.a([self.textinput, self.submitbutton]) self.a(self.container)
class Log(e): def __init__(self, args = {}): super().__init__("div") self.items = [] self.container = Div() self.a(self.container) def build(self): self.container.x() for item in self.items: self.container.a(item) def log(self, item): newitems = [item] i = 1 for olditem in self.items: if i < MAX_LOGITEMS: newitems.append(olditem) i += 1 else: break self.items = newitems self.build() ######################################################
class MultipvInfo(e): def bestmovesanclickedfactory(self, moveuci, dostore = False): def bestmovesanclicked(): if not ( self.bestmovesanclickedcallback is None ): self.bestmovesanclickedcallback(moveuci, dostore) return bestmovesanclicked def scorebonus(self): if "scorebonus" in self.infoi: try: scorebonus = int(self.infoi["scorebonus"]) return scorebonus except: pass return 0 def effscore(self): return self.scorenumerical + self.scorebonus() def bonussliderchanged(self): self.infoi["scorebonus"] = self.bonusslider.v() self.build() if not ( self.bonussliderchangedcallback is None ): self.bonussliderchangedcallback() def traincombochanged(self): self.infoi["metrainweight"] = self.metraincombo.v() self.infoi["opptrainweight"] = self.opptraincombo.v() self.build() def build(self, gamesan = None): self.bestmoveuci = self.infoi["bestmoveuci"] self.bestmovesan = self.infoi["bestmovesan"] self.scorenumerical = self.infoi["scorenumerical"] self.pvsan = self.infoi["pvsan"] self.pvsans = self.pvsan.split(" ") if len(self.pvsans) > ( self.pvlength + 1 ): self.pvsans = self.pvsans[0:self.pvlength + 1] if len(self.pvsans) > 1: self.pvsans = self.pvsans[1:] self.showpv = " ".join(self.pvsans) self.pvpgn = self.infoi["pvpgn"] self.depth = self.infoi["depth"] self.nps = self.infoi["nps"] self.container = Div().ac("multipvinfocontainer") self.idiv = Div().ac("multipvinfoi").html("{}.".format(self.i)) self.bestmovesandiv = Div().ac("multipvinfobestmovesan").html(self.bestmovesan) if gamesan == self.bestmovesan: self.bestmovesandiv.bc("#fbf") self.bestmovesandiv.ae("mousedown", self.bestmovesanclickedfactory(self.bestmoveuci)) self.scorenumericaldiv = Div().ac("multipvinfoscorenumerical").html("{}".format(scoreverbal(self.effscore()))).cp() self.scorenumericaldiv.ae("mousedown", self.bestmovesanclickedfactory(self.bestmoveuci, True)) self.bonussliderdiv = Div().ac("multipvinfobonussliderdiv") self.bonusslider = Slider().setmin(-500).setmax(500).ac("multipvinfobonusslider").sv(self.scorebonus()) self.bonusslider.ae("change", self.bonussliderchanged) self.bonussliderdiv.a(self.bonusslider) self.depthdiv = Div().ac("multipvinfodepth").html("{}".format(self.depth)) self.miscdiv = Div().ac("multipvinfomisc").html("nps {}".format(self.nps)) self.traindiv = Div().ac("multipvinfomisc").w(100) metrainweight = self.infoi["metrainweight"] hasmetrain = False if not metrainweight: metrainweight = "0" opptrainweight = self.infoi["opptrainweight"] hasopptrain = False if not opptrainweight: opptrainweight = "0" try: if int(metrainweight) > 0: hasmetrain = True if int(opptrainweight) > 0: hasopptrain = True except: pass if hasmetrain and hasopptrain: self.trainbc = "#00f" elif hasmetrain: self.trainbc = "#0f0" elif hasopptrain: self.trainbc = "#f00" else: self.trainbc = "inherit" self.metrainweight = int(metrainweight) self.opptrainweight = int(opptrainweight) self.avgtrainweight = ( self.metrainweight + self.opptrainweight ) / 2.0 self.trainop = self.avgtrainweight / 10.0 self.metraincombo = ComboBox().setoptions(TRAIN_OPTIONS, metrainweight, self.traincombochanged) self.opptraincombo = ComboBox().setoptions(TRAIN_OPTIONS, opptrainweight, self.traincombochanged) self.traindiv.a([self.metraincombo, self.opptraincombo]) self.pvdiv = Div().ac("multipvinfopv").html(self.showpv).c("#070").fw("bold") self.container.a([self.idiv, self.bestmovesandiv, self.scorenumericaldiv, self.bonussliderdiv, self.traindiv, self.depthdiv, self.pvdiv]) self.container.bc(self.trainbc) self.bestmovesandiv.c(scorecolor(self.effscore())) self.scorenumericaldiv.c(scorecolor(self.effscore())) self.x().a(self.container) def __init__(self, infoi, pvlength = 4): super().__init__("div") self.pvlength = pvlength self.bestmovesanclickedcallback = None self.bonussliderchangedcallback = None self.infoi = infoi self.i = self.infoi["i"] self.build()
class BasicBoard(e): def clearcanvases(self): self.movecanvas.clear() self.piececanvashook.x() self.arrowdiv.x() def ucitosquare(self, squci): try: file = squci.charCodeAt(0) - "a".charCodeAt(0) rank = self.lastrank - ( squci.charCodeAt(1) - "1".charCodeAt(0) ) return Square(file, rank) except: return None def ucitomove(self, moveuci): if "@" in moveuci: try: parts = moveuci.split("@") sq = self.ucitosquare(parts[1]) move = Move(sq, sq, Piece(parts[0].toLowerCase(), self.turn())) return move except: return None else: try: move = Move(self.ucitosquare(moveuci[0:2]), self.ucitosquare(moveuci[2:4])) try: if len(moveuci) > 4: move.prompiece = Piece(moveuci[4].toLowerCase(), self.turn()) except: print("could not parse prompiece") return move except: return None def resize(self, width, height): self.squaresize = 35 self.calcsizes() while self.totalheight() < height: self.squaresize += 1 self.calcsizes() self.squaresize -= 1 self.calcsizes() self.build() def totalheight(self): th = self.outerheight + cpick(self.showfen, self.fendivheight, 0) if self.variantkey == "crazyhouse": th += 2 * self.squaresize return th def squareuci(self, sq): fileletter = String.fromCharCode(sq.file + "a".charCodeAt(0)) rankletter = String.fromCharCode(self.lastrank - sq.rank + "1".charCodeAt(0)) return fileletter + rankletter def moveuci(self, move): fromuci = self.squareuci(move.fromsq) touci = self.squareuci(move.tosq) promuci = cpick(move.prompiece.isempty(), "", move.prompiece.kind) return fromuci + touci + promuci def islightfilerank(self, file, rank): return ( ( ( file + rank ) % 2 ) == 0 ) def islightsquare(self, sq): return self.islightfilerank(sq.file, sq.rank) def squarelist(self): squarelist = [] for file in range(self.numfiles): for rank in range(self.numranks): squarelist.append(Square(file, rank)) return squarelist def squarecoordsvect(self, sq): return Vect(sq.file * self.squaresize, sq.rank * self.squaresize) def squarecoordsmiddlevect(self, sq): return self.squarecoordsvect(sq).p(Vect(self.squaresize / 2, self.squaresize / 2)) def piececoordsvect(self, sq): return self.squarecoordsvect(sq).p(Vect(self.squarepadding, self.squarepadding)) def flipawaresquare(self, sq): if self.flip: return Square(self.lastfile - sq.file, self.lastrank - sq.rank) return sq def piecedragstartfactory(self, sq, pdiv): def piecedragstart(ev): if self.promoting or self.show: ev.preventDefault() return self.dragkind = "move" self.draggedsq = sq self.draggedpdiv = pdiv self.movecanvashook.x() pdiv.op(0.1) return piecedragstart def piecedragfactory(self): def piecedrag(ev): pass return piecedrag def piecedragendfactory(self, sq, pdiv): def piecedragend(ev): pdiv.op(0.5) return piecedragend def piecedragoverfactory(self, sq): def piecedragover(ev): ev.preventDefault() return piecedragover def ismovepromotion(self, move): fromp = self.getpieceatsquare(move.fromsq) if ( fromp.kind == "p" ) and ( fromp.color == self.turn() ): if self.iswhitesturn(): if move.tosq.rank == 0: return True else: if move.tosq.rank == self.lastrank: return True return False def piecedropfactory(self, sq): def piecedrop(ev): ev.preventDefault() self.draggedpdiv.pv(self.piececoordsvect(self.flipawaresquare(sq))) self.draggedpdiv.zi(100) if self.dragkind == "move": self.dragmove = Move(self.draggedsq, sq) if self.ismovepromotion(self.dragmove): self.promoting = True self.build() elif not ( self.movecallback is None ): self.movecallback(self.variantkey, self.fen, self.moveuci(self.dragmove)) elif self.dragkind == "set": self.container.a(self.draggedpdiv) if not ( self.movecallback is None ): setuci = "{}@{}".format(self.draggedsetpiece.kind, self.squareuci(sq)) self.movecallback(self.variantkey, self.fen, setuci) return piecedrop def buildsquares(self): self.container.x() self.sqdivs = {} self.sqhdivs = {} for sq in self.squarelist(): sqclass = cpick(self.islightsquare(sq), "boardsquarelight", "boardsquaredark") sqdiv = Div().ac(["boardsquare", sqclass]).w(self.squaresize).h(self.squaresize) sqhdiv = Div().pa().w(self.squaresize).h(self.squaresize) self.sqdivs[sq.hashkey()] = sqdiv self.sqhdivs[sq.hashkey()] = { "div": sqhdiv, "cumop": 0.0 } fasq = self.flipawaresquare(sq) sqdiv.pv(self.squarecoordsvect(fasq)) sqhdiv.pv(self.squarecoordsvect(fasq)) sqdiv.ae("dragover", self.piecedragoverfactory(sq)) sqdiv.ae("drop", self.piecedropfactory(sq)) sqhdiv.ae("dragover", self.piecedragoverfactory(sq)) sqhdiv.ae("drop", self.piecedropfactory(sq)) self.container.a([sqdiv, sqhdiv]) p = self.getpieceatsquare(sq) if p.ispiece(): pdiv = Div().ac("boardpiece").w(self.piecesize).h(self.piecesize).pv(self.piececoordsvect(fasq)) pdiv.ac(getclassforpiece(p, self.piecestyle)).sa("draggable", True) pdiv.ae("dragstart", self.piecedragstartfactory(sq, pdiv)) pdiv.ae("drag", self.piecedragfactory()) pdiv.ae("dragend", self.piecedragendfactory(sq, pdiv)) pdiv.ae("dragover", self.piecedragoverfactory(sq)) pdiv.ae("drop", self.piecedropfactory(sq)) pdiv.zi(10) if self.variantkey == "threeCheck": if ( p.kind == "k" ): mul = self.getthreelifesforcolor(p.color) lifesdiv = Div().pa().t(- self.squaresize / 10).l(self.squaresize / 2 + self.squaresize / 10).w(self.squaresize / 2).h(self.squaresize / 2) lifesdiv.ac("boardthreechecklifesdiv").fs(self.squaresize / 1.5).html("{}".format(mul)) lifesdiv.c(["#ff0", "#ff0"][p.color]) pdiv.a(lifesdiv) self.container.a(pdiv) def getthreelifesforcolor(self, color): parts = self.threefen.split("+") mul = 3 if color == WHITE: try: mul = int(parts[2]) except: print("warning, could not parse white lifes from", self.threefen) if color == BLACK: try: mul = int(parts[0]) except: print("warning, could not parse black lifes from", self.threefen) return mul def prompiececlickedfactory(self, prompiecekind): def prompiececlicked(): self.dragmove.prompiece = Piece(prompiecekind, self.turn()) self.movecallback(self.variantkey, self.fen, self.moveuci(self.dragmove)) return prompiececlicked def buildprominput(self): promkinds = prompiecekindsforvariantkey(self.variantkey) promsq = self.dragmove.tosq.copy() dir = cpick(promsq.rank >= ( self.numranks / 2 ), -1, 1) ppks = prompiecekindsforvariantkey(self.variantkey) for ppk in ppks: fapromsq = self.flipawaresquare(promsq) pp = Piece(ppk, self.turn()) psqdiv = Div().pa().cp().zi(150).w(self.squaresize).h(self.squaresize).ac("boardpromotionsquare") psqdiv.pv(self.squarecoordsvect(fapromsq)) ppdiv = Div().pa().cp().zi(200).w(self.piecesize).h(self.piecesize).ac(getclassforpiece(pp, self.piecestyle)) ppdiv.pv(self.piececoordsvect(fapromsq)).ae("mousedown", self.prompiececlickedfactory(ppk)) self.container.a([psqdiv, ppdiv]) promsq = promsq.p(Square(0, dir)) def promotecancelclick(self): self.promoting = False self.build() def drawmovearrow(self, move, args = {}): if move is None: return strokecolor = args.get("strokecolor", "#FFFF00") linewidth = args.get("linewidth", 0.2) * self.squaresize headwidth = args.get("headwidth", 0.2) * self.squaresize headheight = args.get("headheight", 0.2) * self.squaresize tomv = self.squarecoordsmiddlevect(self.flipawaresquare(move.tosq)) frommv = self.squarecoordsmiddlevect(self.flipawaresquare(move.fromsq)) if False: self.movecanvas.lineWidth(linewidth) self.movecanvas.strokeStyle(strokecolor) self.movecanvas.fillStyle(strokecolor) self.movecanvas.drawline(frommv, tomv) dv = Vect(headwidth, headheight) self.movecanvas.fillRect(tomv.m(dv), tomv.p(dv)) if not ( move.prompiece.isempty() ): pf = 4 dvp = Vect(linewidth * pf, linewidth * pf) move.prompiece.color = self.turn() ppdiv = Div().pa().cp().ac(getclassforpiece(move.prompiece, self.piecestyle)).w(linewidth * 2 * pf).h(linewidth * 2 * pf) ppdiv.pv(tomv.m(dvp)) self.piececanvashook.a(ppdiv) arrow = Arrow(frommv, tomv, { "linewidth": linewidth, "pointwidth": headheight * 4, "pointheight": headheight * 4, "color": strokecolor }) self.arrowdiv.a(arrow) def drawuciarrow(self, uci, args = {}): self.drawmovearrow(self.ucitomove(uci), args) def highlightsquare(self, sq, bc, op): if op == 0: return margin = self.squaresize * 0.1 hsize = self.squaresize - 2 * margin sqhdiv = self.sqhdivs[sq.hashkey()] if op > sqhdiv["cumop"]: sqhdiv["cumop"] = op sqhdiv["div"].x().a(Div().pa().t(margin).l(margin).w(hsize).h(hsize).bc(bc).op(sqhdiv["cumop"])) def highlightmove(self, move, bc, op): self.highlightsquare(move.fromsq, bc, op) self.highlightsquare(move.tosq, bc, op) def highlightucimove(self, uci, bc, op): self.highlightmove(self.ucitomove(uci), bc, op) def buildgenmove(self): if "genmove" in self.positioninfo: if not ( genmove == "reset" ): genmoveuci = self.positioninfo["genmove"]["uci"] genmove = self.ucitomove(genmoveuci) if not ( genmove is None ): genmove.prompiece = Piece() self.drawmovearrow(genmove) def fentextchanged(self): if self.fentextchangedcallback: self.fentextchangedcallback(self.fentext.getText()) def build(self): self.sectioncontainer = Div().ac("boardsectioncontainer").w(self.outerwidth) self.sectioncontainer.bci(self.background) self.outercontainer = Div().ac("boardoutercontainer").w(self.outerwidth).h(self.outerheight) self.outercontainer.bci(self.background) self.container = Div().ac("boardcontainer").w(self.width).h(self.height).t(self.margin).l(self.margin) self.container.bci(self.background) self.outercontainer.a(self.container) self.buildsquares() self.turndiv = Div().pa().w(self.turndivsize).h(self.turndivsize).bc(cpick(self.iswhitesturn(), "#fff", "#000")) if self.variantkey == "racingKings": self.turndiv.t(cpick(self.flip, 0, self.outerheight - self.turndivsize)) if xor(self.isblacksturn(), self.flip): self.turndiv.l(0) else: self.turndiv.l(self.outerwidth - self.turndivsize) else: self.turndiv.l(self.outerwidth - self.turndivsize).t(cpick(xor(self.isblacksturn(), self.flip), 0, self.outerheight - self.turndivsize)) self.outercontainer.a(self.turndiv) if self.promoting: self.buildprominput() self.container.ae("mousedown", self.promotecancelclick) self.fentext = TextInput({}).w(self.width).fs(10).setText(self.fen) self.fentext.changecallback = self.fentextchanged self.fendiv = Div().ac("boardfendiv").h(self.fendivheight).a(self.fentext) if self.variantkey == "crazyhouse": self.whitestorediv = Div().ac("boardstorediv").h(self.squaresize).w(self.outerwidth) self.whitestorediv.bci(self.background) self.blackstorediv = Div().ac("boardstorediv").h(self.squaresize).w(self.outerwidth) self.blackstorediv.bci(self.background) self.whitestore = PieceStore({ "show": self.show, "parent": self, "color": WHITE, "store": self.crazyfen, "containerdiv": self.whitestorediv }) self.blackstore = PieceStore({ "show": self.show, "parent": self, "color": BLACK, "store": self.crazyfen, "containerdiv": self.blackstorediv }) if self.flip: self.sectioncontainer.a([self.whitestorediv, self.outercontainer, self.blackstorediv]) else: self.sectioncontainer.a([self.blackstorediv, self.outercontainer, self.whitestorediv]) else: self.sectioncontainer.a([self.outercontainer]) if self.showfen: self.sectioncontainer.a(self.fendiv) self.x().a(self.sectioncontainer) self.movecanvas = Canvas(self.width, self.height).pa().t(0).l(0) self.movecanvashook = Div().pa().t(0).l(0).zi(5).op(0.5) self.piececanvashook = Div().pa().t(0).l(0).zi(11).op(0.5) self.arrowdiv = Div().pa() self.container.a([self.movecanvashook, self.arrowdiv, self.piececanvashook]) self.movecanvashook.a(self.movecanvas) self.buildgenmove() return self def setflip(self, flip): self.flip = flip self.build() def calcsizes(self): self.lastfile = self.numfiles - 1 self.lastrank = self.numranks - 1 self.area = self.numfiles * self.numranks self.width = self.numfiles * self.squaresize self.height = self.numranks * self.squaresize self.avgsize = ( self.width + self.height ) / 2 self.margin = self.marginratio * self.avgsize self.squarepadding = self.squarepaddingratio * self.squaresize self.piecesize = self.squaresize - 2 * self.squarepadding self.outerwidth = self.width + 2 * self.margin self.outerheight = self.height + 2 * self.margin self.turndivsize = self.margin self.fendivheight = 25 def parseargs(self, args): self.fentextchangedcallback = args.get("fentextchangedcallback", None) self.positioninfo = args.get("positioninfo", {}) self.show = args.get("show", False) self.showfen = args.get("showfen", True) self.squaresize = args.get("squaresize", 45) self.squarepaddingratio = args.get("squarepaddingratio", 0.04) self.marginratio = args.get("marginratio", 0.02) self.numfiles = args.get("numfiles", 8) self.numranks = args.get("numranks", 8) self.piecestyle = args.get("piecestyle", "alpha") self.flip = args.get("flip", False) self.movecallback = args.get("movecallback", None) self.background = "/static/img/backgrounds/" + args.get("background", "wood.jpg") self.calcsizes() def setpieceati(self, i, p): if ( i >= 0 ) and ( i < self.area ): self.rep[i] = p else: print("warning, rep index out of range", i) def getpieceati(self, i): if ( i >= 0 ) and ( i < self.area ): return self.rep[i] return Piece() def getpieceatfilerank(self, file, rank): i = rank * self.numfiles + file return self.getpieceati(i) def getpieceatsquare(self, sq): return self.getpieceatfilerank(sq.file, sq.rank) def setrepfromfen(self, fen): self.fen = fen self.crazyfen = None self.threefen = None self.rep = [Piece() for i in range(self.area)] fenparts = self.fen.split(" ") self.rawfen = fenparts[0] rawfenparts = self.rawfen.split("/") if self.variantkey == "crazyhouse": self.crazyfen = "" if "[" in self.rawfen: cfenparts = self.rawfen.split("[") self.rawfen = cfenparts[0] rawfenparts = self.rawfen.split("/") cfenparts = cfenparts[1].split("]") self.crazyfen = cfenparts[0] i = 0 for rawfenpart in rawfenparts: pieceletters = rawfenpart.split("") for pieceletter in pieceletters: if isvalidpieceletter(pieceletter): self.setpieceati(i, piecelettertopiece(pieceletter)) i+=1 else: mul = 0 try: mul = int(pieceletter) except: print("warning, multiplicity could not be parsed from", pieceletter) for j in range(mul): self.setpieceati(i, Piece()) i += 1 if i < self.area: print("warning, raw fen did not fill board") elif i > self.area: print("warning, raw fen exceeded board") self.turnfen = "w" if len(fenparts) > 1: self.turnfen = fenparts[1] else: print("warning, no turn fen") self.castlefen = "-" if len(fenparts) > 2: self.castlefen = fenparts[2] else: print("warning, no castle fen") self.epfen = "-" if len(fenparts) > 3: self.epfen = fenparts[3] else: print("warning, no ep fen") moveclocksi = cpick(self.variantkey == "threeCheck", 5, 4) self.halfmoveclock = 0 if len(fenparts) > moveclocksi: try: self.halfmoveclock = int(fenparts[moveclocksi]) except: print("warning, half move clock could not be parsed from", fenparts[4]) else: print("warning, no half move fen") self.fullmovenumber = 1 if len(fenparts) > ( moveclocksi + 1 ): try: self.fullmovenumber = int(fenparts[moveclocksi + 1]) except: print("warning, full move number could not be parsed from", fenparts[5]) else: print("warning, no full move fen") if self.variantkey == "threeCheck": if len(fenparts) > 4: self.threefen = fenparts[4] self.promoting = False def turn(self): if self.turnfen == "w": return WHITE return BLACK def iswhitesturn(self): return self.turn() == WHITE def isblacksturn(self): return self.turn() == BLACK def initrep(self, args): self.variantkey = args.get("variantkey", "standard") self.setrepfromfen(args.get("fen", getstartfenforvariantkey(self.variantkey))) def setfromfen(self, fen, positioninfo = {}): self.positioninfo = positioninfo self.setrepfromfen(fen) self.build() def reset(self): self.setfromfen(getstartfenforvariantkey(self.variantkey)) def __init__(self, args): super().__init__("div") self.positioninfo = {} self.parseargs(args) self.initrep(args) self.build()
class Client: def __init__(self): self.socket = None self.root = ge("clientroot") def signincallback(self): email = self.emailinput.getText() password = self.passwordinput.getText() print("signing in user with", email, password) firebase.auth().signInWithEmailAndPassword(email, password).then( lambda: print("ok"), lambda error: window.alert("{}".format(error)) ) def signoutcallback(self): if firebase.auth().currentUser: print("signing out") firebase.auth().signOut() else: window.alert("Already signed out.") def signupcallback(self): email = self.emailinput.getText() password = self.passwordinput.getText() print("signing up user with", email, password) firebase.auth().createUserWithEmailAndPassword(email, password).then( lambda: print("ok"), lambda error: window.alert("{}".format(error)) ) def sendverificationcallback(self): email = self.emailinput.getText() firebase.auth().currentUser.sendEmailVerification().then( lambda: window.alert("Verification email has been sent to {} !".format(email)), lambda error: window.alert("{}".format(error)) ) def resetpasswordcallback(self): email = self.emailinput.getText() firebase.auth().sendPasswordResetEmail(email).then( lambda: window.alert("Password reset email has been sent to {} !".format(email)), lambda error: window.alert("{}".format(error)) ) def updatedetailscallback(self): userdetails = { "displayname": self.displaynameinput.getText(), "photourl": self.photourlinput.getText() } self.sioreq({ "kind": "updateuserdetails", "uid": self.uid, "userdetails": userdetails }) def buildsignupdiv(self): self.signupdiv = Div() self.signupmaildiv = Div("signupmaildiv") self.emaillabel = Span().html("Email:") self.emailinput = TextInput().ac("profiletextinput").w(250) self.passwordlabel = Span().html("Password:"******"profiletextinput").w(100) self.signinbutton = Button("Sign in", self.signincallback) self.signoutbutton = Button("Sign out", self.signoutcallback) self.signupbutton = Button("Sign up", self.signupcallback) self.sendverificationbutton = Button("Send verification", self.sendverificationcallback) self.resetpasswordbutton = Button("Reset password", self.resetpasswordcallback) self.userinfodiv = Div("userinfodiv") self.signupmaildiv.a([self.emaillabel, self.emailinput, self.passwordlabel, self.passwordinput, self.signinbutton, self.signoutbutton, self.signupbutton, self.sendverificationbutton, self.resetpasswordbutton]) self.userdetailsdiv = Div("userdetailsdiv") self.displaynamelabel = Span().html("Display name:") self.displaynameinput = TextInput().ac("profiletextinput").w(250) self.photourllabel = Span().html("Photo url:") self.photourlinput = TextInput().ac("profiletextinput").w(250) self.updatedetailsbutton = Button("Update details", self.updatedetailscallback) self.userdetailsdiv.a([self.displaynamelabel, self.displaynameinput, self.photourllabel, self.photourlinput, self.updatedetailsbutton]) self.photodiv = Div("photodiv") self.signupdiv.a([self.signupmaildiv, self.userdetailsdiv, self.userinfodiv, self.photodiv]) self.firebaseuidiv = Div().sa("id", "firebaseuidiv") self.signupdiv.a(self.firebaseuidiv) def serializeconfig(self): self.sioreq({ "kind": "serializeconfig", "data": self.configschema.toargs() }) def storecloud(self): self.sioreq({ "kind": "storecloudconfig", "data": self.configschema.toargs() }) def retrievecloud(self): self.sioreq({ "kind": "retrievecloudconfig" }) def buildconfigdiv(self): self.configdiv = Div() self.configdiv.a(Button("Serialize", self.serializeconfig)) self.configdiv.a(Button("Store cloud", self.storecloud)) self.configdiv.a(Button("Retrieve cloud", self.retrievecloud)) self.configschema = Schema(self.schemaconfig) self.configdiv.a(self.configschema) def build(self): self.root.innerHTML = "" self.buildconfigdiv() self.signupdiv = Div() if self.authenabled: self.buildsignupdiv() self.profiletab = Tab("profile", "Profile", self.signupdiv) self.mainelement = TabPane({ "id": "maintabpane", "fillwindow": True, "tabs": [ Tab("main", "Main", Div("contentplaceholder").html("Main.")), Tab("config", "Config", self.configdiv), Tab("upload", "Upload", FileUploader({"url": "/upload"})), Tab("log", "Log", Div("contentplaceholder").html("Log.")), self.profiletab, Tab("about", "About", Div("contentplaceholder").html("About.")) ], "selected": "upload" }) self.root.appendChild(self.mainelement.e) def onconnect(self): self.sioreq({"kind": "connected"}) def sioreq(self, obj): print("->", obj) self.socket.emit("sioreq", obj) def getuserdisplayname(self): if self.user: if self.displayName: return self.displayName return self.email return None def setprofiletab(self): self.profiletab.rc(["profilelogged", "profileanon"]) dn = self.getuserdisplayname() if dn: self.profiletab.container.html(dn) self.profiletab.ac("profilelogged") else: if self.user: self.profiletab.container.html("Anonymous") self.profiletab.ac("profileanon") else: self.profiletab.container.html("Profile") def signinanonymously(self): firebase.auth().signInAnonymously().then( lambda: print("ok"), lambda error: print(error) ) def userstatusverbal(self): if not self.user: return "[logged out]" if self.user.isAnonymous: return "anonymous" return cpick(self.emailVerified, "verified", "not verified") def userverified(self): if not self.user: return False if self.user.isAnonymous: return False return self.user.emailVerified def authstatechanged(self, user): self.user = user self.passwordinput.setText("") if user: self.displayName = user.displayName self.email = user.email self.emailVerified = user.emailVerified self.photoURL = user.photoURL self.isAnonymous = user.isAnonymous self.uid = user.uid self.providerData = user.providerData print("user", self.displayName, self.email) print(self.providerData) self.nameinfodiv = Div().html("name : <span class='{}'>{}</span>".format(cpick(self.displayName, "uiinfo", "uiinfored"), getelse(self.displayName,"<NA>"))).pt(5) self.emailinfodiv = Div().html("email : <span class='{}'>{}</span>".format(cpick(self.email, "uiinfo", "uiinfored"), getelse(self.email, "<NA>"))) self.verifiedinfodiv = Div().html("status : <span class='{}'>{}</span>".format(cpick(self.userverified(), "uiinfo", "uiinfored"), self.userstatusverbal())) self.photourldiv = Div().html("photo url : <span class='{}'>{}</span>".format(cpick(self.photoURL, "uiinfo", "uiinfored"), getelse(self.photoURL,"<NA>"))) self.uidinfodiv = Div().html("uid : <span class='uiinfo'>{}</span>".format(self.uid)).pb(8) self.userinfodiv.x().a([self.nameinfodiv, self.emailinfodiv, self.verifiedinfodiv, self.photourldiv, self.uidinfodiv]) self.emailinput.setText(self.email) self.displaynameinput.setText(self.displayName) self.photourlinput.setText(self.photoURL) self.photodiv.x() if self.photoURL: self.photodiv.html("<img src='{}'></img>".format(self.photoURL)) else: print("no user") self.userinfodiv.x().a([ Div().html("Please sign up or sign in !"), Button("Sign in anonymously", self.signinanonymously()) ]) self.setprofiletab() self.userinfodiv.fs(cpick(self.user, 10, 14)) def getschemaconfigfromobj(self, obj): self.schemaconfig = { "kind": "collection", "disposition": "dict" } if "schemaconfig" in obj: self.schemaconfig = obj["schemaconfig"] self.authenabled = ( getrec("global/auth/enabled", self.schemaconfig) == "true" ) def initializefirebase(self): print("initializing firebase from", self.firebaseconfig) firebase.initializeApp(self.firebaseconfig) firebase.auth().onAuthStateChanged(self.authstatechanged) def initializefirebaseui(self): self.uiConfig = { "signInSuccessUrl": '/', "signInOptions": [ firebase.auth.GoogleAuthProvider.PROVIDER_ID, #firebase.auth.FacebookAuthProvider.PROVIDER_ID, #firebase.auth.TwitterAuthProvider.PROVIDER_ID, #firebase.auth.GithubAuthProvider.PROVIDER_ID, firebase.auth.EmailAuthProvider.PROVIDER_ID, #firebase.auth.PhoneAuthProvider.PROVIDER_ID ], "tosUrl": '/tos' } print("initializing firebase ui from", self.uiConfig) self.ui = __new__(firebaseui.auth.AuthUI(firebase.auth())) self.ui.start(self.firebaseuidiv.e, self.uiConfig) def startfirebase(self): self.initializefirebase() self.initializefirebaseui() def siores(self, obj): print("<-", obj) if "kind" in obj: kind = obj["kind"] if kind == "connectedack": self.getschemaconfigfromobj(obj) self.build() if self.authenabled: self.firebaseconfig = obj["firebaseconfig"] setTimeout(self.startfirebase, 50) elif kind == "configsaved": window.alert("Config saved, {} characters".format(obj["size"])) elif kind == "setcloudconfig": self.getschemaconfigfromobj(obj) self.build() setTimeout(lambda: window.alert("Config set from cloud."), 10) elif kind == "alert": window.alert(obj["data"]) if obj["reload"]: location.reload() def startup(self): print("creating socket {}".format(SUBMIT_URL)) self.socket = io.connect(SUBMIT_URL) print("socket created ok") self.socket.on('connect', self.onconnect) self.socket.on('siores', self.siores) ######################################################
class Config(e): def serializeconfig(self): getconn().sioreq({ "kind": "serializeconfig", "data": self.configschema.toargs(), "owner": self.id }) def serializelocalstorage(self): getconn().sioreq({ "kind": "serializelocalstorage", "data": JSON.stringify(localStorage), "owner": self.id }) def synclocalstorage(self): getconn().sioreq({"kind": "synclocalstorage", "owner": self.id}) def siores(self, response): try: kind = response["kind"] if kind == "localstoragesaved": window.alert("Local storage saved. Size {} characters.".format( response["size"])) elif kind == "synclocalstorage": obj = response["data"] i = 0 __pragma__("jsiter") for key in obj: localStorage.setItem(key, obj[key]) i += 1 __pragma__("nojsiter") window.alert( "Setting {} key(s) in localstorage done. Press ok to reload." .format(i)) document.location.reload() except: print("there was a problem processing config siores") def resize(self, width, height): self.configsplitpane.resize(width, height) def build(self): self.configsplitpane = SplitPane({"controlheight": 50}) self.configdiv = Div("largesheet") self.configsplitpane.controlpanel.a([ Button("Serialize config", self.serializeconfig).ac("controlbutton"), Button("Serialize localstorage", self.serializelocalstorage).ac("controlbutton"), Button("Sync localstorage", self.synclocalstorage).ac("controlbutton") ]) self.configsplitpane.controlpanel.ac("subcontrolpanel") self.configschema = Schema(self.schemaconfig) self.configdiv.a(self.configschema) self.configsplitpane.setcontentelement(self.configdiv) self.x().a(self.configsplitpane) def setschemaconfig(self, schemaconfig): self.schemaconfig = schemaconfig self.build() def get(self, path, default): return getrecm(path, self.configschema, default) def getpath(self, path): return self.configschema.getpath(path) def __init__(self, args={}): super().__init__("div") self.id = args.get("id", "config") self.schemaconfig = {"kind": "collection", "disposition": "dict"} self.build()
class Schema(e): def copydivclicked(self): global clipboard clipboard = self.toargs() def openbuttonclicked(self): self.childsopened = not self.childsopened self.build() def createcombochanged(self, v): if v == "scalar": sch = Schema({"parent": self, "kind": "scalar"}) elif v == "dict": sch = Schema({ "parent": self, "kind": "collection", "disposition": "dict" }) elif v == "list": sch = Schema({ "parent": self, "kind": "collection", "disposition": "list" }) self.childs.append(sch) self.build() def stringvalueinputchanged(self): self.value = self.stringvalueinput.getText() def keyinputchanged(self): self.key = self.keyinput.getText() def deletechild(self, child): global clipboard newchilds = [] for currchild in self.childs: if not (currchild == child): newchilds.append(currchild) else: clipboard = child.toargs() self.childs = newchilds self.build() def deletedivclicked(self): self.parent.deletechild(self) def pastebuttonpushed(self): global clipboard if clipboard: clipboard["parent"] = self sch = Schema(clipboard) self.childs.append(sch) self.build() def build(self): self.x().ac("schema") self.itemdiv = Div(["item", self.disposition]) self.valuediv = Div(["value", self.disposition]) if self.kind == "scalar": if self.disposition == "string": self.stringvalueinput = TextInput().ac("string").setText( self.value) self.stringvalueinput.ae("keyup", self.stringvalueinputchanged) self.valuediv.a(self.stringvalueinput) self.helpdiv = Div(["box", "help"]).html("?") self.copydiv = Div(["box", "copy"]).html("C").ae("mousedown", self.copydivclicked) if isdict(self.parent): self.keydiv = Div("key") self.keyinput = TextInput().ac("key").setText(self.key) self.keyinput.ae("keyup", self.keyinputchanged) self.keydiv.a(self.keyinput) self.itemdiv.a(self.keydiv) self.itemdiv.a([self.valuediv, self.helpdiv, self.copydiv]) if self.parent: self.deletediv = Div(["box", "delete" ]).html("X").ae("mousedown", self.deletedivclicked) self.itemdiv.a(self.deletediv) if iscollection(self): self.openbutton = Div("openbutton").ae("mousedown", self.openbuttonclicked) self.valuediv.a(self.openbutton) self.childsdiv = Div("childs") if self.childsopened: self.creatediv = Div("create") cc = self.createcombo self.createcombo = ComboBox().setoptions( [["create", "Create new"], ["scalar", "Scalar"], ["dict", "Dict"], ["list", "List"]], "create", self.createcombochanged).ac("createcombo") self.creatediv.a(self.createcombo) self.pastebutton = Button("Paste", self.pastebuttonpushed).ac("pastebutton") self.creatediv.a(self.pastebutton) self.childsdiv.a(self.creatediv) for child in self.childs: self.childsdiv.a(child) self.container = Div("container") self.container.a([self.itemdiv, self.childsdiv]) self.a(self.container) return self def tojsontext(self): return JSON.stringify(self.toargs(), None, 2) def toargs(self): args = {} for arg in SCHEMA_DEFAULT_ARGS: args[arg[0]] = self[arg[0]] args["childsarg"] = [] for child in self.childs: args["childsarg"].append(child.toargs()) return args def __init__(self, args={}): super().__init__("div") self.parent = getitem(args, "parent", None) for arg in SCHEMA_DEFAULT_ARGS: self[arg[0]] = getitem(args, arg[0], arg[1]) self.childs = [] for childarg in self.childsarg: childarg["parent"] = self child = Schema(childarg) self.childs.append(child) self.build()
class Forumnode(e): def __init__(self, root, args={}): super().__init__("div") self.root = root self.move = args["move"] self.uci = args["uci"] self.comment = args["comment"] if not self.comment: self.comment = "" self.owner = args["owner"] self.fen = args["fen"] self.parent = args["parent"] self.isadmin = args["isadmin"] self.halfmoveno = args["halfmoveno"] if not self.halfmoveno: self.halfmoveno = -1 self.childs = [] self.build() def toobj(self): moveobjs = {} for child in self.childs: moveobjs[child.move] = child.toobj() return { "uci": self.uci, "comment": self.comment, "owner": self.owner, "fen": self.fen, "moves": moveobjs } def appendchild(self, node): node.halfmoveno = self.halfmoveno + 1 node.build() self.childs.append(node) self.containerdiv.a(node) if len(self.childs) > 1: rgb = "rgb({},{},{})".format(int(random() * 128 + 127), int(random() * 128 + 127), int(random() * 128 + 127)) self.containerdiv.bc(rgb).bds("solid").bdw(10).bdr(20).bdc(rgb) def addnode(self): input = window.prompt("Move:uci:owner:fen", "") if input: self.root.shift() parts = input.split(":") self.appendchild( Forumnode( self.root, { "move": parts[0], "uci": None, "comment": "", "uci": parts[0], "owner": parts[2], "fen": parts[2], "parent": self, "isadmin": self.isadmin })) self.root.parse() def edituci(self): input = window.prompt("Uci", "") if input: self.uci = input self.setboard() self.ucidiv.html(self.uci) self.root.parse() def editfen(self): input = window.prompt("Fen", "") if input: self.fen = input self.setboard() self.root.parse() def setmovelabel(self): if self.halfmoveno < 0: moveno = "" elif (self.halfmoveno % 2) == 0: moveno = ((self.halfmoveno + 2) / 2) + ". " else: moveno = ((self.halfmoveno + 1) / 2) + ".. " self.movelabeldiv.html("{}{}".format(moveno, self.move)) def editsan(self): input = window.prompt("San", "") if input: self.move = input self.setmovelabel() self.root.parse() def editcomment(self): input = window.prompt("Comment", self.comment) if input: self.comment = input self.commentdiv.html(self.comment) self.root.parse() def editowner(self): input = window.prompt("Owner", "") if input: self.owner = input self.ownerdiv.html(self.owner) self.root.parse() def movecallback(self, variantkey, fen, uci): if self.reqfenunderway: print("a fen request is in progress, cannot start a new one") return self.root.shift() self.root.reqfenunderway = True self.root.reqnode = self getconn().sioreq({ "kind": "forumgamemove", "owner": "forumgame", "moveuci": uci, "variantkey": variantkey, "fen": fen }) def bbdragstart(self, ev): ev.stopPropagation() def setboard(self): initobj = { "fen": self.fen, "squaresize": 20, "showfen": False, "movecallback": self.movecallback, "variantkey": "atomic" } if self.uci: initobj["positioninfo"] = {"genmove": {"uci": self.uci}} b = BasicBoard(initobj) b.cp().ae("dragstart", self.bbdragstart) self.boarddiv.x().a(b) def analyzelocal(self): try: self.root.mainboard.variantchanged("atomic", self.fen) self.root.parenttabpane.selectbykey("board") except: pass def analyzelichess(self): window.open("https://lichess.org/analysis/atomic/" + self.fen, "_blank") def delchilds(self): self.childs = [] self.root.rebuild(mainseed) def delme(self): parent = self.parent if parent: newchilds = [] for child in parent.childs: print("child", child.move, child.uci) if not (child == self): newchilds.append(child) parent.childs = newchilds self.root.rebuild(mainseed) def serializefunc(self): self.root.rebuild(mainseed + 1) self.root.store() def serialize(self): self.infohook.html("serializing") setTimeout(self.serializefunc, 100) def copysrc(self): self.root.copysrc() def copylink(self): ti = TextInput() self.linktexthook.a(ti) ti.setText("https://fbserv.herokuapp.com/analysis/atomic/" + self.fen.replace(" ", "%20")) ti.e.select() document.execCommand("copy") self.linktexthook.x() def build(self): self.movediv = Div().disp("flex").fd("row").ai("center") self.movedescdiv = Div().bc("#eee").w(110).maw(110).pad(3) self.movelabeldiv = Div().fw("bold").pad(3).ff("monospace") self.setmovelabel() self.ownerdiv = Div().html( self.owner).ff("monospace").fs("10").c("#007") self.ucidiv = Div().ff("monospace").fs("12").pad(3) self.commentdiv = Div().fs("12").pad(5).html(self.comment) if self.uci: self.ucidiv.html(self.uci) self.movedescdiv.a([self.movelabeldiv, self.ownerdiv, self.commentdiv]) self.movedescdiv.a(Button("Analyze local", self.analyzelocal).mar(2)) self.movedescdiv.a( Button("Analyze lichess", self.analyzelichess).mar(2)) self.infohook = Div().ff("monospace").pad(3).c("#007").fw("bold").html( "built") if self.isadmin: self.movedescdiv.a(self.infohook) self.linktexthook = Div() self.movedescdiv.a(self.ucidiv) self.movedescdiv.a(Button("+", self.addnode).pad(5)) self.movedescdiv.a(Button("san", self.editsan).pad(5)) self.movedescdiv.a(Button("uci", self.edituci).pad(5)) self.movedescdiv.a(Button("fen", self.editfen).pad(5)) self.movedescdiv.a(Button("comment", self.editcomment).pad(5)) self.movedescdiv.a(Button("owner", self.editowner).pad(5)) self.movedescdiv.a( Button("serialize", self.serialize).pad(5).bc("#ffa")) self.movedescdiv.a(Button("copy", self.copysrc).pad(5).bc("#afa")) self.movedescdiv.a(self.linktexthook) self.movedescdiv.a(Button("link", self.copylink).pad(5).bc("#aff")) self.movedescdiv.a( Button("delchilds", self.delchilds).pad(5).bc("#faa")) self.movedescdiv.a(Button("delme", self.delme).pad(5).bc("#faa")) self.boarddiv = Div().pad(2) self.movecontainerdiv = Div().disp("flex").fd("row").ai("center") self.movecontainerdiv.a([self.movedescdiv, self.boarddiv]) self.containerdiv = Div().disp("flex").fd("column").ai("flex-start") self.movediv.a([self.movecontainerdiv, self.containerdiv]) self.setboard() self.x().a(self.movediv) self.mw(600)
class Forumgame(e): def __init__(self): super().__init__("div") self.messagediv = Div().disp("inline-block").pad(3).ff("monospace") self.contentdiv = Div() self.a([self.messagediv, self.contentdiv]) self.reqfenunderway = False self.reqnode = None self.requestforumgame() self.ae("mousemove", self.mousemove) self.ae("mouseup", self.mouseup) self.ae("mouseleave", self.mouseleave) def copysrc(self): self.textarea.e.select() document.execCommand("copy") window.alert("Copied source to clipboard, {} characters.".format( len(self.textarea.getText()))) def mousemove(self, ev): if self.dragunderway: dx = ev.clientX - self.dragstartx dy = ev.clientY - self.dragstarty self.parenttabpane.contentdiv.e.scrollTop = self.scrolltop + 20 * dy self.parenttabpane.contentdiv.e.scrollLeft = self.scrollleft + 20 * dx def mouseup(self, ev): self.dragunderway = False def mouseleave(self, ev): self.dragunderway = False def parse(self): obj = self.rootnode.toobj() text = JSON.stringify(obj, None, 2) self.textarea.setText(text) return text def store(self): self.parenttabpane.contentdiv.bc("#faa") self.messagediv.html("Parsing JSON") try: obj = JSON.parse(self.textarea.getText()) self.messagediv.html("Storing JSON") getconn().sioreq({ "kind": "setforumgame", "owner": "forumgame", "forumgame": obj }) except: self.messagediv.html("Error: could not parse JSON") return def requestforumgame(self): getconn().sioreq({"kind": "getforumgame", "owner": "forumgame"}) def buildrec(self, parentnode, tree): __pragma__("jsiter") if not tree["moves"]: return for move in tree["moves"]: moveobj = tree["moves"][move] node = Forumnode( self, { "move": move, "uci": moveobj["uci"], "comment": moveobj["comment"], "owner": moveobj["owner"], "fen": moveobj["fen"], "parent": parentnode, "isadmin": self.isadmin }) parentnode.appendchild(node) self.buildrec(node, moveobj) __pragma__("nojsiter") def build(self, text, seed): setseed(seed) self.contentdiv.x().pad(3) self.textarea = TextArea().w(1000).h(200) self.textarea.setText(text) self.controlpanel = Div() self.controlpanel.a(Button("Store", self.store)) if self.isadmin: self.contentdiv.a(self.textarea) self.contentdiv.a(self.controlpanel) self.rootnode = Forumnode( self, { "move": "startpos", "uci": None, "owner": "Wolfram_EP", "comment": "Forum game", "fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "parent": None, "isadmin": self.isadmin }) self.contentdiv.a(self.rootnode) self.buildrec(self.rootnode, self.forumgame) #self.rootnode.e.scrollIntoView(True) self.parenttabpane.setscroll() self.contentdiv.sa("draggable", True).cm().ae("dragstart", self.dragstart) def dragstart(self, ev): ev.preventDefault() self.dragstartx = ev.clientX self.dragstarty = ev.clientY self.scrolltop = self.parenttabpane.contentdiv.e.scrollTop self.scrollleft = self.parenttabpane.contentdiv.e.scrollLeft self.dragunderway = True def rebuild(self, seed): text = self.parse() self.forumgame = JSON.parse(text) self.build(text, seed) def shift(self): sl = self.parenttabpane.contentdiv.e.scrollLeft self.parenttabpane.contentdiv.e.scrollLeft = sl + 300 def siores(self, response): if response["kind"] == "setforumgame": self.forumgame = response["forumgame"] self.messagediv.html("Forumgame loaded") self.isadmin = response["isadmin"] if queryparams.get("noadmin", "false") == "true": self.isadmin = False self.build(JSON.stringify(self.forumgame, None, 2), mainseed) self.parenttabpane.contentdiv.bc("#def") if response["kind"] == "setforumgamedone": self.messagediv.html("Stored, refreshing") self.requestforumgame() if response["kind"] == "setforumgamefen": posinfo = response["positioninfo"] fen = response["fen"] san = posinfo["genmove"]["san"] uci = posinfo["genmove"]["uci"] rp = self.reqnode.parent owner = None if rp: owner = rp.owner if not owner: owner = window.prompt("Owner", "?") if not owner: owner = "?" self.reqnode.appendchild( Forumnode( self, { "move": san, "uci": uci, "comment": "", "owner": owner, "fen": fen, "parent": self.reqnode, "isadmin": self.isadmin })) self.parse()
class Schema(e): def copydivclicked(self): global clipboard clipboard = self.toargs() def openbuttonclicked(self): self.childsopened = not self.childsopened self.build() def createcombochanged(self, v): if v == "scalar": sch = Schema({ "parent": self, "kind": "scalar", "disposition": "string" }) elif v == "slider": sch = Schema({ "parent": self, "kind": "scalar", "disposition": "slider" }) elif v == "checkbox": sch = Schema({ "parent": self, "kind": "scalar", "disposition": "checkbox" }) elif v == "textarea": sch = Schema({ "parent": self, "kind": "scalar", "disposition": "textarea" }) elif v == "date": sch = Schema({ "parent": self, "kind": "scalar", "disposition": "date", "value": dateToDateInputStr(__new__(Date())) }) elif v == "color": sch = Schema({ "parent": self, "kind": "scalar", "disposition": "color", "value": "#ffffff" }) elif v == "dict": sch = Schema({ "parent": self, "kind": "collection", "disposition": "dict" }) elif v == "list": sch = Schema({ "parent": self, "kind": "collection", "disposition": "list" }) elif v == "combo": sch = Schema({ "parent": self, "kind": "collection", "disposition": "combo" }) elif v == "radio": sch = Schema({ "parent": self, "kind": "collection", "disposition": "radio" }) elif v == "process": sch = Schema({ "parent": self, "kind": "collection", "disposition": "dict", "childsopened": True, "childsarg": [{ "kind": "scalar", "disposition": "string", "key": "key" }, { "kind": "scalar", "disposition": "string", "key": "displayname" }, { "kind": "scalar", "disposition": "string", "key": "command" }, { "kind": "collection", "disposition": "list", "key": "command_args" }] }) self.childs.append(sch) self.build() def stringvalueinputchanged(self): self.value = self.stringvalueinput.getText() def keyinputchanged(self): self.key = self.keyinput.getText() def deletechild(self, child): global clipboard newchilds = [] for currchild in self.childs: if not (currchild == child): newchilds.append(currchild) else: clipboard = child.toargs() self.childs = newchilds self.build() def deletedivclicked(self): self.parent.deletechild(self) def pastebuttonpushed(self): global clipboard if clipboard: clipboard["parent"] = self sch = Schema(clipboard) self.childs.append(sch) self.build() def setslidervalue(self, value, doslider=True): self.value = float(value) if self.value < self.minvalue: self.value = self.minvalue if self.value > self.maxvalue: self.value = self.maxvalue if doslider: self.slider.sv(self.value) self.slidervalueinput.setText("{}".format(self.value)) def minvalueinputchanged(self): self.minvalue = texttofloat(self.minvalueinput.getText(), self.minvalue) self.slider.setmin(self.minvalue) self.setslidervalue(self.value) def maxvalueinputchanged(self): self.maxvalue = texttofloat(self.maxvalueinput.getText(), self.maxvalue) self.slider.setmax(self.maxvalue) self.setslidervalue(self.value) def sliderstepinputhchanged(self): self.valuestep = texttofloat(self.sliderstepinput.getText(), self.valuestep) self.slider.setstep(self.valuestep) self.setslidervalue(self.value) def sliderchanged(self): self.setslidervalue(self.slider.v(), False) def slidervalueinputchanged(self): self.setslidervalue( texttofloat(self.slidervalueinput.getText(), self.value)) def checkboxchanged(self): self.value = self.checkbox.getchecked() def combocheckboxchanged(self): self.selected = self.combocheckbox.getchecked() def radioradioclicked(self): for child in self.parent.childs: isme = (child == self) child.radioradio.setchecked(isme) child.selected = isme print(isme) def textareachanged(self): self.value = self.textarea.getText() def setdatelabel(self): self.datelabel.html("{}".format( dateInputStrToDate(self.value).getTime())) def datechanged(self): self.value = self.date.v() self.setdatelabel() def colorchanged(self): self.value = self.color.v() self.colorlabel.html(self.value) def build(self): self.x().ac("schema") self.itemdiv = Div(["item", self.disposition]) self.valuediv = Div(["value", self.disposition]) if self.kind == "scalar": if self.disposition == "dict": if type(self.value) == bool: self.disposition = "checkbox" else: self.disposition = "string" if self.disposition == "string": self.stringvalueinput = TextInput().ac("string").setText( self.value) self.stringvalueinput.ae("keyup", self.stringvalueinputchanged) self.valuediv.a(self.stringvalueinput) elif self.disposition == "slider": self.slidervalueinput = TextInput().ac("slidervalue").setText( self.value).setchangecallback(self.slidervalueinputchanged) self.minvalueinput = TextInput().ac("sliderminmax").setText( self.minvalue).setchangecallback(self.minvalueinputchanged) self.slider = Slider().ac("sliderslider").ae( "change", self.sliderchanged) self.maxvalueinput = TextInput().ac("sliderminmax").setText( self.maxvalue).setchangecallback(self.maxvalueinputchanged) self.sliderstepinput = TextInput().ac("sliderstep").setText( self.valuestep).setchangecallback( self.sliderstepinputhchanged) self.valuediv.a([ self.slidervalueinput, self.minvalueinput, self.slider, self.maxvalueinput, self.sliderstepinput ]) self.slider.setmin(self.minvalue).setmax( self.maxvalue).setstep(self.valuestep) self.setslidervalue( texttofloat(self.value, SCHEMA_SLIDER_DEFAULT_VALUE)) elif self.disposition == "checkbox": self.value = (self.value is True) self.checkbox = CheckBox().ac("checkbox").setchecked( self.value).ae("change", self.checkboxchanged) self.valuediv.a(self.checkbox) elif self.disposition == "textarea": self.textarea = TextArea().ac("textarea").setText(self.value) self.textarea.ae(["keyup", "change"], self.textareachanged) self.valuediv.a(self.textarea) elif self.disposition == "date": self.date = DateInput().ac("date").sv(self.value) self.date.ae(["keyup", "change"], self.datechanged) self.datelabel = Label().ac("datelabel") self.setdatelabel() self.valuediv.a([self.date, self.datelabel]) elif self.disposition == "color": self.color = ColorInput().ac("color").sv(self.value) self.color.ae(["keyup", "change"], self.colorchanged) self.colorlabel = Label().ac("colorlabel").html(self.value) self.valuediv.a([self.color, self.colorlabel]) self.helpdiv = Div(["box", "help"]).html("?") self.copydiv = Div(["box", "copy"]).html("C").ae("mousedown", self.copydivclicked) if isdict(self.parent): self.keydiv = Div("key") self.keyinput = TextInput().ac("key").setText(self.key) self.keyinput.ae("keyup", self.keyinputchanged) self.keydiv.a(self.keyinput) self.itemdiv.a(self.keydiv) if iscombo(self.parent): self.combodiv = Div(["box", "combo"]) self.combocheckbox = CheckBox().ac("checkbox").setchecked( self.selected).ae("change", self.combocheckboxchanged) self.combodiv.a(self.combocheckbox) self.itemdiv.a(self.combodiv) if isradio(self.parent): self.radiodiv = Div(["box", "radio"]) self.radioradio = Radio().ac("radio").setchecked(self.selected).ae( "mousedown", self.radioradioclicked) self.radiodiv.a(self.radioradio) self.itemdiv.a(self.radiodiv) self.itemdiv.a([self.valuediv, self.helpdiv, self.copydiv]) if self.parent: self.deletediv = Div(["box", "delete" ]).html("X").ae("mousedown", self.deletedivclicked) self.itemdiv.a(self.deletediv) if iscollection(self): self.openbutton = Div("openbutton").ae("mousedown", self.openbuttonclicked) self.valuediv.a(self.openbutton) self.childsdiv = Div("childs") if self.childsopened: self.creatediv = Div("create") cc = self.createcombo self.createcombo = ComboBox().setoptions( [["create", "Create new"], ["scalar", "Scalar"], ["slider", "Slider"], ["checkbox", "Checkbox"], ["textarea", "Textarea"], ["date", "Date"], [ "color", "Color" ], ["dict", "Dict"], ["list", "List"], ["combo", "Combo"], ["radio", "Radio"], ["process", "Process"]], "create", self.createcombochanged).ac("createcombo") self.creatediv.a(self.createcombo) self.pastebutton = Button("Paste", self.pastebuttonpushed).ac("pastebutton") self.creatediv.a(self.pastebutton) self.childsdiv.a(self.creatediv) for child in self.childs: self.childsdiv.a(child) self.container = Div("container") self.container.a([self.itemdiv, self.childsdiv]) self.a(self.container) return self def tojsontext(self): return JSON.stringify(self.toargs(), None, 2) def toargs(self): args = {} for arg in SCHEMA_DEFAULT_ARGS: args[arg[0]] = self[arg[0]] args["childsarg"] = [] for child in self.childs: args["childsarg"].append(child.toargs()) return args def __init__(self, args={}): super().__init__("div") self.parent = getitem(args, "parent", None) for arg in SCHEMA_DEFAULT_ARGS: self[arg[0]] = getitem(args, arg[0], arg[1]) self.childs = [] for childarg in self.childsarg: childarg["parent"] = self child = Schema(childarg) self.childs.append(child) self.build() def getchildbykey(self, key): for child in self.childs: if child.key == key: return child return None def getpathrec(self, sch, pathparts): if not sch: return None if len(pathparts) == 0: return sch key = pathparts[0] pathparts = pathparts[1:] if self.disposition == "dict": return self.getpathrec(self.getchildbykey(key), pathparts) else: return None def getpath(self, path): if path == "": pathparts = [] else: pathparts = path.split("/") return self.getpathrec(self, pathparts)
class Client: def __init__(self): self.isadmin = False self.root = ge("clientroot") self.owners = {} self.config = Config() self.authdone = False self.connectdone = False def driveeditclickedcallback(self, dir): ext = getext(dir) if ext == "bin": self.mainboard.setbookpath(dir, True) self.mainboard.tabpane.selectbykey("book") self.tabs.selectbykey("board") self.mainboard.getbookpage() return True def requestbots(self): getconn().sioreq({"kind": "getmybots"}) def createbotdiv(self): self.botdiv = Div() self.botresultdiv = Div() self.botdiv.a(Button("Request bots", self.requestbots).mar(10)) self.botdiv.a(Hlink("/bots", "Bots page")) self.botdiv.a(self.botresultdiv) def build(self): self.root.innerHTML = "" self.owners["config"] = self.config if self.dodirbrowser: self.maindirbrowser = DirBrowser({"id": "maindirbrowser"}) self.owners["maindirbrowser"] = self.maindirbrowser else: self.maindirbrowser = Div() if self.dodrive: self.drive = DirBrowser({ "id": "drive", "drive": True, "editclickedcallback": self.driveeditclickedcallback }) self.owners["drive"] = self.drive else: self.drive = Div() self.createbotdiv() if self.doboard: self.mainboard = Board({ "dobook": self.dobook, "dostoredanalysis": self.dostoredanalysis, "dostoredauto": self.dostoredauto, "dogames": self.dogames, "setposinfo": self.setposinfo, "dogamepreview": self.dogamepreview, "background": self.boardbackground, "autoanalysisdelay": self.autoanalysisdelay, "maxgames": self.maxgames, "gamesfilter": self.gamesfilter, "analysispvlength": self.analysispvlength }) self.mainboard.setusername(self.username, self.usertoken) self.mainboard.tabpane.controlpanel.ac("subcontrolpanel") self.owners["mainboard"] = self.mainboard else: self.mainboard = Div() if self.dodocs: self.doc = Doc() self.srcdiv = self.doc.srcdiv self.owners["doc"] = self.doc else: self.doc = Div() self.srcdiv = Div() if self.doabout: self.about = Doc({ "id": "about", "startpage": "about", "showcontentslink": False }) self.owners["about"] = self.about else: self.about = Div() if self.isadmin: self.processpane = ProcessPane( {"configsch": self.config.getpath("processes")}) self.processpane.processtabpane.controlpanel.ac("subcontrolpanel") else: self.processpane = Div("featureplaceholder").html( "Admin only feature.") self.forumgametab = Tab( "forumgame", "Forum game", Div("featureplaceholder").html("Forum game disabled.")) if self.doforumgame: self.forumgame = Forumgame() self.forumgame.mainboard = self.mainboard self.owners["forumgame"] = self.forumgame self.forumgametab = Tab("forumgame", "Forum game", self.forumgame) self.tabs = TabPane({ "id": "maintabpane", "fillwindow": True, "tabs": [ Tab("config", "Config", self.config), Tab("upload", "Upload", FileUploader({"url": "/upload"})), Tab("board", "Board", self.mainboard), self.forumgametab, Tab("process", "Process", self.processpane), Tab("dirbrowser", "Dirbrowser", self.maindirbrowser), Tab("drive", "Drive", self.drive), Tab("bots", "Bots", self.botdiv), Tab("doc", "Doc", self.doc), Tab("src", "Src", self.srcdiv), Tab("log", "Log", getconn().log), getconn().profiletab, Tab("about", "About", self.about) ], "selected": "drive" }) self.root.appendChild(self.tabs.e) qseltab = queryparams.get("tab", None) if qseltab: self.tabs.selectbykey(qseltab) def onready(self): getconn().sioreq({"kind": "connected", "queryparams": queryparams}) def setloadinfo(self, content): ge("connectmsg").innerHTML = content def onconnect(self): self.connectdone = True if self.authdone: self.onready() else: self.setloadinfo("Authenticating, please wait ...") def onauth(self): self.authdone = True if self.connectdone: self.onready() else: self.setloadinfo( "Authenticated, connecting to server, please wait ...") def getschemaconfigfromobj(self, obj): self.config.setschemaconfig(obj["schemaconfig"]) self.dodocs = self.config.get("global/dodocs", True) self.dobook = self.config.get("global/dobook", True) self.username = self.config.get("global/username") self.usertoken = self.config.get("global/usertoken") self.dostoredanalysis = self.config.get("global/dostoredanalysis", True) self.dodirbrowser = self.config.get("global/dodirbrowser", True) self.dodrive = self.config.get("global/dodrive", True) self.dogames = self.config.get("global/dogames", True) self.doboard = self.config.get("global/doboard", True) self.doabout = self.config.get("global/doabout", True) self.dogamepreview = self.config.get("global/dogamepreview", True) self.doforumgame = self.config.get("global/doforumgame", True) self.dostoredauto = self.config.get("global/dostoredauto", True) self.boardbackground = self.config.get("layout/boardbackground", "wood.jpg") self.autoanalysisdelay = self.config.get("global/autoanalysisdelay", True) self.maxgames = self.config.get("global/maxgames", 25) self.gamesfilter = self.config.get("global/gamesfilter", "") self.analysispvlength = self.config.get("global/analysispvlength", 4) self.setposinfo = obj["setposinfo"] def buildfromconfiginobj(self, obj): self.getschemaconfigfromobj(obj) self.build() def setmybots(self, obj): botprofiles = obj["mybots"] self.botresultdiv.x() __pragma__("jsiter") for id in botprofiles: botprofile = botprofiles[id] self.botresultdiv.a(Div().html("{} {}".format( botprofile["username"], cpick(botprofile["online"], "online", "offline"))).fs(25).pad(5)) self.botresultdiv.a(Div().html( "follow {} games {} last move {}".format( botprofile["nbFollowers"], botprofile["count"]["all"], botprofile["lastmoveago"])).fs(20).pad(3)) self.botresultdiv.a(Div().html("last players {}".format( botprofile["lastplayers"])).fs(20).pad(3)) __pragma__("nojsiter") def siores(self, obj): self.isadmin = obj["isadmin"] if queryparams.get("noadmin", "false") == "true": self.isadmin = False if "kind" in obj: kind = obj["kind"] if kind == "buffered": for item in obj["items"]: self.siores(item) elif kind == "connectedack": self.buildfromconfiginobj(obj) elif kind == "configsaved": window.alert("Config saved, {} characters".format(obj["size"])) location.reload() elif kind == "alert": window.alert(obj["data"]) if obj["reload"]: location.reload() elif kind == "proc": self.processpane.siores(obj) elif kind == "storedb": pass elif kind == "storedbfailed": pass elif kind == "retrievedbfailed": pass elif kind == "mybots": self.setmybots(obj) else: if IS_DEV(): self.owners[obj["owner"]].siores(obj) else: try: self.owners[obj["owner"]].siores(obj) except: print("could not handle", obj) if kind == "showdoc": if obj["switchtodoctab"]: self.tabs.selectbykey("doc") def authtimeout(self): if not self.authdone: print("authtimeout") self.onauth() def startup(self): createconn({ "connectcallback": self.onconnect, "authcallback": self.onauth, "siorescallback": self.siores }) if IS_DEV(): setTimeout(self.authtimeout, 3000)
class Connection: def signincallback(self): email = self.emailinput.getText() password = self.passwordinput.getText() print("signing in user with", email, password) firebase.auth().signInWithEmailAndPassword(email, password).then( lambda: print("ok"), lambda error: window.alert("{}".format(error))) def signoutcallback(self): if firebase.auth().currentUser: print("signing out") firebase.auth().signOut() else: window.alert("Already signed out.") def signupcallback(self): email = self.emailinput.getText() password = self.passwordinput.getText() print("signing up user with", email, password) firebase.auth().createUserWithEmailAndPassword(email, password).then( lambda: print("ok"), lambda error: window.alert("{}".format(error))) def sendverificationcallback(self): email = self.emailinput.getText() firebase.auth().currentUser.sendEmailVerification().then( lambda: window.alert("Verification email has been sent to {} !". format(email)), lambda error: window.alert("{}".format(error))) def resetpasswordcallback(self): email = self.emailinput.getText() firebase.auth().sendPasswordResetEmail(email).then( lambda: window.alert("Password reset email has been sent to {} !". format(email)), lambda error: window.alert("{}".format(error))) def updatedisplaynamecallback(self): getconn().sioreq({ "kind": "updateuserdisplayname", "displayname": self.displaynameinput.getText(), "uid": self.uid }) def updatephotourlcallback(self): getconn().sioreq({ "kind": "updateuserphotourl", "photourl": self.photourlinput.getText(), "uid": self.uid }) def linkgoogleok(self, result): print(result) window.alert("Account linked with Google !") location.reload() def linkmailok(self, usercred): print(usercred) window.alert("Account linked with Email !") location.reload() def linkgooglecallback(self): provider = __new__(firebase.auth.GoogleAuthProvider()) firebase.auth().currentUser.linkWithPopup(provider).then( self.linkgoogleok, lambda err: window.alert("Link Google failed: {}".format(err))) def linkmailcallback(self): credential = firebase.auth.EmailAuthProvider.credential( self.emailinput.getText(), self.passwordinput.getText()) firebase.auth().currentUser.linkAndRetrieveDataWithCredential( credential).then( self.linkmailok, lambda err: window.alert("Link Email failed: {}".format(err))) def helpcallback(self): self.sioreq({"kind": "getdoc", "data": "profilehelp", "owner": "doc"}) def buildsignupdiv(self): self.signupdiv = Div() self.signupmaildiv = Div("signupmaildiv") self.emaillabel = Span().html("Email:") self.emailinput = TextInput().ac("profiletextinput").w(250) self.passwordlabel = Span().html("Password:"******"profiletextinput").w(100) self.helpbutton = Button("Help", self.helpcallback).ac("helpbutton") self.signinbutton = Button("Sign in", self.signincallback) self.signoutbutton = Button("Sign out", self.signoutcallback) self.signupbutton = Button("Sign up", self.signupcallback) self.sendverificationbutton = Button("Send verification", self.sendverificationcallback) self.resetpasswordbutton = Button("Reset password", self.resetpasswordcallback) self.linkgooglebutton = Button("Link Google", self.linkgooglecallback) self.linkmailbutton = Button("Link Email", self.linkmailcallback) self.userinfodiv = Div("userinfodiv") self.signupmaildiv.a([ self.helpbutton, self.emaillabel, self.emailinput, self.passwordlabel, self.passwordinput, self.signinbutton, self.signoutbutton, self.signupbutton, self.sendverificationbutton, self.resetpasswordbutton, self.linkgooglebutton, self.linkmailbutton ]) self.userdetailsdiv = Div("userdetailsdiv") self.displaynamelabel = Span().html("Display name:") self.displaynameinput = TextInput().ac("profiletextinput").w(250) self.photourllabel = Span().html("Photo url:") self.photourlinput = TextInput().ac("profiletextinput").w(250) self.updatedisplaynamebutton = Button("Update display name", self.updatedisplaynamecallback) self.updatephotourlbutton = Button("Update photo url", self.updatephotourlcallback) self.userdetailsdiv.a([ self.displaynamelabel, self.displaynameinput, self.updatedisplaynamebutton, self.photourllabel, self.photourlinput, self.updatephotourlbutton ]) self.photodiv = Div("photodiv") self.signupdiv.a([ self.signupmaildiv, self.userdetailsdiv, self.userinfodiv, self.photodiv ]) self.firebaseuidiv = Div().sa("id", "firebaseuidiv") self.signupdiv.a(self.firebaseuidiv) def logobj(self, logkind, obj, prompt): objstr = JSON.stringify(obj) if self.log: li = LogItem({"text": objstr, "kind": logkind, "prompt": prompt}) li.container.ac("socketlog") self.log.log(li) def emit(self, kind, obj): self.logobj("info", obj, "-> ") if self.rawsocket: self.rawsocket.emit(kind, obj) def sioreq(self, obj): obj["uid"] = self.getuid() #print("sioreq", obj) self.emit("sioreq", obj) def onconnect(self): if self.log: self.logobj("success", "socket connected ok", "socket message: ") if not self.configloaded: self.sioreq({"kind": "sendfirebaseconfig"}) if self.connectcallback: self.connectcallback() def siores(self, obj): if self.log: self.logobj("normal", obj, "<- ") if self.configloaded: if self.siorescallback: self.siorescallback(obj) else: kind = obj["kind"] if kind == "firebaseconfig": self.configloaded = True self.startfirebase(obj["firebaseconfig"]) def getuserdisplayname(self): if self.user: if self.displayName: return self.displayName return self.email return None def setprofiletab(self): self.profiletab.rc(["profilelogged", "profileanon"]) dn = self.getuserdisplayname() if dn: self.profiletab.container.html(dn) self.profiletab.ac("profilelogged") else: if self.user: self.profiletab.container.html("Anonymous") self.profiletab.ac("profileanon") else: self.profiletab.container.html("Profile") def signinanonymously(self): firebase.auth().signInAnonymously().then(lambda: print("ok"), lambda error: print(error)) def userstatusverbal(self): if not self.user: return "[logged out]" if self.user.isAnonymous: return "anonymous" return cpick(self.emailVerified, "verified", "not verified") def userverified(self): if not self.user: return False if self.user.isAnonymous: return False return self.user.emailVerified def authstatechanged(self, user): self.user = user self.passwordinput.setText("") if user: self.displayName = user.displayName self.email = user.email self.emailVerified = user.emailVerified self.photoURL = user.photoURL self.isAnonymous = user.isAnonymous self.uid = user.uid self.providerData = user.providerData print("user:"******"name : <span class='{}'>{}</span>".format( cpick(self.displayName, "uiinfo", "uiinfored"), getelse(self.displayName, "<NA>"))).pt(5) self.emailinfodiv = Div().html( "email : <span class='{}'>{}</span>".format( cpick(self.email, "uiinfo", "uiinfored"), getelse(self.email, "<NA>"))) self.verifiedinfodiv = Div().html( "status : <span class='{}'>{}</span>".format( cpick(self.userverified(), "uiinfo", "uiinfored"), self.userstatusverbal())) self.photourldiv = Div().html( "photo url : <span class='{}'>{}</span>".format( cpick(self.photoURL, "uiinfo", "uiinfored"), getelse(self.photoURL, "<NA>"))) self.uidinfodiv = Div().html( "uid : <span class='uiinfo'>{}</span>".format(self.uid)).pb(8) self.userinfodiv.x().a([ self.nameinfodiv, self.emailinfodiv, self.verifiedinfodiv, self.photourldiv, self.uidinfodiv ]) self.emailinput.setText(self.email) self.displaynameinput.setText(self.displayName) self.photourlinput.setText(self.photoURL) self.photodiv.x() if self.photoURL: self.photodiv.html( "<img src='{}' class='userphotoimg'></img>".format( self.photoURL)) else: print("no user") self.userinfodiv.x().a([ Div().html("Please sign up or sign in !"), Button("Sign in anonymously", self.signinanonymously()) ]) self.setprofiletab() self.userinfodiv.fs(cpick(self.user, 10, 14)) if user: if self.authcallback: self.authcallback() def initializefirebase(self): print("initializing firebase from", self.firebaseconfig) firebase.initializeApp(self.firebaseconfig) firebase.auth().onAuthStateChanged(self.authstatechanged) def initializefirebaseui(self): self.uiConfig = { "signInSuccessUrl": '/', "signInOptions": [ firebase.auth.GoogleAuthProvider.PROVIDER_ID, #firebase.auth.FacebookAuthProvider.PROVIDER_ID, #firebase.auth.TwitterAuthProvider.PROVIDER_ID, #firebase.auth.GithubAuthProvider.PROVIDER_ID, firebase.auth.EmailAuthProvider.PROVIDER_ID, #firebase.auth.PhoneAuthProvider.PROVIDER_ID ], "tosUrl": '/tos' } print("initializing firebase ui from", self.uiConfig) self.ui = __new__(firebaseui.auth.AuthUI(firebase.auth())) self.ui.start(self.firebaseuidiv.e, self.uiConfig) def startfirebase(self, firebaseconfig): self.firebaseconfig = firebaseconfig self.initializefirebase() self.initializefirebaseui() def getuid(self): if self.user: return self.uid return "mockuser" def __init__(self, args={}): self.configloaded = False self.user = None if window.location.protocol == "https:": self.ws_scheme = "wss://" else: self.ws_scheme = "ws://" self.SUBMIT_URL = self.ws_scheme + window.location.host print("creating socket {}".format(self.SUBMIT_URL)) self.rawsocket = io.connect(self.SUBMIT_URL) print("socket created ok") self.log = Log() self.connectcallback = args.get("connectcallback", None) self.authcallback = args.get("authcallback", None) self.siorescallback = args.get("siorescallback", None) self.buildsignupdiv() self.profiletab = Tab("profile", "Profile", self.signupdiv) if self.rawsocket: self.rawsocket.on("connect", self.onconnect) self.rawsocket.on("siores", self.siores)
class FileUploader(e): def fileinputchanged(self): self.files = self.fileinput.files() self.handlefiles() def preventdefaults(self, ev): ev.preventDefault() ev.stopPropagation() def highlight(self): self.droparea.ac("highlight") def unhighlight(self): self.droparea.rc("highlight") def log(self, html): self.infoitems.append(html) self.infoitems.reverse() self.info.html("<br>".join(self.infoitems)) self.infoitems.reverse() def loginfo(self, content): try: json = JSON.parse(content) if json["success"]: if self.dirbrowseruploadedcallback: self.dirbrowseruploadedcallback() self.log("Uploaded <span class='fileuploadfilename'>{}</span> .".format(json["filename"])) else: path = "/uploads/{}".format(json["savefilename"]) self.log("uploaded <span class='fileuploadfilename'>{}</span> <a href='{}' target='_blank' rel='noopener noreferrer'>{}</a> <br> <font size='2'> media link <a href='{}' target='_blank' rel='noopener noreferrer'>{}</a> </font>".format(json["filename"], path, path, json["medialink"], json["medialink"])) else: self.log("<span class='fileuploaderror'>File upload failed. Status: {} .</span>".format(json["status"])) except: self.log("Error parsing response as JSON.") def uploadfile(self, file): if self.url is None: print("no upload url") return formdata = __new__ (FormData()) formdata.append('files', file) formdata.append('drive', self.drive) if self.getuid: formdata.append('uid', self.getuid()) if self.dirbrowsergetpathcallback: formdata.append("dirpath", self.dirbrowsergetpathcallback()) __pragma__("jsiter") args = { "method": 'POST', "body": formdata } __pragma__("nojsiter") fetch(self.url, args).then( lambda response: response.text().then( lambda content: self.loginfo(content), lambda err: self.loginfo(err) ), lambda err: self.loginfo(err) ) def handlefiles(self, files = self.files): for i in range(files.length): print("uploading file {}".format(i)) self.uploadfile(files.item(i)) def handledrop(self, ev): self.dt = ev.dataTransfer self.files = self.dt.files self.handlefiles() def build(self): self.x() self.droparea = Div("fileuploaddroparea") self.form = Form().ac("fileuploadform") self.desc = P().ac("fileuploadp").html("Upload {}s with the file dialog or by dragging and dropping them onto the dashed region".format(self.acceptdisplay)) self.fileinput = FileInput().ac("fileuploadfileelem").setmultiple(self.multiple).setaccept(self.accept) self.fileinput.sa("id", "fileinputelement") self.fileinput.ae("change", self.fileinputchanged) self.button = Label().ac("fileuploadbutton").sa("for", "fileinputelement").html("Select some {}s".format(self.acceptdisplay)) self.form.a([self.desc, self.fileinput, self.button]) self.droparea.a(self.form) for eventname in ["dragenter", "dragover", "dragleave", "drop"]: self.droparea.ae(eventname, self.preventdefaults) for eventname in ["dragenter", "dragover"]: self.droparea.ae(eventname, self.highlight) for eventname in ["dragleave", "drop"]: self.droparea.ae(eventname, self.unhighlight) self.droparea.ae("drop", self.handledrop) self.info = Div("fileuploadinfo") self.infoitems = [] self.a([self.droparea, self.info]) def __init__(self, args = {}): super().__init__("div") self.url = args.get("url", None) self.multiple = args.get("multiple", True) self.accept = args.get("accept", "image/*") self.acceptdisplay = args.get("acceptdisplay", "image") self.drive = args.get("drive", False) self.dirbrowseruploadedcallback = args.get("dirbrowseruploadedcallback", None) self.dirbrowsergetpathcallback = args.get("dirbrowsergetpathcallback", None) self.getuid = args.get("getuid", None) self.build()