more work on sticky studies
parent
005d4b47d4
commit
3c60fdca79
|
@ -1 +1 @@
|
|||
Subproject commit 9ab653c037094c919d59a7bdca1cb49f33e8f11d
|
||||
Subproject commit c187c7d871717a09f5eea66eca0a259a4134b0e5
|
|
@ -16,8 +16,7 @@ case class AnaDrop(
|
|||
variant: Variant,
|
||||
fen: String,
|
||||
path: String,
|
||||
chapterId: Option[String],
|
||||
local: Boolean
|
||||
chapterId: Option[String]
|
||||
) {
|
||||
|
||||
def branch: Valid[Branch] =
|
||||
|
@ -64,7 +63,6 @@ object AnaDrop {
|
|||
variant = variant,
|
||||
fen = fen,
|
||||
path = path,
|
||||
chapterId = d str "ch",
|
||||
local = ~(d boolean "local")
|
||||
chapterId = d str "ch"
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,8 +16,7 @@ case class AnaMove(
|
|||
fen: String,
|
||||
path: String,
|
||||
chapterId: Option[String],
|
||||
promotion: Option[chess.PromotableRole],
|
||||
local: Boolean // if local, do not affect the server state
|
||||
promotion: Option[chess.PromotableRole]
|
||||
) {
|
||||
|
||||
def branch: Valid[Branch] =
|
||||
|
@ -64,7 +63,6 @@ object AnaMove {
|
|||
fen = fen,
|
||||
path = path,
|
||||
chapterId = d str "ch",
|
||||
promotion = d str "promotion" flatMap chess.Role.promotable,
|
||||
local = ~(d boolean "local")
|
||||
promotion = d str "promotion" flatMap chess.Role.promotable
|
||||
)
|
||||
}
|
||||
|
|
|
@ -98,7 +98,8 @@ private final class Socket(
|
|||
|
||||
case ReloadAll => notifyVersion("reload", JsNull, noMessadata)
|
||||
|
||||
case ChangeChapter(uid) => notifyVersion("changeChapter", Json.obj(
|
||||
case ChangeChapter(uid, pos) => notifyVersion("changeChapter", Json.obj(
|
||||
"p" -> pos,
|
||||
"w" -> who(uid)
|
||||
), noMessadata)
|
||||
|
||||
|
@ -265,7 +266,7 @@ private object Socket {
|
|||
case class SetGlyphs(position: Position.Ref, glyphs: Glyphs, uid: Uid)
|
||||
case class ReloadChapters(chapters: List[Chapter.Metadata])
|
||||
case object ReloadAll
|
||||
case class ChangeChapter(uid: Uid)
|
||||
case class ChangeChapter(uid: Uid, position: Position.Ref)
|
||||
case class SetConceal(position: Position.Ref, ply: Option[Chapter.Ply])
|
||||
case class SetLiking(liking: Study.Liking, uid: Uid)
|
||||
case class SetTags(chapterId: Chapter.Id, tags: List[chess.format.pgn.Tag], uid: Uid)
|
||||
|
|
|
@ -55,19 +55,21 @@ private[study] final class SocketHandler(
|
|||
}
|
||||
case ("anaMove", o) => AnaRateLimit(uid.value, member) {
|
||||
AnaMove parse o foreach { anaMove =>
|
||||
val moveOpts = getMoveOpts(o)
|
||||
anaMove.branch match {
|
||||
case scalaz.Success(branch) if branch.ply < Node.MAX_PLIES =>
|
||||
member push makeMessage("node", anaMove json branch)
|
||||
for {
|
||||
userId <- member.userId
|
||||
chapterId <- anaMove.chapterId
|
||||
if !anaMove.local
|
||||
if moveOpts.write
|
||||
} api.addNode(
|
||||
userId,
|
||||
studyId,
|
||||
Position.Ref(Chapter.Id(chapterId), Path(anaMove.path)),
|
||||
Node.fromBranch(branch),
|
||||
uid
|
||||
uid,
|
||||
sticky = moveOpts.sticky
|
||||
)
|
||||
case scalaz.Success(branch) =>
|
||||
member push makeMessage("stepFailure", s"ply ${branch.ply}/${Node.MAX_PLIES}")
|
||||
|
@ -78,19 +80,21 @@ private[study] final class SocketHandler(
|
|||
}
|
||||
case ("anaDrop", o) => AnaRateLimit(uid.value, member) {
|
||||
AnaDrop parse o foreach { anaDrop =>
|
||||
val moveOpts = getMoveOpts(o)
|
||||
anaDrop.branch match {
|
||||
case scalaz.Success(branch) if branch.ply < Node.MAX_PLIES =>
|
||||
member push makeMessage("node", anaDrop json branch)
|
||||
for {
|
||||
userId <- member.userId
|
||||
chapterId <- anaDrop.chapterId
|
||||
if !anaDrop.local
|
||||
if moveOpts.write
|
||||
} api.addNode(
|
||||
userId,
|
||||
studyId,
|
||||
Position.Ref(Chapter.Id(chapterId), Path(anaDrop.path)),
|
||||
Node.fromBranch(branch),
|
||||
uid
|
||||
uid,
|
||||
sticky = moveOpts.sticky
|
||||
)
|
||||
case scalaz.Success(branch) =>
|
||||
member push makeMessage("stepFailure", s"ply ${branch.ply}/${Node.MAX_PLIES}")
|
||||
|
@ -248,6 +252,16 @@ private[study] final class SocketHandler(
|
|||
private implicit val StudyDataReader = Json.reads[Study.Data]
|
||||
private implicit val setTagReader = Json.reads[actorApi.SetTag]
|
||||
|
||||
private case class MoveOpts(write: Boolean, sticky: Boolean)
|
||||
|
||||
private def getMoveOpts(o: JsObject) = {
|
||||
val d = (o.pp obj "d").pp | Json.obj()
|
||||
MoveOpts(
|
||||
write = d.get[Boolean]("write") | true,
|
||||
sticky = d.get[Boolean]("sticky") | true
|
||||
).pp
|
||||
}
|
||||
|
||||
def join(
|
||||
studyId: Study.Id,
|
||||
uid: Uid,
|
||||
|
|
|
@ -163,14 +163,14 @@ final class StudyApi(
|
|||
}
|
||||
}
|
||||
|
||||
def addNode(userId: User.ID, studyId: Study.Id, position: Position.Ref, node: Node, uid: Uid) = sequenceStudyWithChapter(studyId) {
|
||||
def addNode(userId: User.ID, studyId: Study.Id, position: Position.Ref, node: Node, uid: Uid, sticky: Boolean) = sequenceStudyWithChapter(studyId) {
|
||||
case Study.WithChapter(study, chapter) => Contribute(userId, study) {
|
||||
chapter.addNode(node, position.path) match {
|
||||
case None => fufail(s"Invalid addNode $studyId $position $node") >>- reloadUid(study, uid)
|
||||
case Some(chapter) =>
|
||||
chapter.root.nodeAt(position.path) ?? { parent =>
|
||||
chapterRepo.setChildren(chapter, position.path, parent.children) >>
|
||||
studyRepo.setPosition(study.id, position + node) >>
|
||||
(sticky ?? studyRepo.setPosition(study.id, position + node)) >>
|
||||
updateConceal(study, chapter, position + node) >>-
|
||||
sendTo(study, Socket.AddNode(position, node, chapter.setup.variant, uid)) >>-
|
||||
sendStudyEnters(study, userId)
|
||||
|
@ -376,8 +376,9 @@ final class StudyApi(
|
|||
(study.position.chapterId != chapterId) ?? {
|
||||
chapterRepo.byIdAndStudy(chapterId, study.id) flatMap {
|
||||
_ ?? { chapter =>
|
||||
studyRepo.updateSomeFields(study withChapter chapter) >>-
|
||||
sendTo(study, Socket.ChangeChapter(uid))
|
||||
val newStudy = study withChapter chapter
|
||||
studyRepo.updateSomeFields(newStudy) >>-
|
||||
sendTo(study, Socket.ChangeChapter(uid, newStudy.position))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -411,7 +412,7 @@ final class StudyApi(
|
|||
(newChapter.setup.orientation != chapter.setup.orientation) ||
|
||||
(newChapter.practice != chapter.practice)
|
||||
if (study.position.chapterId == chapter.id && shouldReload)
|
||||
sendTo(study, Socket.ChangeChapter(uid))
|
||||
sendTo(study, Socket.ChangeChapter(uid, study.position))
|
||||
else
|
||||
reloadChapters(study)
|
||||
}
|
||||
|
|
|
@ -62,11 +62,6 @@ lichess.studyTour = function(study) {
|
|||
text: "With the !? button, or a right click on the move list on the right.<br>" +
|
||||
"Annotation glyphs are shared and persisted.",
|
||||
attachTo: "#lichess .member_buttons .glyph top"
|
||||
} : null, study.isContrib ? {
|
||||
title: "Connect / disconnect",
|
||||
text: "Choose whether or not your moves are shared and persisted.<br>" +
|
||||
"Useful to try out variations before sharing them.",
|
||||
attachTo: "#study-sync top"
|
||||
} : null, {
|
||||
title: "Thanks for your time",
|
||||
text: "You can find your <a href='/study/mine/hot'>previous studies</a> from your profile page.<br>" +
|
||||
|
|
|
@ -438,9 +438,6 @@ div.underboard .notif.error {
|
|||
.study_buttons .button:hover {
|
||||
color: #3893E8;
|
||||
}
|
||||
.study_buttons #study-sync .data-count::after {
|
||||
right: 8px;
|
||||
}
|
||||
.glyph-icon::before {
|
||||
content: '⁉';
|
||||
font-size: 1.3em;
|
||||
|
|
|
@ -13,7 +13,7 @@ module.exports = function(send, ctrl) {
|
|||
this.clearCache = function() {
|
||||
anaDestsCache = (
|
||||
ctrl.data.game.variant.key === 'standard' &&
|
||||
ctrl.tree.root.fen.split(' ', 1)[0] === initialBoardFen
|
||||
ctrl.tree.root.fen.split(' ', 1)[0] === initialBoardFen
|
||||
) ? {
|
||||
'': {
|
||||
path: '',
|
||||
|
@ -29,13 +29,18 @@ module.exports = function(send, ctrl) {
|
|||
}, 1000);
|
||||
|
||||
var currentChapterId = function() {
|
||||
if (ctrl.study) return ctrl.study.currentChapter().id;
|
||||
if (ctrl.study) return ctrl.study.vm.chapterId;
|
||||
};
|
||||
var addStudyData = function(req, addLocal) {
|
||||
var addStudyData = function(req, isWrite) {
|
||||
var c = currentChapterId();
|
||||
if (c) {
|
||||
req.ch = c;
|
||||
if (addLocal && !ctrl.vm.mode.write) req.local = true;
|
||||
if (isWrite) {
|
||||
if (ctrl.study.vm.mode.write) {
|
||||
if (!ctrl.study.vm.mode.sticky) req.sticky = false;
|
||||
}
|
||||
else req.write = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -46,7 +51,7 @@ module.exports = function(send, ctrl) {
|
|||
if (data.ch == currentChapterId())
|
||||
ctrl.addNode(data.node, data.path);
|
||||
else
|
||||
console.log('socket handler node got wrong chapter id', data);
|
||||
console.log('socket handler node got wrong chapter id', data);
|
||||
},
|
||||
stepFailure: function(data) {
|
||||
clearTimeout(anaMoveTimeout);
|
||||
|
@ -58,7 +63,7 @@ module.exports = function(send, ctrl) {
|
|||
anaDestsCache[data.path] = data;
|
||||
ctrl.addDests(data.dests, data.path, data.opening);
|
||||
} else
|
||||
console.log('socket handler node got wrong chapter id', data);
|
||||
console.log('socket handler node got wrong chapter id', data);
|
||||
},
|
||||
destsFailure: function(data) {
|
||||
console.log(data);
|
||||
|
|
|
@ -27,12 +27,12 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
loading: false,
|
||||
nextChapterId: false,
|
||||
tab: m.prop(data.chapters.length > 1 ? 'chapters' : 'members'),
|
||||
chapterId: sticked ? data.position.chapterId : data.chapter.id,
|
||||
// path is at ctrl.vm.path
|
||||
mode: {
|
||||
sticky: sticked,
|
||||
write: true
|
||||
},
|
||||
catchingUp: false, // in the process of sticking
|
||||
chapterId: sticked ? null : data.chapter.id // only useful when not sticking
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
|
@ -59,25 +59,18 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
|
||||
var chapters = chapterCtrl(data.chapters, send, lichess.partial(vm.tab, 'chapters'), lichess.partial(xhr.chapterConfig, data.id), ctrl);
|
||||
|
||||
var currentChapterId = function() {
|
||||
return vm.chapterId || data.position.chapterId;
|
||||
}
|
||||
var currentChapter = function() {
|
||||
return chapters.get(currentChapterId());
|
||||
return chapters.get(vm.chapterId);
|
||||
};
|
||||
var isChapterOwner = function() {
|
||||
return ctrl.userId === data.chapter.ownerId;
|
||||
};
|
||||
|
||||
var isWriting = function() {
|
||||
return vm.mode.write && members.canContribute();
|
||||
};
|
||||
|
||||
var makeChange = function(t, d) {
|
||||
if (isWriting()) {
|
||||
if (vm.mode.write) {
|
||||
send(t, d);
|
||||
return true;
|
||||
} else if (!members.canContribute()) vm.mode.sticky = false;
|
||||
} else vm.mode.sticky = false;
|
||||
};
|
||||
|
||||
var commentForm = commentFormCtrl(ctrl);
|
||||
|
@ -117,9 +110,7 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
|
||||
var onReload = function(d) {
|
||||
var s = d.study;
|
||||
if (data.visibility === 'public' && s.visibility === 'private' && !members.myMember())
|
||||
return lichess.reload();
|
||||
if (s.position !== data.position) commentForm.close();
|
||||
if (vm.mode.sticky && s.position !== data.position) commentForm.close();
|
||||
['position', 'name', 'visibility', 'features', 'settings', 'chapter', 'likes', 'liked'].forEach(function(key) {
|
||||
data[key] = s[key];
|
||||
});
|
||||
|
@ -133,12 +124,13 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
|
||||
ctrl.chessground = undefined; // don't apply changes to old cg; wait for new cg
|
||||
|
||||
if (vm.mode.sticky || vm.catchingUp) ctrl.userJump(data.position.path);
|
||||
else ctrl.userJump('');
|
||||
if (vm.mode.sticky) {
|
||||
vm.chapterId = data.position.chapterId;
|
||||
ctrl.userJump(data.position.path);
|
||||
}
|
||||
|
||||
configurePractice();
|
||||
|
||||
vm.catchingUp = false;
|
||||
m.redraw.strategy("all"); // create a new cg
|
||||
m.redraw();
|
||||
ctrl.startCeval();
|
||||
|
@ -146,15 +138,15 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
|
||||
var xhrReload = function() {
|
||||
vm.loading = true;
|
||||
return xhr.reload(practice ? 'practice/load' : 'study', data.id, vm.chapterId).then(onReload);
|
||||
};
|
||||
|
||||
var activity = function(userId) {
|
||||
members.setActive(userId);
|
||||
return xhr.reload(
|
||||
practice ? 'practice/load' : 'study',
|
||||
data.id,
|
||||
vm.mode.sticky ? null : vm.chapterId
|
||||
).then(onReload, lichess.reload);
|
||||
};
|
||||
|
||||
var onSetPath = throttle(300, false, function(path) {
|
||||
if (path !== data.position.path) makeChange("setPath", addChapterId({
|
||||
if (vm.mode.sticky && path !== data.position.path) makeChange("setPath", addChapterId({
|
||||
path: path
|
||||
}));
|
||||
});
|
||||
|
@ -171,7 +163,7 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
|
||||
var mutateCgConfig = function(config) {
|
||||
config.drawable.onChange = function(shapes) {
|
||||
if (members.canContribute()) {
|
||||
if (vm.mode.write) {
|
||||
ctrl.tree.setShapes(shapes, ctrl.vm.path);
|
||||
makeChange("shapes", addChapterId({
|
||||
path: ctrl.vm.path,
|
||||
|
@ -181,6 +173,14 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
};
|
||||
}
|
||||
|
||||
var wrongChapter = function(serverPosition) {
|
||||
if (serverPosition.chapterId !== vm.chapterId) {
|
||||
// sticky should really be on the same chapter
|
||||
if (vm.mode.sticky) xhrReload();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
data: data,
|
||||
form: form,
|
||||
|
@ -209,7 +209,7 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
},
|
||||
onJump: practice ? practice.onJump : function() {},
|
||||
withPosition: function(obj) {
|
||||
obj.ch = currentChapterId();
|
||||
obj.ch = vm.chapterId;
|
||||
obj.path = ctrl.vm.path;
|
||||
return obj;
|
||||
},
|
||||
|
@ -230,8 +230,8 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
}));
|
||||
},
|
||||
setChapter: function(id, force) {
|
||||
if (id === currentChapterId() && !force) return;
|
||||
if (!makeChange("setChapter", id)) {
|
||||
if (id === vm.chapterId && !force) return;
|
||||
if (!vm.mode.sticky || !makeChange("setChapter", id)) {
|
||||
vm.chapterId = id;
|
||||
xhrReload();
|
||||
}
|
||||
|
@ -240,27 +240,11 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
m.redraw();
|
||||
},
|
||||
toggleSticky: function() {
|
||||
if (!data.features.sticky) {
|
||||
vm.mode.sticky = false;
|
||||
}
|
||||
else if (vm.mode.sticky) {
|
||||
vm.mode.sticky = false;
|
||||
vm.chapterId = currentChapterId();
|
||||
} else {
|
||||
vm.mode.sticky = true;
|
||||
vm.chapterId = null;
|
||||
vm.catchingUp = true;
|
||||
xhrReload();
|
||||
}
|
||||
vm.mode.sticky = !vm.mode.sticky && data.features.sticky;
|
||||
xhrReload();
|
||||
},
|
||||
toggleWrite: function() {
|
||||
if (vm.behind !== false) {
|
||||
tours.onSync();
|
||||
resync();
|
||||
} else {
|
||||
vm.behind = 0;
|
||||
vm.chapterId = currentChapterId();
|
||||
}
|
||||
vm.mode.write = !vm.mode.write && members.canContribute();
|
||||
},
|
||||
makeChange: makeChange,
|
||||
startTour: startTour,
|
||||
|
@ -272,13 +256,15 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
path: function(d) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
if (vm.behind !== false) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
if (!ctrl.tree.pathExists(position.path)) xhrReload();
|
||||
who && members.setActive(who.u);
|
||||
// #TODO if not sticky, still follow if on the parent path (live games)
|
||||
if (!vm.mode.sticky) return;
|
||||
if (position.chapterId !== data.position.chapterId ||
|
||||
!ctrl.tree.pathExists(position.path)) {
|
||||
return xhrReload();
|
||||
}
|
||||
data.position.path = position.path;
|
||||
if (who && who.s === sri) return;
|
||||
data.position.path = position.path;
|
||||
ctrl.userJump(position.path);
|
||||
m.redraw();
|
||||
},
|
||||
|
@ -286,44 +272,46 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
var position = d.p,
|
||||
node = d.n,
|
||||
who = d.w;
|
||||
if (position.chapterId !== currentChapterId()) return;
|
||||
who && activity(who.u);
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
// node author already has the node
|
||||
if (who && who.s === sri) {
|
||||
data.position.path = position.path + node.id;
|
||||
return;
|
||||
}
|
||||
var newPath = ctrl.tree.addNode(node, position.path);
|
||||
ctrl.tree.addDests(d.d, newPath, d.o);
|
||||
if (!newPath) xhrReload();
|
||||
if (!newPath) return xhrReload();
|
||||
data.position.path = newPath;
|
||||
if (vm.behind === false) ctrl.jump(data.position.path);
|
||||
if (vm.mode.sticky) ctrl.jump(data.position.path);
|
||||
m.redraw();
|
||||
},
|
||||
deleteNode: function(d) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
if (vm.behind !== false) return;
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
// deleter already has it done
|
||||
if (who && who.s === sri) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
if (!ctrl.tree.pathExists(d.p.path)) return xhrReload();
|
||||
ctrl.tree.deleteNodeAt(position.path);
|
||||
ctrl.jump(ctrl.vm.path);
|
||||
if (vm.mode.sticky) ctrl.jump(ctrl.vm.path);
|
||||
m.redraw();
|
||||
},
|
||||
promote: function(d, toMainline) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
if (vm.behind !== false) return;
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
if (who && who.s === sri) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
if (!ctrl.tree.pathExists(d.p.path)) return xhrReload();
|
||||
ctrl.tree.promoteAt(position.path, toMainline);
|
||||
ctrl.jump(ctrl.vm.path);
|
||||
if (vm.mode.sticky) ctrl.jump(ctrl.vm.path);
|
||||
},
|
||||
reload: xhrReload,
|
||||
changeChapter: function(d) {
|
||||
d.w && activity(d.w.u);
|
||||
d.w && members.setActive(d.w.u);
|
||||
data.position = d.p;
|
||||
if (vm.mode.sticky) xhrReload();
|
||||
},
|
||||
members: function(d) {
|
||||
|
@ -338,51 +326,48 @@ module.exports = function(data, ctrl, tagTypes, practiceData) {
|
|||
shapes: function(d) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
if (vm.behind !== false) return;
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
if (who && who.s === sri) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
ctrl.tree.setShapes(d.s, ctrl.vm.path);
|
||||
ctrl.chessground && ctrl.chessground.setShapes(d.s);
|
||||
if (ctrl.vm.path === position.path && ctrl.chessground) ctrl.chessground.setShapes(d.s);
|
||||
m.redraw();
|
||||
},
|
||||
setComment: function(d) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
if (who && who.s === sri) commentForm.dirty(false);
|
||||
if (vm.behind !== false) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
ctrl.tree.setCommentAt(d.c, position.path);
|
||||
m.redraw();
|
||||
},
|
||||
setTags: function(d) {
|
||||
d.w && activity(d.w.u);
|
||||
if (d.chapterId === data.position.chapterId) data.chapter.tags = d.tags;
|
||||
d.w && members.setActive(d.w.u);
|
||||
if (wrongChapter(position)) return;
|
||||
data.chapter.tags = d.tags;
|
||||
m.redraw();
|
||||
},
|
||||
deleteComment: function(d) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
if (vm.behind !== false) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
ctrl.tree.deleteCommentAt(d.id, position.path);
|
||||
m.redraw();
|
||||
},
|
||||
glyphs: function(d) {
|
||||
var position = d.p,
|
||||
who = d.w;
|
||||
who && activity(who.u);
|
||||
who && members.setActive(who.u);
|
||||
if (wrongChapter(position)) return;
|
||||
if (who && who.s === sri) glyphForm.dirty(false);
|
||||
if (vm.behind !== false) return;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
ctrl.tree.setGlyphsAt(d.g, position.path);
|
||||
m.redraw();
|
||||
},
|
||||
conceal: function(d) {
|
||||
var position = d.p;
|
||||
if (position.chapterId !== data.position.chapterId) return;
|
||||
if (wrongChapter(position)) return;
|
||||
data.chapter.conceal = d.ply;
|
||||
m.redraw();
|
||||
},
|
||||
|
|
|
@ -22,28 +22,5 @@ module.exports = {
|
|||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
offline: function() {
|
||||
lichess.shepherd(function(theme) {
|
||||
var tour = new Shepherd.Tour({
|
||||
defaults: {
|
||||
classes: theme,
|
||||
scrollTo: true
|
||||
}
|
||||
});
|
||||
tour.addStep('off', {
|
||||
title: 'Offline mode',
|
||||
text: 'Your board is no longer shared!<br>Click this button to reconnect.',
|
||||
attachTo: '#study-sync top',
|
||||
buttons: [{
|
||||
text: 'OK',
|
||||
action: tour.next
|
||||
}],
|
||||
});
|
||||
tour.start();
|
||||
});
|
||||
},
|
||||
// onSync: function() {
|
||||
// if (window.Shepherd && Shepherd.activeTour) Shepherd.activeTour.next()
|
||||
// }
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,67 +21,52 @@ function buttons(root) {
|
|||
var canContribute = ctrl.members.canContribute();
|
||||
return m('div.study_buttons', [
|
||||
m('div.member_buttons', [
|
||||
ctrl.data.features.sticky ? m('span#study-sticky.hint--top', {
|
||||
'data-hint': ctrl.vm.mode.stiky ? 'Sticky' : 'Free'
|
||||
}, m('a', {
|
||||
class: 'button',
|
||||
ctrl.data.features.sticky ? m('a.button.text', {
|
||||
'data-icon': ctrl.vm.mode.sticky ? '"' : '"',
|
||||
onclick: ctrl.toggleSticky
|
||||
}),
|
||||
m('i', {
|
||||
'data-icon': ctrl.vm.mode.sticky ? '"' : '"'
|
||||
})) : null,
|
||||
ctrl.members.canContribute() ? m('span#study-write.hint--top', {
|
||||
'data-hint': ctrl.vm.mode.write ? 'Write' : 'Read'
|
||||
}, m('a', {
|
||||
class: 'button',
|
||||
}, ctrl.vm.mode.sticky ? 'Sticky' : 'Free') : null,
|
||||
ctrl.members.canContribute() ? m('a.button.text', {
|
||||
'data-icon': ctrl.vm.mode.write ? 'E' : 'k',
|
||||
onclick: ctrl.toggleWrite
|
||||
}),
|
||||
m('i', {
|
||||
'data-icon': ctrl.vm.mode.write ? 'E' : 'k'
|
||||
})) : null,
|
||||
m('a.button.share.hint--top', {
|
||||
class: classSet({
|
||||
active: ctrl.share.open()
|
||||
}),
|
||||
'data-hint': 'Share & export',
|
||||
config: bindOnce('click', function() {
|
||||
ctrl.share.toggle();
|
||||
})
|
||||
},
|
||||
m('i.[data-icon=z]')),
|
||||
canContribute ? [
|
||||
(function(enabled) {
|
||||
return m('a.button.comment.hint--top', {
|
||||
}, ctrl.vm.mode.write ? 'Write' : 'Read') : null,
|
||||
m('a.button.share.hint--top', {
|
||||
class: classSet({
|
||||
active: ctrl.share.open()
|
||||
}),
|
||||
'data-hint': 'Share & export',
|
||||
config: bindOnce('click', ctrl.share.toggle)
|
||||
},
|
||||
m('i.[data-icon=z]')),
|
||||
canContribute ? [
|
||||
m('a.button.comment.hint--top', {
|
||||
class: classSet({
|
||||
active: ctrl.commentForm.current(),
|
||||
disabled: !enabled
|
||||
disabled: !ctrl.vm.mode.write
|
||||
}),
|
||||
'data-hint': 'Comment this position',
|
||||
config: bindOnce('click', function() {
|
||||
if (ctrl.vm.mode.write) ctrl.commentForm.toggle(ctrl.currentChapter().id, root.vm.path, root.vm.node);
|
||||
})
|
||||
}, m('i[data-icon=c]'));
|
||||
})(ctrl.vm.mode.write), (function(enabled) {
|
||||
return m('a.button.glyph.hint--top', {
|
||||
}, m('i[data-icon=c]')),
|
||||
m('a.button.glyph.hint--top', {
|
||||
class: classSet({
|
||||
active: ctrl.glyphForm.isOpen(),
|
||||
disabled: !enabled
|
||||
disabled: !(root.vm.path && ctrl.vm.write)
|
||||
}),
|
||||
'data-hint': 'Annotate with symbols',
|
||||
config: bindOnce('click', function() {
|
||||
if (root.vm.path && ctrl.vm.mode.write) ctrl.glyphForm.toggle();
|
||||
})
|
||||
},
|
||||
m('i.glyph-icon'));
|
||||
})(root.vm.path && ctrl.vm.mode.write)
|
||||
] : null
|
||||
m('i.glyph-icon'))
|
||||
] : null
|
||||
]),
|
||||
m('span.button.help.hint--top', {
|
||||
'data-hint': 'Need help? Get the tour!',
|
||||
onclick: ctrl.startTour
|
||||
}, m('i.text', {
|
||||
'data-icon': ''
|
||||
}, 'help'))
|
||||
m('span.button.help.hint--top', {
|
||||
'data-hint': 'Need help? Get the tour!',
|
||||
onclick: ctrl.startTour
|
||||
}, m('i.text', {
|
||||
'data-icon': ''
|
||||
}, 'help'))
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue