Mixitup.js and multiple filtering - javascript

I've taken the code from http://codepen.io/patrickkunka/pen/iwcap and modified it, but i can't make it work as desired.
If i select only 1 filter, it works fine - but if i start compare my filters, it's not returning the correct result.
I'm returning the "filters" dynamicly - but that shouldn't be the problem.
Can anyone give me some heads up on this?
Link for js fiddle :
http://jsfiddle.net/u6ksLwts/26/
// Loop through all div's with .mix class
var genders = [];
var models = [];
var brands = [];
var prices = [];
$(".mix").each(function () {
addToArrayIfNew(genders, $(this).attr('data-Gender'));
addToArrayIfNew(models, $(this).data('model'));
addToArrayIfNew(brands, $(this).data('brand'));
if ($(this).data('brand').match(/\s/g)){
$(this).addClass('Brand_' + $(this).data('brand'));
}
addToArrayIfNew(prices, $(this).data('price'));
// Fix invalid css class names
});
// Now return the arrays to HTML code
if (models.length > 0) {
var filterName = 'Model';
var idName = 'ModelsFilter';
$("#" + idName).append(RenderHTMLFilterBoxes(filterName, models));
}
if (genders.length > 0) {
var filterName = 'Gender';
var idName = 'GendersFilter';
$("#" + idName).append(RenderHTMLFilterBoxes(filterName, genders));
}
if (brands.length > 0) {
var filterName = 'Brand';
var idName = 'BrandsFilter';
$("#" + idName).append(RenderHTMLFilterBoxes(filterName, brands));
}
function RenderHTMLFilterBoxes(filterName, arraylist) {
var htmlStr = "";
for (var i in arraylist) {
htmlStr = htmlStr + '<div class="filterBoxes"><div class="checkbox">';
htmlStr = htmlStr + '<input type="checkbox" value=".' + filterName + '_' + arraylist[i].replace(/[^a-zA-Z]+/g,'') + '" />';
htmlStr = htmlStr + '<label>' + arraylist[i] + '</label>';
htmlStr = htmlStr + '</div></div>';
}
return htmlStr;
}
function addToArrayIfNew(arr, item) {
if (item && jQuery.inArray(item, arr) == -1) {
arr.push(item);
}
}
function RenderHTMLPriceRange() {
var lowest = Number.POSITIVE_INFINITY;
var highest = Number.NEGATIVE_INFINITY;
var tmp;
for (var i = prices.length - 1; i >= 0; i--) {
tmp = prices[i];
if (tmp < lowest) lowest = tmp;
if (tmp > highest) highest = tmp;
}
console.log(highest, lowest);
}
// MIX IT UP CODE
// To keep our code clean and modular, all custom functionality will be contained inside a single object literal called "checkboxFilter".
var checkboxFilter = {
// Declare any variables we will need as properties of the object
$filters: null,
$reset: null,
groups: [],
outputArray: [],
outputString: '',
// The "init" method will run on document ready and cache any jQuery objects we will need.
init: function () {
var self = this; // As a best practice, in each method we will asign "this" to the variable "self" so that it remains scope-agnostic. We will use it to refer to the parent "checkboxFilter" object so that we can share methods and properties between all parts of the object.
self.$filters = $('#Filters');
self.$reset = $('#Reset');
self.$container = $('#Container');
self.$filters.find('.filterBoxes').each(function () {
self.groups.push({
$inputs: $(this).find('input'),
active: [],
tracker: false
});
});
// console.log(self.groups);
self.bindHandlers();
},
// The "bindHandlers" method will listen for whenever a form value changes.
bindHandlers: function () {
var self = this;
self.$filters.on('change', function () {
self.parseFilters();
});
self.$reset.on('click', function (e) {
e.preventDefault();
self.$filters[0].reset();
self.parseFilters();
});
},
// The parseFilters method checks which filters are active in each group:
parseFilters: function () {
var self = this;
// loop through each filter group and add active filters to arrays
for (var i = 0, group; group = self.groups[i]; i++) {
group.active = []; // reset arrays
group.$inputs.each(function () {
$(this).is(':checked') && group.active.push(this.value);
});
group.active.length && (group.tracker = 0);
}
// console.log(self.groups);
self.concatenate();
},
// The "concatenate" method will crawl through each group, concatenating filters as desired:
concatenate: function () {
var self = this,
cache = '',
crawled = false,
checkTrackers = function () {
console.log(1);
var done = 0;
for (var i = 0, group; group = self.groups[i]; i++) {
(group.tracker === false) && done++;
}
return (done < self.groups.length);
},
crawl = function () {
// console.log(2);
for (var i = 0, group; group = self.groups[i]; i++) {
group.active[group.tracker] && (cache += group.active[group.tracker]);
if (i === self.groups.length - 1) {
self.outputArray.push(cache);
cache = '';
updateTrackers();
}
}
},
updateTrackers = function () {
//console.log(3);
for (var i = self.groups.length - 1; i > -1; i--) {
var group = self.groups[i];
if (group.active[group.tracker + 1]) {
group.tracker++;
break;
} else if (i > 0) {
group.tracker && (group.tracker = 0);
} else {
crawled = true;
}
}
};
self.outputArray = []; // reset output array
do {
crawl();
}
while (!crawled && checkTrackers());
self.outputString = self.outputArray.join();
// If the output string is empty, show all rather than none:
!self.outputString.length && (self.outputString = 'all');
//console.log(self.outputString);
// ^ we can check the console here to take a look at the filter string that is produced
// Send the output string to MixItUp via the 'filter' method:
if (self.$container.mixItUp('isLoaded')) {
// console.log(4);
self.$container.mixItUp('filter', self.outputString);
// console.log(self.outputString);
}
}
};
// On document ready, initialise our code.
$(function () {
// To avoid non javascript browsers not to see the content, the display:none will first be set
// here, instead of the CSS file
// Initialize checkboxFilter code
checkboxFilter.init();
// Instantiate MixItUp
$(".mix").css("display", "none");
$('#Container').mixItUp({
load: {
filter: 'none'
},
controls: {
toggleLogic: 'or',
toggleFilterButtons: true,
enable: true // we won't be needing these
},
animation: {
easing: 'cubic-bezier(0.86, 0, 0.07, 1)',
duration: 600
}
});
});
HTML :
<div id="Filters">
<div id="GendersFilter"></div>
<div id="BrandsFilter"></div>
<div id="ModelsFilter"></div>
</div>
<div id="Container">
<div class="mix Brand_MystBrandname Model_ Gender_0" data-Gender="0" data-Brand="My 1st. Brand name!" data-Model="" data-Price="1000">My 1st. Brand name!</div>
<div class="mix Brand_Casio Model_ Gender_0" data-Gender="0" data-Brand="Casio" data-Model="" data-Price="10">My casio block</div>
<div class="mix Brand_Seiko Model_ Gender_2" data-Gender="2" data-Brand="Seiko" data-Model="Precision" data-Price="200">My seiko block</div>
<div class="mix Brand_Nikon Model_Lada Gender_1" data-Gender="1" data-Brand="Nikon" data-Model="Lada" data-Price="40">My Nikon block</div>
<div class="mix Brand_DELL Model_2 Gender_Inspirion" data-Gender="1" data-Brand="DELL" data-Model="Inspirion" data-Price="500">My Dell block</div>
</div>
<script src="http://cdn.jsdelivr.net/jquery.mixitup/latest/jquery.mixitup.min.js"></script>

