📜 ⬆️ ⬇️

Chained together, or add comfort comments Vkontakte

Chained by one chain

On a typical evening, he looked into the comments of one of the Vkontakte communities and decided to participate in the discussion. But it was not there! To read the "conversation" of several speakers it was necessary to scroll through the discussion and weed out dozens of unnecessary replicas that did not participate in the dialogue I needed. Obvious routine, which really want to push on the mechanical brains. But for some reason, there is no tool to isolate only what is needed from Vkontakt. "Well? For the cause! “- shouted one of the internal voices, and the rest unanimously supported.

So I started to cut the Google Chrome browser extension, which allows me to look at the chains of related comments in Vkontakte discussions.
')
Who is not interested in the plot, can immediately see the result:

We continue. Away, little things, like writing a manifesto! I'll start immediately on the interesting.

Embedding script in page code


The goal is to display a comment chain by clicking on the icon at the comment. To do this, you need to draw this icon and hang an event on it.

icon
So this “icon” looks like

It immediately became clear that the code should work “from the inside”. The content script that is usual for extensions will be embedded in the page. So he will deal with it:

var s = document.createElement("script"); s.src = chrome.extension.getURL('/js/inject.js'); (document.head || document.documentElement).appendChild(s); 

Some more embedded data will need some static data, like urls for background images and the id of the extension itself. I forward them through a samopny event raised in the content script after the embedded script has loaded. The entire content script now looks like this:

 var s = document.createElement("script"); s.src = chrome.extension.getURL('/js/inject.js'); (document.head || document.documentElement).appendChild(s); s.onload = function() { var evt = document.createEvent("CustomEvent"); var url = chrome.extension.getURL('/img/planet.gif'); app_uid = chrome.runtime.id; evt.initCustomEvent("BindDefData", true, true, { 'url': url, 'app_uid': app_uid }); document.dispatchEvent(evt); }; 

This is the final look. A "listen" event on the side of the embedded script. This is pretty commonplace.

Communication between embedded and background scripts


Obtaining comments, of course, occurs via api Vkontakte (namely, the wall.getComments method). The process of obtaining them does not require that the code be written in a script embedded in the page. It will be written in a so-called “background script”. Let me remind the structure. We have:


preloader
During the walk to the api preloader is drawn. There are usually no delays, but sometimes something doubts the depths of VKontakte and you have to wait a couple of seconds.

The api request itself is executed by a simple function that implements xhr:

 var send_api_request = function(data, url, sync) { var req = new XMLHttpRequest(); req.open('GET', url + dict_to_uri(data), sync); req.send(); return req.responseText; } 

Much more interesting is the background taking commands from the embedded script. To do this, was written "listener":

 chrome.extension.onMessageExternal.addListener(function(request, sender, call_back) { chain = create_chaine(request.ids_list); //   call_back({ 'chain': chain[0], 'pid': request.ids_list[1], 'persons': chain[1] }); //     „“ }) 

Notice that onMessageExternal is used, since the event is fired from the embedded script. In other words, for a browser, these events are triggered on the site external to it, and not inside its own extension.

On the client side, the event is called like this:

 chrome.runtime.sendMessage(app_uid, { 'ids_list': ids_list }, function(result) { ... }) 

In it we transfer the list of necessary id-schnik (speaker id, post, comment) and then we process the received chain of comments. The process of building the dialogue itself is trivial, it can be found in the source code.

Drawing


The time has come for the “visible” part of the extension - the pop-up window drawing.


It looks like a short dialogue now

I did not reinvent the wheel and after a minute reverse engineering, I used the MessageBox class, which Vkontakt uses:

 var draw_box = function(html) { var box = new MessageBox({ title: false, width: 670, onHide: false, onDestroy: false, bodyStyle: 'background-color: rgba(79, 113, 152, 0.3); border-radius: 6px', hideButtons: true, grey: true, progress: true, hideOnBGClick: false }); box.content(html); box.show(); return box; } 

The html template that is being embedded has been “ripped off” and slightly altered from the first available hipster site. He is too clumsy to quote. And it is filled with the help of a slightly tweaked contact function rs:

 var rs_t = function(html, repl) { each(repl, function(k, v) { if (k == 'text') { v = (typeof v === 'undefined' ? '' : v); v = v.replace(/(\r|\n)/g, ' <br /> '); // make newlines v = v.replace(/((http)?s?(\:\/\/)?((www)?\.?[a-zA-Z0-9]+\.[a-zA-Z]+\/?\S+))/g, '<a href="$1" target="_blank">$4</a>'); //make links }; html = html.replace(new RegExp('%' + k + '%', 'g'), (typeof v === 'undefined' ? '' : v).toString().replace(/\$/g, '$')); }); html = html.replace(/\[(id[0-9]+)\|([^\]+]+)\]/, '<a href="/$1">$2</a>'); // [id|name] -> <a href="/id">name</a> return html; } 

Those. in the template, a construction of the form % data% is replaced with the value of the data variable. This involved the original function. I added a couple more things: generating links to a profile from records of the form [id000000 | Ivan Ivanov] , generating links from urls in the message text, and processing end-of-line characters (hyphenation).


Cropped screen of real discussion

Full value. Gently, dimensions.

In general, everything is already working, but there is no main element - handles, having pulled that, we will see all these wonders. And here again, it was not without the share of reverse engineering. Vkontakte has a Wall class and a _repliesLoaded class method. It is called when the comments are loaded, which is clearly hinted at by the name. I replace this method with my own:

 var cloned_function = Wall._repliesLoaded; Wall._repliesLoaded = function(post, hl, replies, names, data) { cloned_function(post, hl, replies, names, data); wall_overloaded = true; setTimeout(replace_html, 300); }; 

Those. technically, I call it the same, but immediately after I launch a function that draws an icon in the required freshly loaded comments, clicking on which we will see a pop-up window with a chain of comments.

What is the result?


The extension works. Able to show comment chains with images and links. Able to follow the appeared content and add a button to the chain, where necessary.


Screen comments chain with links, images and line breaks.

Does not know how to build parallel chains for cases where the discussion forks and then “collapses” again to the final comment. Soon learn. In the process of selecting the data structure.

The frameworks are not smeared. For someone it is a plus, for someone a minus. I would very much like to throw my head up high and proudly declare: “And I don’t need them at all!” But no. Everything is more prosaic - I hardly know any local frameworks and batteries. JS is a non-core language.

Link to the source repository . I will be glad to forks and pull requests.

PS: I did not pay for my developer account in Google. I do not need it. If anyone wants, can safely put the extension in the chrome web store. If you also mention the author, it will be fine.

UPD: Great news! The extension has become available to everyone! MadDAD posted it in the chrome store - link .
Cheers, comrades! MadDAD , thank you very much. I am infinitely grateful.

Source: https://habr.com/ru/post/310146/


All Articles