diff --git a/ServiceAPI/Mentions.php b/ServiceAPI/Mentions.php new file mode 100644 index 00000000..33c1fc01 --- /dev/null +++ b/ServiceAPI/Mentions.php @@ -0,0 +1,50 @@ +user = $user; + } + + function resolve(int $id, callable $resolve, callable $reject): void + { + if($id > 0) { + $user = (new Users)->get($id); + if(!$user) { + $reject("Not found"); + return; + } + + $resolve([ + "url" => $user->getURL(), + "name" => $user->getFullName(), + "ava" => $user->getAvatarURL("miniscule"), + "about" => $user->getStatus() ?? "", + "online" => ($user->isFemale() ? tr("was_online_f") : tr("was_online_m")) . " " . $user->getOnline(), + "verif" => $user->isVerified(), + ]); + return; + } + + $club = (new Clubs)->get(abs($id)); + if(!$club) { + $reject("Not found"); + return; + } + + $resolve([ + "url" => $club->getURL(), + "name" => $club->getName(), + "ava" => $club->getAvatarURL("miniscule"), + "about" => $club->getDescription() ?? "", + "online" => tr("participants", $club->getFollowersCount()), + "verif" => $club->isVerified(), + ]); + } +} diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml index e717acfe..1be7ba55 100644 --- a/Web/Presenters/templates/@layout.xml +++ b/Web/Presenters/templates/@layout.xml @@ -17,6 +17,14 @@ {script "js/l10n.js"} {script "js/openvk.cls.js"} + {css "js/node_modules/tippy.js/dist/backdrop.css"} + {css "js/node_modules/tippy.js/dist/border.css"} + {css "js/node_modules/tippy.js/dist/svg-arrow.css"} + {css "js/node_modules/tippy.js/themes/light.css"} + {script "js/node_modules/@popperjs/core/dist/umd/popper.min.js"} + {script "js/node_modules/tippy.js/dist/tippy-bundle.umd.min.js"} + {script "js/node_modules/handlebars/dist/handlebars.min.js"} + {if $isTimezoned == NULL} {script "js/timezone.js"} {/if} @@ -325,6 +333,7 @@ {script "js/scroll.js"} {script "js/al_wall.js"} {script "js/al_api.js"} + {script "js/al_mentions.js"} {ifset $thisUser} {script "js/al_notifs.js"} diff --git a/Web/Presenters/templates/components/post/microblogpost.xml b/Web/Presenters/templates/components/post/microblogpost.xml index d2991bca..daf2c275 100644 --- a/Web/Presenters/templates/components/post/microblogpost.xml +++ b/Web/Presenters/templates/components/post/microblogpost.xml @@ -25,7 +25,7 @@ {$post->isDeactivationMessage() ? ($author->isFemale() ? tr($deac . "_f") : tr($deac . "_m"))} {if ($onWallOf ?? false) &&!$post->isPostedOnBehalfOfGroup() && $post->getOwnerPost() !== $post->getTargetWall()} {var $wallOwner = $post->getWallOwner()} - + {if isset($thisUser) && $thisUser->getId() === $post->getTargetWall()} {_post_on_your_wall} @@ -75,7 +75,7 @@ {var $actualAuthor = $post->getOwner(false)} {_author}: - + {$actualAuthor->getCanonicalName()} diff --git a/Web/Presenters/templates/components/post/oldpost.xml b/Web/Presenters/templates/components/post/oldpost.xml index 057f76a5..f865e9d0 100644 --- a/Web/Presenters/templates/components/post/oldpost.xml +++ b/Web/Presenters/templates/components/post/oldpost.xml @@ -21,7 +21,7 @@ {$post->isDeactivationMessage() ? ($author->isFemale() ? tr($deac . "_f") : tr($deac . "_m")) : ($post->isPostedOnBehalfOfGroup() ? tr("post_writes_g") : ($author->isFemale() ? tr("post_writes_f") : tr("post_writes_m")))} {if ($onWallOf ?? false) &&!$post->isPostedOnBehalfOfGroup() && $post->getOwnerPost() !== $post->getTargetWall()} {var $wallOwner = $post->getWallOwner()} - + {if isset($thisUser) && $thisUser->getId() === $post->getTargetWall()} {_post_on_your_wall} @@ -56,7 +56,7 @@ {var $actualAuthor = $post->getOwner(false)} {_author}: - + {$actualAuthor->getCanonicalName()} diff --git a/Web/static/css/style.css b/Web/static/css/style.css index d35154c1..25516af7 100644 --- a/Web/static/css/style.css +++ b/Web/static/css/style.css @@ -2051,6 +2051,13 @@ table td[width="120"] { max-height: 250px; } +.tippy-box[data-theme~="vk"] { + user-select: none; + background-color: #fff; + border: 1px solid #DCE1E6; + border-radius: 1px; +} + @keyframes appearing { from { opacity: 0; diff --git a/Web/static/js/al_mentions.js b/Web/static/js/al_mentions.js new file mode 100644 index 00000000..f9d479ed --- /dev/null +++ b/Web/static/js/al_mentions.js @@ -0,0 +1,42 @@ +var tooltipTemplate = Handlebars.compile(` + + + + + + +
+ + + + {{name}} + {{#if verif}} + + {{/if}} +
+ {{online}}
+ {{about}} +
+`); + +tippy(".mention", { + theme: "light vk", + content: "⌛", + allowHTML: true, + interactive: true, + interactiveDebounce: 500, + + onCreate: async function(that) { + that._resolvedMention = null; + }, + + onShow: async function(that) { + if(!that._resolvedMention) { + let id = Number(that.reference.dataset.mentionRef); + that._resolvedMention = await API.Mentions.resolve(id); + } + + let res = that._resolvedMention; + that.setContent(tooltipTemplate(res)); + } +}); diff --git a/Web/static/js/package.json b/Web/static/js/package.json index e29efb2e..a082506b 100644 --- a/Web/static/js/package.json +++ b/Web/static/js/package.json @@ -2,6 +2,7 @@ "dependencies": { "@atlassian/aui": "^8.5.1", "create-react-class": "^15.7.0", + "handlebars": "^4.7.7", "jquery": "^2.1.0", "knockout": "^3.5.1", "ky": "^0.19.0", @@ -15,6 +16,7 @@ "requirejs": "^2.3.6", "soundjs": "^1.0.1", "textfit": "^2.4.0", + "tippy.js": "^6.3.7", "umbrellajs": "^3.1.0" } } diff --git a/Web/static/js/yarn.lock b/Web/static/js/yarn.lock index b507ac3c..691a64b5 100644 --- a/Web/static/js/yarn.lock +++ b/Web/static/js/yarn.lock @@ -29,6 +29,11 @@ resolved "https://registry.yarnpkg.com/@atlassian/tipsy/-/tipsy-1.3.2.tgz#ab759d461670d712425b2dac7573b79575a10502" integrity sha512-H7qWMs66bztELt2QpOCLYDU9ZM3VZfE0knbRHHLBukH7v9dMkIS5ZwqcGREjWnVt0KNETaBeXxj0FD88TEOGVw== +"@popperjs/core@^2.9.0": + version "2.11.6" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.6.tgz#cee20bd55e68a1720bdab363ecf0c821ded4cd45" + integrity sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw== + asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -89,6 +94,18 @@ fbjs@^0.8.0: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -170,6 +187,11 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: dependencies: js-tokens "^3.0.0 || ^4.0.0" +minimist@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + monaco-editor@^0.20.0: version "0.20.0" resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.20.0.tgz#5d5009343a550124426cb4d965a4d27a348b4dea" @@ -185,6 +207,11 @@ msgpack-lite@^0.1.26: int64-buffer "^0.1.9" isarray "^1.0.0" +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + node-fetch@^1.0.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" @@ -271,11 +298,23 @@ soundjs@^1.0.1: resolved "https://registry.yarnpkg.com/soundjs/-/soundjs-1.0.1.tgz#99970542d28d0df2a1ebd061ae75c961a98c8180" integrity sha512-MgFPvmKYfpcNiE3X5XybNvScie3DMQlZgmNzUn4puBcpw64f4LqjH/fhM8Sb/eTJ8hK57Crr7mWy0bfJOqPj6Q== +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + textfit@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/textfit/-/textfit-2.4.0.tgz#80cba8006bfb9c3d9d552739257957bdda95c79c" integrity sha512-/x4aoY5+/tJmu+iwpBH1yw75TFp86M6X15SvaaY/Eep7YySQYtqdOifEtfvVyMwzl7SZ+G4RQw00FD9g5R6i1Q== +tippy.js@^6.3.7: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + trim-extra-html-whitespace@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/trim-extra-html-whitespace/-/trim-extra-html-whitespace-1.3.0.tgz#b47efb0d1a5f2a56a85cc45cea525651e93404cf" @@ -286,6 +325,11 @@ ua-parser-js@^0.7.18: resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== +uglify-js@^3.1.4: + version "3.17.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.3.tgz#f0feedf019c4510f164099e8d7e72ff2d7304377" + integrity sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg== + umbrellajs@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/umbrellajs/-/umbrellajs-3.1.0.tgz#a4e6f0f6381f9d93110b5eee962e0e0864b10bd0" @@ -300,3 +344,8 @@ whatwg-fetch@>=0.10.0: version "3.6.2" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==