self.$filters.find('.filterBoxes').each(function () {
self.groups.push({
$inputs: $(this).find('input'),
active: [],
tracker: false
});
});
changed to
> self.$filters.find('.filters').each(function () {
> self.groups.push({
> $inputs: $(this).find('input'),
> active: [],
> tracker: false
> });
> });
and added css class "filters" on each of the groups
<div id="Filters">
<div id="GendersFilter" class="filters"></div>
...
</div>

Related

Custom downloading image in PhotoSwipe.js

I am using PhotoSwipe gallery for my project.
On the line 175 there is a code url:items[0].hqImage, I want to use index of current image instead of 0, how can I do that?
I've tried to use pswp.listen('afterChange', function() { }); event, like so:
//at the start of the document
var downloadIndex = 0;
//in initPhotoSwipeFromDOM function after gallery.listen('imageLoadComplete') event
gallery.listen('beforeChange', function() {
downloadIndex +=1;
console.log(downloadIndex)
;});
but when I am swiping my gallery it send me output like this:
0 1 2 3 after swiping the first image, 5 6 after second, and this code start iterating as it should, only on 5 out of 6 images.
Program code provided bellow.
(function() {
var pswpElement = document.querySelectorAll('.pswp')[0];
if (pswpElement) {
var gallerySelector = '.masonry';
var initPhotoSwipeFromDOM = function(gallerySelector) {
// parse slide data (url, title, size ...) from DOM elements
// (children of gallerySelector)
var parseThumbnailElements = function(el) {
var thumbElements = $(el).find('.masonry-item').toArray(),
numNodes = thumbElements.length,
items = [],
figureEl,
linkEl,
size,
imgEl,
item;
for (var i = 0; i < numNodes; i++) {
figureEl = thumbElements[i]; // <figure> element
// include only element nodes
if (figureEl.nodeType !== 1) {
continue;
}
linkEl = figureEl.children[0]; // <a> element
imgEl = linkEl.children[0]; // <img>
size = linkEl.getAttribute('data-size');
size = size && size.split('x');
// create slide object
item = {
src: linkEl.getAttribute('href'),
w: size && parseInt(size[0], 10) || imgEl.width,
h: size && parseInt(size[1], 10) || imgEl.height,
title: linkEl.getAttribute('data-caption'),
hqImage: linkEl.getAttribute('original-image')
};
if (figureEl.children.length > 1) {
item.title = figureEl.children[1].innerHTML;
}
if (linkEl.children.length > 0) {
// <img> thumbnail element, retrieving thumbnail url
item.msrc = linkEl.children[0].getAttribute('src');
}
item.el = figureEl; // save link to element for getThumbBoundsFn
items.push(item);
}
return items;
};
// find nearest parent element
var closest = function closest(el, fn) {
return el && (fn(el) ? el : closest(el.parentNode, fn));
};
// triggers when user clicks on thumbnail
var onThumbnailsClick = function(e) {
e = e || window.event;
var eTarget = e.target || e.srcElement;
// find root element of slide
var clickedListItem = closest(eTarget, function(el) {
return (el.className && el.className.toUpperCase() === 'MASONRY-ITEM');
});
if (!clickedListItem) {
return;
}
if (e.preventDefault) {
e.preventDefault();
} else {
e.returnValue = false;
}
// find index of clicked item by looping through all child nodes
// alternatively, you may define index via data- attribute
var clickedGallery = $(clickedListItem).closest(gallerySelector)[0],
childNodes = $(clickedGallery).find('.masonry-item').toArray(),
numChildNodes = childNodes.length,
nodeIndex = 0,
index;
for (var i = 0; i < numChildNodes; i++) {
if (childNodes[i].nodeType !== 1) {
continue;
}
if (childNodes[i] === clickedListItem) {
index = nodeIndex;
break;
}
nodeIndex++;
}
if (index >= 0) {
// open PhotoSwipe if valid index found
openPhotoSwipe(index, clickedGallery);
}
return false;
};
// parse picture index and gallery index from URL (#&pid=1&gid=2)
var photoswipeParseHash = function() {
var hash = window.location.hash.substring(1),
params = {};
if (hash.length < 5) {
return params;
}
var vars = hash.split('&');
for (var i = 0; i < vars.length; i++) {
if (!vars[i]) {
continue;
}
var pair = vars[i].split('=');
if (pair.length < 2) {
continue;
}
params[pair[0]] = pair[1];
}
if (params.gid) {
params.gid = parseInt(params.gid, 10);
}
return params;
};
var openPhotoSwipe = function(index, galleryElement, disableAnimation, fromURL) {
var pswpElement = document.querySelectorAll('.pswp')[0],
gallery,
options,
items;
items = parseThumbnailElements(galleryElement);
// define options (if needed)
options = {
// define gallery index (for URL)
galleryUID: galleryElement.getAttribute('data-pswp-uid'),
getThumbBoundsFn: function(index) {
// See Options -> getThumbBoundsFn section of documentation for more info
var thumbnail = items[index].el.getElementsByTagName('img')[0], // find thumbnail
pageYScroll = window.pageYOffset || document.documentElement.scrollTop,
rect = thumbnail.getBoundingClientRect();
return {
x: rect.left,
y: rect.top + pageYScroll,
w: rect.width
};
},
bgOpacity:0.85,
timeToIdle: 3000,
shareButtons: [
{id:'facebook', label:'Share on Facebook', url:'https://www.facebook.com/sharer/sharer.php?u={{url}}'},
{id:'twitter', label:'Tweet', url:'https://twitter.com/intent/tweet?text={{text}}&url={{url}}'},
{id:'pinterest', label:'Pin it', url:'http://www.pinterest.com/pin/create/button/?url={{url}}&media={{image_url}}&description={{text}}'},
{id:'vk', label:'Share on VK', url:'https://vk.com/share.php?url={{url}}'},
{id:'download', label:'Download HQ image', url:items[0].hqImage, download:true } //items[index].hqImage
],
closeOnScroll:false,
};
// PhotoSwipe opened from URL
if (fromURL) {
if (options.galleryPIDs) {
// parse real index when custom PIDs are used
// http://photoswipe.com/documentation/faq.html#custom-pid-in-url
for (var j = 0; j < items.length; j++) {
if (items[j].pid == index) {
options.index = j;
break;
}
}
} else {
// in URL indexes start from 1
options.index = parseInt(index, 10) - 1;
}
} else {
options.index = parseInt(index, 10);
}
// exit if index not found
if (isNaN(options.index)) {
return;
}
if (disableAnimation) {
options.showAnimationDuration = 0;
}
// Pass data to PhotoSwipe and initialize it
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
gallery.listen('imageLoadComplete', function(index, item) {
var linkEl = item.el.children[0];
var img = item.container.children[0];
if (!linkEl.getAttribute('data-size')) {
linkEl.setAttribute('data-size', img.naturalWidth + 'x' + img.naturalHeight);
item.w = img.naturalWidth;
item.h = img.naturalHeight;
gallery.invalidateCurrItems();
gallery.updateSize(true);
}
});
gallery.init();
};
// loop through all gallery elements and bind events
var galleryElements = document.querySelectorAll(gallerySelector);
for (var i = 0, l = galleryElements.length; i < l; i++) {
galleryElements[i].setAttribute('data-pswp-uid', i + 1);
galleryElements[i].onclick = onThumbnailsClick;
}
// Parse URL and open gallery if it contains #&pid=3&gid=1
var hashData = photoswipeParseHash();
if (hashData.pid && hashData.gid) {
openPhotoSwipe(hashData.pid, galleryElements[hashData.gid - 1], true, true);
}
};
// execute above function
initPhotoSwipeFromDOM(gallerySelector);
}
})();
<!--for the grid layout I use Isotope.js-->
<div class="masonry">
<div class="masonry-sizer"></div>
<div class="masonry-item">
<a href="../../img/paintings/Graia.jpg" data-caption="Graia<br>1" original-image='../../img/original/paintings/Graia.jpg'>
<img class="masonry-content" src="../../img/previews/paintings/Graia.webp">
</a>
</div>
</div>
So, I've changed photoswipe-ui-default.js line
getImageURLForShare: function( /* shareButtonData */ ) {
return pswp.currItem.src || '';
to
getImageURLForShare: function( /* shareButtonData */ ) {
return pswp.currItem.hqImage || '';
And it worked out for me.

TinyMce 5 setcontent unable to set html properly

I am writing a tinymce custom plugin called Mergetable. which will merger two user selected table.
Problem statement:
TinyMce is not allowing to select two table , by using shift and mouse I can select content of the table. So I can't use tinmce.activeeditor.selection.getNode() method instead using tinmce.activeeditor.selection.getContent().
Form getcontent() method I am getting proper html of both table. After do some operation while setting content using tinmce.activeeditor.selection.setContent() both table merged properly but two more table with empty td created one in top and one in bottom . Please see below plugin code.
code:
(function () {
var mergeTable = (function () {
'use strict';
tinymce.PluginManager.add("mergeTable", function (editor, url) {
function Merge(){
var selectedhtml=editor.selection.getContent();
//using getContent() as getnode returning body node
var dv=document.createElement('div');
dv.innerHTML= selectedhtml;
var tableElements = dv.getElementsByTagName('TABLE');
if (tableElements.length == 2) {
var tableOne = tableElements[0];
var tableTwo = tableElements[1];
var tempTable = null;
var offsetLeft = tableOne.offsetLeft;
var offsetTop = tableOne.offsetTop;
var elem = tableElements[0];
if (tableOne.nodeName == "TABLE" && tableTwo.nodeName == "TABLE") {
for (var r = 0; r < tableTwo.rows.length; r++) {
var newTR = tableOne.insertRow(tableOne.rows.length);
for (var i = 0; i < tableTwo.rows[r].cells.length; i++) {
var newTD = newTR.insertCell()
newTD.innerHTML = tableTwo.rows[r].cells[i].innerHTML;
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan;
newTD.rowSpan = tableTwo.rows[r].cells[i].rowSpan;
newTD.style.cssText = tableTwo.rows[r].cells[i].style.cssText;
if (tableOne.style.border != "") {
newTD.style.border = "1px dotted #BFBFBF"
}
}
}
tableTwo.remove();
console.log(dv.innerHTML);
editor.selection.setContent(dv.innerHTML);
editor.nodeChanged();
}
else {
alert("Please select two tables");
}
}
}
editor.ui.registry.addButton('mergeTable', {
text: "Merge Table",
onAction: function(){ Merge();}
});
});
}());
}());
I am able to fix my problem by using some work around . Instead use setContent() method. I have remove selected content and use insertContent().
Please find working code below.
(function () {
var mergeTable = (function () {
'use strict';
tinymce.PluginManager.add("mergeTable", function (editor, url) {
var cmd = function (command) {
return function () {
return editor.execCommand(command);
};
};
function Merge(){
var selectedhtml=editor.selection.getContent();
var dv=document.createElement('div');
dv.innerHTML= selectedhtml;
var tableElements = dv.getElementsByTagName('TABLE');
if (tableElements.length == 2) {
var tableOne = tableElements[0];
var tableTwo = tableElements[1];
var tempTable = null;
var tableOneMaxCell=0
var tabletwoMaxCell=0
var tempCellcount=0
var tableOneRowcount=tableOne.rows.length;
tableOne.querySelectorAll("tr").forEach(function(e){
tempCellcount= e.querySelectorAll("td").length ;
if(tempCellcount>tableOneMaxCell)
{
tableOneMaxCell=tempCellcount;
}
});
tableTwo.querySelectorAll("tr").forEach(function(e){
tempCellcount= e.querySelectorAll("td").length ;
if(tempCellcount>tabletwoMaxCell)
{
tabletwoMaxCell=tempCellcount;
}
});
if (tableOne.nodeName == "TABLE" && tableTwo.nodeName == "TABLE") {
for (var r = 0; r < tableTwo.rows.length; r++) {
var newTR = tableOne.insertRow(tableOne.rows.length);
for (var i = 0; i < tableTwo.rows[r].cells.length; i++) {
var newTD = newTR.insertCell()
newTD.innerHTML = tableTwo.rows[r].cells[i].innerHTML;
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan;
newTD.rowSpan = tableTwo.rows[r].cells[i].rowSpan;
newTD.style.cssText = tableTwo.rows[r].cells[i].style.cssText;
if (tableOne.style.border != "") {
newTD.style.border = "1px dotted #BFBFBF"
}
if(i==tableTwo.rows[r].cells.length-1 && tableOneMaxCell>tabletwoMaxCell){
newTD.colSpan = tableTwo.rows[r].cells[i].colSpan + (tableOneMaxCell-tabletwoMaxCell);
}
}
}
for( var t1=0; t1<tableOneRowcount; t1++ ){
var celllen=tableOne.rows[t1].cells.length;
tableOne.rows[t1].cells[celllen-1].colSpan=tableOne.rows[t1].cells[celllen-1].colSpan+(tabletwoMaxCell-tableOneMaxCell)
}
tableTwo.remove();
// cmd('mceTableDelete');
// var selObj = editor.selection;
// var selstartRange = selObj.getStart();
// var selectendRange= selObj.getEnd();
// var selrng=selObj.getRng();
// console.log(selstartRange);
// console.log(selectendRange);
// editor.execCommand('mceTableDelete');
// selObj.removeAllRanges();
editor.selection.getSelectedBlocks().forEach(function(elm){
elm.remove();
});
// selObj.setRng(selrng,true);
editor.insertContent(dv.innerHTML);
editor.nodeChanged();
}
else {
editor.notificationManager.open({
text: 'Please select two table.',
type: 'error'
});
}
}
else {
editor.notificationManager.open({
text: 'Please select two table.',
type: 'error'
});
}
}
editor.ui.registry.addButton('mergeTable', {
text: "MergeTable",
onAction: function(){ Merge();}
});
});
}());
}());

Is it Possible/Okay to have two controller files for one view in meteor?

so heres my folder structure for the client:
https://s3.amazonaws.com/f.cl.ly/items/0I0S063e3U0A2o2s3k21/Image%202014-12-05%20at%206.42.17%20PM.png
The problem is I have two states for tournaments... One Live and One noLive.
The use all the exact same views ect but could potentially have very different functionality.
Is there a trick were I can use two completely different controllers for the same view based on the data the view needs to load in iron router or something?
-thanks
For reference here is my:
routes.js for tourneys:
/* Tournaments / Browse section */
Router.route('/tournaments/:_id', function () {
this.fastRender = true;
// add the subscription handle to our waitlist
this.wait(Meteor.subscribe('campaigns'));
// this.ready() is true if all items in the wait list are ready
// console.log("Tournaments.findOne({_id: this.params._id}:", Campaigns.findOne({_id: this.params._id}));
if (this.ready()) {
this.render('tournament', {
data: function () {
return Campaigns.findOne({_id: this.params._id});
}
});
} else {
this.render('loading');
}
});
tournaments.js:
/* Globals */
Template.tournament.rendered = function () {
var self = this;
var participants = $('.participant-id');
var currentParticipant;
var nextRound;
var thisMatch;
var nextMatch;
var bracket;
participants.map(function(index, value){
if ($(value).text() === Meteor.userId()) {
if ($(value).parent().find('.participant-status').text() === 'undetermined') {
nextRound = $(value).parent().find('.participant-round').text();
thisMatch = $(value).parent().find('.participant-match').text();
bracket = $(value).parent().parent().parent().find('.participant');
};
};
});
nextRound = parseInt(nextRound) + 1;
nextMatch = Math.round(parseInt(thisMatch)/2) - 1;
if (parseInt(thisMatch) % 2 != 0) {
currentParticipant = 0;
}else{
currentParticipant = 1;
}
var winnerOptions = '';
var winnerBox = $('<div class="select-winner">');
bracket.map(function(index, value) {
winnerOptions += '<span class="winner-option"> '+$(value).find('.participant-title').text()+' <div class="winner-info"> '+$(value).find('a').html()+' </div> </span>'
});
winnerBox.append(winnerOptions);
$($($('.round'+nextRound).find('li')[nextMatch]).find('.participant')[currentParticipant]).removeClass('loser').addClass('undetermined');
$($($('.round'+nextRound).find('li')[nextMatch]).find('.participant')[currentParticipant]).find('a').addClass('tooltip').html(winnerBox);
var tournamentStartTime = function(){
var d = new Date();
var n = d.getTime();
var currentTime = TimeSync.serverTime(n);
var startTime = self.data.card.startTime;
var difference = startTime - currentTime;
var hoursDifference = Math.floor(difference/1000/60/60);
difference -= hoursDifference*1000*60*60
var minutesDifference = Math.floor(difference/1000/60);
difference -= minutesDifference*1000*60
var secondsDifference = Math.floor(difference/1000);
/* if ends (make tournament live server side?) */
if (hoursDifference < 0 || minutesDifference < 0 || secondsDifference < 0) {
Meteor.clearInterval(tStartTime);
Session.set("tournamentStartTime", false);
}else{
if (hoursDifference < 10) {hoursDifference = "0"+hoursDifference;}
if (minutesDifference < 10) {minutesDifference = "0"+minutesDifference;}
if (secondsDifference < 10) {secondsDifference = "0"+secondsDifference;}
var formattedTime = hoursDifference + ':' + minutesDifference + ':' + secondsDifference;
Session.set("tournamentStartTime", formattedTime);
}
};
Session.set("tournamentStartTime", '00:00:00');
tournamentStartTime();
var tStartTime = Meteor.setInterval(tournamentStartTime, 1000);
};
Template.tournament.events({
// Select winner from 2 options in tooltip
// Then previous round is given winner class on correct person
'click .winner-option': function(event){
// var self = $(event.target)
// var winner = self.text()
// self.parent().hide()
// self.closest('.participant').removeClass('undetermined')
// self.parent().siblings('.participant-title').text(winner)
// var classes = self.closest('ul').prev().attr('class')
// $('.' + classes.substring(0, classes.indexOf(' ')) + ' .participant-title').each(function() {
// if ($(this).text() === winner) {
// $(this).parent().parent().removeClass('loser').addClass('winner')
// }
// // else {
// // $(this).parent().parent().removeClass('winner').addClass('loser')
// // }
// });
// // $(.previousULClass .
$('#theaterMode').show();
}
});
Template.tournament.helpers({
round: function() {
var tournament = this.tournament.brackets;
var rounds = tournament.length;
var results = [];
tournament.map(function(value, index){
var currentRound = index + 1;
results.push({rounds: rounds, currentRound: currentRound, matches: value});
});
// console.log("results:", results);
return results;
},
match: function(){
// console.log("matches:", this.matches);
return this.matches;
},
participant: function(){
var results = [];
// console.log("this:", this);
this.map(function (value, index) {
// console.log("value, index:", value, index);
var type = value['win'];
var obj = {
id: value['id'],
rank: value['id'].slice(0,3),
displayName: value['displayName'],
thisRound: value['round'],
thisMatch: value['match'],
status: type
};
if (type === true || type === 'undetermined') {
obj.winner = true;
}else{
obj.loser = true;
}
results.push(obj);
});
// console.log("results:", results);
return results;
},
tournamentStartTime: function(){
return Session.get('tournamentStartTime');
}
});
How do you recognize which state is current? You should post some code, routes.js, tournament.js and your view.blade, for better understanding what you really wanna do and for figure out, what the best pratice is. :)

jQuery text() and html() method not working on Chrome

After some calculation I am trying to display the results in a table. I tried using .text() and .html() method but none of them working fine on Chrome (FF is perfectly fine).
1) .html() - Doesn't display anything on Chrome
2) .text() - Returns false string
Here is my JS function.
populateHomeGrid: function(categories, day) {
var eventsForTimer = [];
$.each(categories, function(index, value) {
// categoryId -> {raceNumber : event, ...}
var categoryName = value.name, categoryId = value.categoryId,
mapOfEvents = [], maxNumberOfEvents = 0;
// subcategories
$.each(value.categories, function(index, category) {
var mapOfOneCategory = {}, mapSize = 0;
$.each(category.events, function(index, event) {
var raceNumber = event.raceNumber;
mapOfOneCategory[raceNumber] = event;
mapSize++;
});
if (mapSize > maxNumberOfEvents) maxNumberOfEvents = mapSize;
mapOfEvents.push(mapOfOneCategory);
})
maxNumberOfEvents = maxNumberOfEvents;
// drawing main category
var tableId = "home_grid_" + day + "_" + categoryId,
table = $('<table id="' + tableId + '" cellspacing="0" cellpadding="0" width="100%" class="racing_tables" />')
.appendTo($('#' + day))
var tr = $('<tr class="gray"/>')
.appendTo(table)
.append($('<td valign="middle" width="20%"/>')
.append($('<h2/>').html(categoryName)))
for (var i = 1; i <= maxNumberOfEvents; i ++) {
tr.append($('<td valign="middle" />')
.append($('<p/>').html(i)))
}
// drawing sub categories
$.each(mapOfEvents, function(index, event) {
// Drawing row
var firstRow = true, categoryTr;
for (var i = 1; i <= maxNumberOfEvents; i++) {
if (firstRow) {
categoryTr = $('<tr class="white"/>').appendTo(table)
var categoryHolder = $('<td/>').appendTo(categoryTr),
categoryName = $('<p/>').appendTo(categoryHolder)
firstRow = false;
}
if (typeof event[i] != 'undefined') {
categoryName.html(event[i].categoryName);
var categoryId = event[i].categoryId;
(function(i) {
var a = $('<a/>')
.click(function() {racingNavigation.showLocationAndRaceNumber(categoryId, i)})
.data('event', event[i])
.appendTo($('<td />')
.appendTo(categoryTr))
if (racingNavigation.updateHomeCellInfo(a)) eventsForTimer.push(a);
})(i)
}
else {
categoryTr.append($('<td />'))
}
}
})
});
// Setting the counter to update the closing events
var intervalId = setInterval(function() {
$.each(eventsForTimer, function (index, value) {
if (racingNavigation.updateHomeCellInfo(value) == null) {
window.clearInterval(intervalId);
}
})
}, 5000);
intervalIdsForUpdatingHomeGrid.push(intervalId);
},
Function call to racingNavigation.updateHomeCellInfo
updateHomeCellInfo: function(a) {
var info = '', redClass = false,
event = $(a).data('event');
// Killing the interval
if (typeof event == 'undefined') return null;
var timeUtc = event.timeUtc,
status = event.status,
neededForTimer = false;
if (status == 'expired' || status == 'telephone') info = closed;
else if (date.hourDifference(timeUtc) < 1 && date.minDifference(timeUtc) < 1 && date.secDifference(timeUtc) < 2 && (status == 'live' || status == 'run' )) info = closed;
else if (event.result != null) {
var position = 1;
$.each(event.result.winPlaceResults, function() {
var finishingPosition = this.finishingPosition,
selectionNumber = this.selectionNumber;
if (parseInt(finishingPosition) == position) {
info += selectionNumber.toString();
position++;
}
if (position != 4) info += ', ';
if (position == 4) return false;
})
}
else {
neededForTimer = true;
if (date.hourDifference(timeUtc) > 0) {
info = date.formatTime(new Date(timeUtc));
}
else {
info = date.minDifference(timeUtc);
if (info <= 5) redClass = true;
info = date.minDifference(timeUtc) + ' ' + min;
}
}
if (redClass) $(a).parent().addClass('red')
else $(a).parent().removeClass('red');
$(a).html(info);
return neededForTimer;
},
At the end of my second function I am displaying the result $(a).html(info);
where as info contains different element based on the calculations.Default info is set to CLOSED which is defined in another file as var closed = "CLOSED".
I am expecting the table should display string CLOSED when all the different conditions are invalid. Both .text() and .html() method works fine on FF but not on Chrome as explained in the beginning.

