diff --git a/src/applications/ponder/view/PonderVotableView.php b/src/applications/ponder/view/PonderVotableView.php index d4fb401b5c..0f1b10ddf6 100644 --- a/src/applications/ponder/view/PonderVotableView.php +++ b/src/applications/ponder/view/PonderVotableView.php @@ -47,23 +47,60 @@ final class PonderVotableView extends AphrontView { require_celerity_resource('ponder-vote-css'); require_celerity_resource('javelin-behavior-ponder-votebox'); - Javelin::initBehavior( - 'ponder-votebox', + Javelin::initBehavior('ponder-votebox', array()); + + $uri = id(new PhutilURI($this->uri))->alter('phid', $this->phid); + + $up = javelin_render_tag( + 'a', array( - 'nodeid' => $this->phid, - 'vote' => $this->vote, - 'count' => $this->count, - 'uri' => $this->uri - )); + 'href' => (string)$uri, + 'sigil' => 'upvote', + 'mustcapture' => true, + 'class' => ($this->vote > 0) ? 'ponder-vote-active' : null, + ), + "\xE2\x96\xB2"); - $content = - '
'. - '
-
'. - $this->renderChildren(). - '
'; + $down = javelin_render_tag( + 'a', + array( + 'href' => (string)$uri, + 'sigil' => 'downvote', + 'mustcapture' => true, + 'class' => ($this->vote < 0) ? 'ponder-vote-active' : null, + ), + "\xE2\x96\xBC"); - return $content; + $count = javelin_render_tag( + 'div', + array( + 'class' => 'ponder-vote-count', + 'sigil' => 'ponder-vote-count', + ), + phutil_escape_html($this->count)); + + return javelin_render_tag( + 'div', + array( + 'class' => 'ponder-votable', + 'sigil' => 'ponder-votable', + 'meta' => array( + 'count' => (int)$this->count, + 'vote' => (int)$this->vote, + ), + ), + javelin_render_tag( + 'div', + array( + 'class' => 'ponder-votebox', + ), + $up.$count.$down). + phutil_render_tag( + 'div', + array( + 'class' => 'ponder-votebox-content', + ), + $this->renderChildren())); } } diff --git a/webroot/rsrc/css/application/ponder/vote.css b/webroot/rsrc/css/application/ponder/vote.css index 9e6e0e428d..31b8ac9f71 100644 --- a/webroot/rsrc/css/application/ponder/vote.css +++ b/webroot/rsrc/css/application/ponder/vote.css @@ -2,17 +2,45 @@ * @provides ponder-vote-css */ - - -.ponder-votable .phabricator-transaction-view { - margin : 0; - padding : 0; +.ponder-votebox { + text-align: center; } -.ponder-votable .phabricator-transaction-detail { - min-height : 90px; +.ponder-votebox a { + font-size: 20px; + line-height: 20px; + display: block; + + text-decoration: none; + color: #999999; + font-weight: normal; + + /* Our default fonts have weirdly different up/down arrow sizes. */ + font-family: Arial; } +.ponder-votebox a:hover { + color: #606060; +} + +.ponder-votebox a.ponder-vote-active { + color: #3b5998; +} + +.ponder-votebox a.ponder-vote-active:hover { + color: #a1bbe5; +} + +.ponder-vote-count { + color: #888888; + font-size: 14px; + line-height: 14px; + font-weight: bold; +} + + + + .ponder-votebox { float : left; width : 32px; @@ -21,57 +49,11 @@ margin-left : 10px; } -.ponder-upbutton { - border : none; - padding : 0; +.ponder-votable .phabricator-transaction-view { margin : 0; - width : 32px; - height : 13px; -} - -.ponder-downbutton { - border : none; padding : 0; - margin : 0; - width : 32px; - height : 13px; } -.ponder-votecount { - width : 32px; - height : 22pt; - padding : 0; - margin : 0; - overflow : visible; - text-align : center; - font-size : 15pt; -} - -.ponder-upbutton:hover { - cursor : pointer; -} - -.ponder-downbutton:hover { - cursor : pointer; -} - -.ponder-votable-bottom { - clear : both; -} - -.ponder-upbutton { - background : url(/rsrc/image/application/ponder/upvote.png) 0 -13px no-repeat; -} - -.ponder-upbutton.ponder-vote-up { - background : url(/rsrc/image/application/ponder/upvote.png) 0 0 no-repeat; -} - -.ponder-downbutton { - background : url(/rsrc/image/application/ponder/downvote.png) - 0 -13px no-repeat; -} - -.ponder-downbutton.ponder-vote-down { - background : url(/rsrc/image/application/ponder/downvote.png) 0 0 no-repeat; +.ponder-votable .phabricator-transaction-detail { + min-height : 90px; } diff --git a/webroot/rsrc/image/application/ponder/downvote.png b/webroot/rsrc/image/application/ponder/downvote.png deleted file mode 100644 index 7272a6645c..0000000000 Binary files a/webroot/rsrc/image/application/ponder/downvote.png and /dev/null differ diff --git a/webroot/rsrc/image/application/ponder/upvote.png b/webroot/rsrc/image/application/ponder/upvote.png deleted file mode 100644 index cb543a2141..0000000000 Binary files a/webroot/rsrc/image/application/ponder/upvote.png and /dev/null differ diff --git a/webroot/rsrc/js/application/ponder/behavior-votebox.js b/webroot/rsrc/js/application/ponder/behavior-votebox.js index 3871d30b40..15c3197484 100644 --- a/webroot/rsrc/js/application/ponder/behavior-votebox.js +++ b/webroot/rsrc/js/application/ponder/behavior-votebox.js @@ -3,74 +3,53 @@ * @requires javelin-behavior * javelin-dom * javelin-util - * phabricator-shaped-request + * javelin-stratcom + * javelin-request */ JX.behavior('ponder-votebox', function(config) { - var node = JX.$(config.nodeid); - var vote = config.vote; - var count = config.count | 0; - var targetURI = config.targetURI; + function handle_vote(e, vote) { + e.kill(); - var upnode, countnode, downnode; + var root = e.getNode('ponder-votable'); + var data = e.getNodeData('ponder-votable'); - // this defines the behavior of the up/downvote - // buttons, e.g. clicking 'up' transitions from - // an 'up' vote to a 'none' vote - var votecycle = { - "1" : { up : "0", down : "-1" }, - "0" : { up : "1", down : "-1" }, - "-1" : { up : "1", down : "0" } - }; + if (data.vote != vote) { + data.vote = vote; + data.count += vote; + } else { + // User is undoing their vote. + data.vote = 0; + data.count -= vote; + } - var voteclass = { - "0" : "ponder-vote-none", - "-1" : "ponder-vote-down", - "1" : "ponder-vote-up" - }; + var upv = JX.DOM.find(root, 'a', 'upvote'); + JX.DOM.alterClass(upv, 'ponder-vote-active', (data.vote > 0)); - function decorate() { - upnode = JX.$N('div'); - countnode = JX.$N('div'); - downnode = JX.$N('div'); - node.appendChild(upnode); - node.appendChild(countnode); - node.appendChild(downnode); - JX.DOM.alterClass(upnode, "ponder-upbutton " + voteclass[vote], true); - JX.DOM.alterClass(downnode, "ponder-downbutton " + voteclass[vote], true); - JX.DOM.alterClass(countnode, "ponder-votecount", true); + var downv = JX.DOM.find(root, 'a', 'downvote'); + JX.DOM.alterClass(downv, 'ponder-vote-active', (data.vote < 0)) + + JX.DOM.setContent( + JX.DOM.find(root, 'div', 'ponder-vote-count'), + data.count); + + new JX.Request(e.getTarget().href, JX.bag) + .setData({vote: data.vote}) + .send() } - function update_state() { - upnode.className = "ponder-upbutton " + voteclass[vote]; - downnode.className = "ponder-downbutton " + voteclass[vote]; - JX.DOM.setContent(countnode, JX.$H(count.toString())); - } + JX.Stratcom.listen( + 'click', + 'downvote', + function(e) { + handle_vote(e, -1); + }); - function getdata() { - return { phid : config.nodeid, vote : vote }; - } - - var request = new JX.PhabricatorShapedRequest(config.uri, JX.id, getdata); - var trigger = JX.bind(request, request.trigger); - - function handle_upvote(e) { - count += votecycle[vote].up - vote; - vote = votecycle[vote].up; - trigger(); - update_state(); - } - - function handle_downvote(e) { - count += votecycle[vote].down - vote; - vote = votecycle[vote].down; - trigger(); - update_state(); - } - - decorate(); - update_state(); - JX.DOM.listen(upnode, 'click', null, handle_upvote); - JX.DOM.listen(downnode, 'click', null, handle_downvote); + JX.Stratcom.listen( + 'click', + 'upvote', + function(e) { + handle_vote(e, 1); + }); });