Meteor client-side pagination - meteor

There's a collection Comments. Currently comments for the specfic Content are all published to the client.
Without pagination I can successfully render them in my template, insert new comments and enjoy the reactivity.
I'm fine at the moment with all comments sent to the client but I want to implement all-client-side pagination to visually simplify the page much like FB does.
Hare are the rules:
Comments are always sorted by the creation timestamp ASC (newer at the bottom of the list)
I need to show the total number of records in the collection (T)
I need to show the total number of comments currently displayed (C)
If there are more comments (C < T) I need to show a 'See more' link
Initially I show 5 newest comments (or all of them if there're less than 5)
New comments (pushed from the server) are instantly shown at the end of the list
When I click the 'See more' link up to 10 extra comments (the newest from the currently invisible -- and all of them are older that those already shown) are shown in the beginning of the list
So effectively it could be like:
have the minTime variable
initially set it to the timestamp of the 5th newest comment
when I click the link set it to the timestamp of the 10th newest comment older than the current value
template renders all the comments not older than this value
at some point calculate values C and T and save them
I tried to solve this with a bunch of Session variables but didn't succeed -- I think at some point getting and setting these vars from the template leads to recursion or what?
Additional problem is that I don't reliably know the 'initial' moment when I should calculate the minTime for the 1st time -- comments may still not be synched when the template is created or rendered for the first time.
So, the question: what is the proper way to fulfill my requirements?

Solution:
Meteor.startup(function(){
Session.set('number_of_visible_comments', 5);
});
Template.comments = function() {
return Comments.find({content: id_of_content}, {
sort: {timestamp: -1},
limit: Session.get('number_of_visible_comments')
});
};
Template.total_number_of_comments = function() {
return Comments.find({content: id_of_content}).count();
};
Template.number_of_visible_comments = function() {
return Session.get('number_of_visible_comments').count();
};
Template.comments.events({
'click': function() {
var count = Session.get('number_of_visible_comments') + 10;
Session.set('number_of_visible_comments', count);
}
});

In the meantime there are tow Meteor package for doing client-side pagination, one within a table. I admit I didn't go through all your requirements because of the comment exchange with ram1 above, but the package may help:
https://atmosphere.meteor.com/package/reactive-table
https://github.com/alethes/meteor-pages

Related

How to clean old deployed versions in Firebase hosting?

Every time you deploy to Firebase hosting a new deploy version is created so you can roll back and see who deployed. This means that each time every file you deploy is stored and occupying more space.
Other than manually deleting each deployed version one by one, is there any automated way to clean those useless files?
You're correct. You'll need to delete the old deployed versions one by one using the Firebase Hosting console.
There's no other way to do this, so I'd suggest you to file a feature request to enable deletion of multiple deployed version in the Firebase Hosting console.
Update:
You can vote here (please avoid +1 spam, use reactions) https://github.com/firebase/firebase-tools/issues/215#issuecomment-314211730 for one of the alternatives proposed by the team (batch delete, keep only X versions, keep versions with published date < Y)
UPDATE Mar/2019
There's now a proper solution: "Version history settings" which allows to keep the last X versions.
https://support.google.com/firebase/answer/9242086?hl=en
UPDATE Feb/2019
Confirmed by Google employee # github.com/firebase/firebase-tools/issues/...
It is actively being worked on. 🙂
🎉🎉🎉
Before continuing reading:
You can vote here (please avoid +1 spamming, use reactions) https://github.com/firebase/firebase-tools/issues/215#issuecomment-314211730 for one of the alternatives proposed by the team
So, by using Chrome Dev tools I found a way to delete multiple versions. Keep in mind it requires a bit for work (proceed with care since deleted versions can't be restored and you won't get any warnings like when using the UI).
Step 1. Retrieving the version list.
Open Chrome Dev Tools (if you don't know how to chances are you should wait for a proper solution by Firebase's team).
Open Firebase's Console and go to the "Hosting" tab.
Go to the "Network" tab on CDT and use the Websockets filter.
Select the request named .ws?v=5&ns=firebase
Open the "Frames" tab
Now comes the tedious part: Select the frames with the highest "length" value. (Depending on your data, it could be 2-n frames. In my case, 3 frames with 14k-16k length)
Paste each of the frame's data in order (which will form a valid JSON object).
Extracting the data: There are several ways to do it. I opted for simple JS on CDT's console.
var jsonString = '...';
var json = JSON.parse(jsonString);
var ids = Object.keys(json.d.b.d);
Step 2. Performing the requests
Almost there :P
Now that you have the IDs, perform the following requests:
DELETE https://firebasehosting.clients6.google.com/v1beta1/sites/PROJECT_NAME/versions/-VERSION_ID?key=KEY
I used Sublime (to create the request strings) + Paw.
The "KEY" can be copied from any of CDT's requests. It doesn't match Firebase's Web API key
=> Before performing the requests: take note of the version you don't want to delete from the table provided by Firebase. (Each version listed on the website has the last 6 digits of it's ID under your email)
(Screenshots weren't provided since all of them would require blurring and a bit of work)
This script is not yet super-solid, so use it at your own risk. I'll try to update it later, but worked for me for now.
Just some javascript to click on buttons to delete deployed items one by one.
var deleteDeployment = function(it) {
it.click()
setTimeout(function() {
$('.md-dialog-container .delete-dialog button.md-raised:contains("Delete")').click()
}, 300)
}
$('.h5g-hist-status-deployed').map((i, a) => $(a).parent()).map((i, a) => $(a).find('md-menu button:contains(Delete)')).each((i, it) => {
setTimeout(function() {
deleteDeployment(it)
}, (i + 1) * 2000)
})
Firebase finally implemented a solution for this.
It is now possible to set a limit of retained versions.
https://firebase.google.com/docs/hosting/deploying#set_limit_for_retained_versions
EDIT: previous link is outdated. Here is a new link that works:
https://firebase.google.com/docs/hosting/usage-quotas-pricing#control-storage-usage
This may be a bit brittle due to the selectors' reliance on current DOM structure and classes on the Hosting Dashboard, but it works for me!
NOTE: This script (if executed from the console) or bookmarklet will click and confirm delete on all of the rows in the current view. I'm fairly certain that even if you click delete on the current deployment it will not delete it.
Function for running in console:
let deleteAllHistory = () => {
let deleteBtns = document.querySelectorAll('.table-row-actions button.md-icon-button');
const deleteBtn = (pointer) => {
deleteBtns[pointer].click();
setTimeout(() => {
document.querySelector('.md-open-menu-container.md-clickable md-menu-item:last-child button').click();
setTimeout(() => {
document.querySelector('.fb-dialog-actions .md-raised').click();
if(pointer < deleteBtns.length - 1) {
deleteBtn(pointer + 1);
}
}, 500);
}, 500);
};
deleteBtn(0);
};
Bookmarklet:
javascript:(function()%7Bvar%20deleteBtns%3Ddocument.querySelectorAll('.table-row-actions%20button.md-icon-button')%2CdeleteBtn%3Dfunction(a)%7BdeleteBtns%5Ba%5D.click()%2CsetTimeout(function()%7Bdocument.querySelector('.md-open-menu-container.md-clickable%20md-menu-item%3Alast-child%20button').click()%2CsetTimeout(function()%7Bdocument.querySelector('.fb-dialog-actions%20.md-raised').click()%2Ca%3CdeleteBtns.length-1%26%26deleteBtn(a%2B1)%7D%2C500)%7D%2C500)%7D%3BdeleteBtn(0)%7D)()
Nathan's option is great, but I have a quick-and-dirty method using AutoHotkey. Takes about a second per version to delete, so you can knock out a page in 10 seconds.
#a::
Click
MouseGetPos, xpos, ypos
MouseMove, xpos, ypos + 30
Sleep 300
Click
Sleep 400
Click 1456, 816
MouseMove, xpos, ypos + 82
return
#s::
Click
MouseGetPos, xpos, ypos
MouseMove, xpos, ypos - 820
return
You'll likely need to modify the exact pixel values for your screen, but this works perfectly on my 1920x1080.
Win + a is delete and move to the next entry, Win + s is move to the next page. Put your mouse on the first 3-dot menu and go for it!
On top of the release history table, click the tool bar and select "Version history settings". Set to desired amount and click save.This will auto delete older deployments.
I don't know it can help you or not but I can delete old deployments from "hosting" menu like this:
Delete or rollback old deployment

Discussion pagination in elgg 1.8 is not working properly

We have a website created using elgg, and we have discussion part of elgg where pagination is not working properly.
When listing all discussion list, pagination is working correctly, from latest to oldest
But pagination inside topic (one of the discussion) where replies are too many, and they separated by pagination (Previous, next), it is showing replies incorrectly:
In the first page we have:
As you can see it is ordered from latest to oldest: 17 days ago and then comes 21 days ago.
But when you go next page:
It is ordered inside the page from latest to oldest, but the the pages should be swapped.
How can I fix it?
Thanks forward
It works properly. Discussions are ordered by last action on the thread. You may have older thread first due to it having most recent response of all threads.
To change it, look at discussion_handle_list_page function in mod/groups/lib/discussion and how it uses order_by parameter. You need to override this page and just remove order_by to use default ordering, which is creation time of the entity (in his case thread). You could do it by tapping to the "route" plugin hook, or overriding whole discussions page handler.
And that's why not just change it inline: http://learn.elgg.org/en/1.9/guides/dont-modify-core.html
I have found finally going through all pagination libraries, and annotation views.
The problem is when listing replies for discussion on replies.php file which in /views/default/discussion there are two jquery functions on the bottom of the page that reverse the order.
function reverse(arr){
var newArr = [];
for(var iter = arr.length -1; iter >= 0; iter--){
newArr.push(arr[iter])
}
return newArr;
}
I have change the iter to start from 0 and go to arr.lenthg.
But it is not all yet, in order to get the latest replies first, I have added to
$options = array(
'guid' => $vars['entity']->getGUID(),
'annotation_name' => 'group_topic_post',
);
this line:
'order_by'=> 'time_created desc'
And then I got my replies ordered correctly: from latest to oldest.

select number of items in drupal views

Is there a way i can have an exposed filter wherein the user can select the number of items displayed by the drupal view?
I am nearly positive that you can do this with hook_views_pre_build (&$view). I know for a fact that you can mess with $view->pager to update whether to use the pager or not and to alter the number of items per page.
This is a snippet from a custom module I did:
if (is_numeric($perpage) && (int) $perpage > 1) {
$view->pager["items_per_page"] = (int) $perpage;
} else if ($perpage == "all") {
$view->pager["use_pager"] = false;
$view->pager["items_per_page"] = 0;
}
I suspect you can turn the pager off and also set the items per page to limit the results.
EDIT:
OK, just saw the part about the exposed filter. The code snippet is actually from a bit of code that simulates an exposed filter for this case. The page has some links on it to select the number of items per page. The links refresh the page, and tack on a perpage=whatever parameter. The hook then sanitizes the input, and basically runs the code snippet above. I have also done something similar using HTML a select, and then wiring up the parameter w/ refresh using jQuery.
Based on this thread in the issue queue, that appears to be a long requested feature. It has apparently been added to the 6.x-3.x-dev branch, so it should be available in the 6.x-3.0-alpha3 release.
Or if you're using Drupal 7, it has been added to the 7.x-3.x-dev branch too, so it should be in the 7.x-3.0-alpha1 release.

add expiration date to a node in Drupal

i want to add an expiration date field to my custom content type in Drupal. it should specified by days (7-15-.... days after creating node) and after it reached the node should not display in site to visitors. but i need a renew option for it to allow creator renew it and activate it again.
is it too hard to impelmentation? how can i do it?
Have you already tried searching for modules?
Here's one that might do the trick http://drupal.org/project/auto_expire. There are others as well,but maybe you should check them out to see which one fits your needs (or can be altered easily if needed).
You can use Views to do that. Make a new View, specifically for a node or more nodes of that type, and put a filter on it with "Node:Updated". Then specify how many days you need.
You can create a View for the original poster and have him update the post, which will reset the counter.
A creative solution, but it should work.
Take a look at Node expire which sets up timers for nodes based on Rules. For a simpler approach, Scheduler can do it to. Both are linked from the Auto Expire module linked by wimvds, so there is some measure of duplication, though they do seem to have different approaches.
The following code may be of interest. It's a small snippet from a module i've had to create to auto expire adverts on an intranet site. The nodes simply unpublish after a number of days you specify in the code so could be hidden from your site and then the author of the content could simply just re -publish the nodes if they needed to.
/**
* Implementation of hook_cron().
*/
function auto_unpublish_pages_cron() {
//we only want to deal with all blog_post content type nodes
$c_type = 'blog_post';
//grab all nodes
$c_nodes = node_load_multiple(array(), array('type' => $c_type));
//setup time stamp for node expiry
$message_search_data = strtotime('- 7 days');
//now loop through nodes, & if they are old, expire them
foreach ($c_nodes as $m) {
$obj = entity_metadata_wrapper('node', $m);
//check when was last updated and if its still published
$last_update = $obj->changed->value();
$published = $obj->status->value();
//if it's still published & it's not recent, unpublish it
if (($message_search_date > $last_update) && $published<>0) {
$obj->status = 0;
$obj->save();
}
}
}

Drupal module to control user post frequency?

We've been having a new type of spam-bot this week at PortableApps.com which posts at a rate of about 10 comments a minute and doesn't seem to stop - at least the first hour or so (we've always stopped it within that time so far). We've had them about a dozen times in the last week - sometimes stopping it at 50 or 60, sometimes up to 250 or 300. We're working to stop it and other spam bots as much as possible, but at the moment it's still a real pest.
I was wondering whether in the mean time whether there's any sort of module to control the frequency a user can post at to e.g. 50 an hour or something like 10 in an hour for new users. That at least would mean that instead of having to clear up 300 comments 50 at a time in admin/content/comment we'd have a smaller number to clear. (A module to add a page to delete all content by a user and block them would also be helpful!)
I believe that there's a plugin to do this available for WordPress, but can't find any such thing for Drupal.
For your second question, i would have a look at the code of the User Delete module (click).
The module also disables the user account and unpublished all nodes/comments from a certain user. By extending the code, you could easily create another possibility to unpublish + delete all nodes/comments from a certain user and blocking the account.
After the unpublish code in the module, you should just put delete code (in sql if the module is selecting by a sql-query or by using the drupal delete functions).
Another option would be so make a view (using the view module) only to be viewed by administrators, where you choose a certain user using the filters and then lists his/her posts. Then in the node-contenttype.tpl.php you place a button that calls a function which deletes all nodes/comments and the user.
First problem (post frequency)
I've been thinking about the comment post limit. If I remember correctly Drupal stores comments in a seperate table and has comment specific functions.
I'd create a new module and using the comment_nodeapi function i would check in the operation 'insert' how much comments the current user has already made within a certain timeframe.
To check this I would write a custom sql query on the database which takes the count of alle comments made by uid where the post_date is larger then NOW-1hour. If that count is larger then 10 or 15 or whatever post frequency you want then you give a message back to the user. You can retrieve the user id and name by using the global $user variable.
(example: print $user->name;)
You have to check on your own for the sql query but here's some code when you have the amount:
<?php
function comment_nodeapi(&$node, $op, $arg = 0) {
switch ($op) {
case 'insert':
//PLACE HERE THE SQL TO GET THE COUNT
if($count > 15){
$repeat = FALSE;
$type = 'status'
drupal_set_message("You have reached the comment limit for this time.", $type, $repeat);
break;
}else{
db_query('INSERT INTO {node_comment_statistics} (nid, last_comment_timestamp, last_comment_name, last_comment_uid, comment_count) VALUES (%d, %d, NULL, %d, 0)', $node->nid, $node->changed, $node->uid);
break;
}
}
}
?>
(this code has not been tested so no guarantees, but this should put you on the right track)
I would suggest something like Mollom (from the creator of Drupal). It scans the message for known spam pattern/keywords/... and if this scan fails, it displays a CAPTCHA to the user to make sure that it's a real human that wants to enter content that has the same properties like spam.
They offer a free service and some paid solutions. We are using it for some customers and it's worth the money. It also integrates very well in Drupal.
Comment Limit is probably what you need.
http://drupal.org/project/spam
http://drupal.org/project/antispam - with akismet support

Resources