Meteor JS: Use subset of same subscribed data

I built out a custom pagination script to display data for my app. It works wonderfully. However, I am having a slight problem when it comes to trying to figure out how to grab a subset of the same paginated subscription.
Meteor.startup(function(){
Session.setDefault('page', 1);
Session.setDefault('recordCount', 0);
Session.setDefault('recordsPerPage', 10);
Session.setDefault('currentIndustry', null);
Session.setDefault('currentMapArea', null);
Session.setDefault('gmapLoaded', false);
});
Deps.autorun(function () {
Meteor.call('getJobsCount', Session.get('currentIndustry'), Session.get('currentMapArea'), function (err, count) {
Session.set('recordCount', count);
});
Meteor.subscribe('pagedRecords', Session.get('page'), Session.get('recordsPerPage'), Session.get('currentIndustry'), Session.get('currentMapArea'));
});
Template.gmap.rendered = function() {
if(!Session.get('gmapLoaded'))
gmaps.initialize();
}
var templateName = "jobs";
function plotCities(jobs) {
var addresses = _.chain(jobs)
.countBy('address')
.pairs()
.sortBy(function(j) {return -j[1];})
.map(function(j) {return j[0];})
.slice(0, 99)
.value();
gmaps.clearMap();
$.each(_.uniq(addresses), function(k, v){
var addr = v.split(', ');
Meteor.call('getCity', addr[0].toUpperCase(), addr[1], function(error, city){
if(city) {
var opts = {};
opts.lng = city.loc[1];
opts.lat = city.loc[0];
opts.population = city.pop;
opts._id = city._id;
gmaps.addMarker(opts);
}
});
});
}
Template[templateName].helpers({
selected: function(){
return Session.get('recordsPerPage');
}
});
Template[templateName].pages = function() {
var numPages = Math.ceil(Session.get('recordCount') / Session.get('recordsPerPage'));
var currentPage = Session.get('page');
var totalPages = Session.get('recordCount');
var prevPage = Number(currentPage) - 1;
var nextPage = Number(currentPage) + 1;
var html = '<div class="pagination-cont"><ul class="pagination">';
if (numPages !== 1) {
if (currentPage > 1) {
html += '<li>«</li>';
}
for (var i = currentPage; (i <= numPages) && (i - currentPage < 4); i++) {
if (i < 1) continue;
if (i !== currentPage)
html += '<li>' + i + '</li>';
else
html += '<li class="active">' + i + '</li>';
}
if (currentPage < numPages) {
html += '<li>»</li>';
}
}
html += '</ul></div>';
return html;
}
Template[templateName].jobs = function() {
var options = {};
var cursor;
if(!Session.get('currentMapArea')) {
cursor = Jobs.find({}, {limit: 500});
plotCities(cursor.fetch());
}
return Jobs.find({}, { limit: Session.get('recordsPerPage') });
}
Template[templateName].rendered = function(){
var select = $('#perPage');
var option = select.attr('_val');
$('option[value="' + option + '"]').attr("selected", "selected");
select.selectpicker({
style: 'btn-info col-md-4',
menuStyle: 'dropdown-inverse'
});
}
Template[templateName].events({
'click div.select-block ul.dropdown-menu li': function(e){
var selectedIndex = $(e.currentTarget).attr("rel");
var val = $('select#perPage option:eq(' + selectedIndex + ')').attr('value');
var oldVal = Session.get('recordsPerPage');
if(val != oldVal)
Session.set('recordsPerPage', Number(val));
},
'click .pageNum': function(e){
e.preventDefault();
var num = $(e.currentTarget).data('page');
Session.set('page', Number(num));
}
});
Currently, by default, only 10 records per page show up (unless the user selects from a drop-down a different amount). I have a plotCities function that I am using to try to plot the top 100 cities from the subset that is returned, however, I can't grab the top 100 because only 10 at a time show up.
Is there anyway to do what I am describing?
Ok, so the jobsPerCity and jobs are two totally different things, so I would use a separate on-fly-collection for the first one. Nothing will be stored in the database but the client will "think" that there is actually a jobsPerCity collection, which you can use to plot your map. The way you can achieve this is to define another named collection:
// only on the client !!!
var jobsPerCity = new Meteor.Collection("jobsPerCity");
On the server you will need to define a custom publish method:
Meteor.publish('jobsPerCity', function (options) {
var self = this;
var cities = new Meteor.Collection(null);
var jobToCity = {};
handle1 = Jobs.find({/* whatever condition you want */}).observeChanges({
added: function (id, fields) {
jobToCity[id] = fields.address.split(',')[0].toUpper();
cities.upsert({ _id: jobToCity[id] }, { $inc: { jobsCount: 1 } });
},
removed: function (id) {
cities.upsert({ _id: jobToCity[id] }, { $inc: { jobsCount: -1 } });
delete jobToCity[id];
},
changed: function (id, fields) {
// left as an exercise ;)
},
});
handle2 = cities.find({}, {sort: {jobsCount: -1}, limit: 100}).observeChanges({
added: function (id, fields) {
self.added('jobsPerCity', id, fields);
},
changed: function (id, fields) {
self.changed('jobsPerCity', id, fields);
},
removed: function (id) {
self.removed('jobsPerCity', id);
},
});
self.ready();
self.onStop(function () { handle1.stop(); handle2.stop(); });
});
and your good to go :)
EDIT (simple solution for more static data)
If the data is not going to be updated very often (as #dennismonsewicz suggested in one of his comments), the publish method can be implemented in a much simpler way:
Meteor.publish('jobsPerCity', function (options) {
var self = this, jobsPerCity = {};
Jobs.find({/* whatever condition you want */}).forEach(function (job) {
var city = job.address.split(',')[0].toUpper();
jobsPerCity[city] = jobsPerCity[city] !== undefined ? jobsPerCity[city] + 1 : 1;
});
_.each(jobsPerCity, function (jobsCount, city) {
self.added('jobsPerCity', city, { jobsCount: jobsCount });
});
self.ready();
});

Categories