I have created lwc to generatingpdffile.in VScode is ok but in app has bug"Error during LWC component constructor phase:[Timesheet__c is not defined]" - apex

`import getTimesheets from '#salesforce/apex/Generatepdf.getTimesheetsController';
export default class GeneratePdf extends LightningElement {
timesheetList = [];
headers = this.createHeaders(Timesheet__c[
this.EmployeeName__c,
this.ProjectName__c,
this.StartDate__c,
this.Login__c,
this.LogOut__c
]);
renderedCallback() {
Promise.all(values[
loadScript(this, JSPDF)
]);
}
generatePDF(){
const {jsPDF} = window.jspdf;
const doc = new jsPDF({
encryption: {
userPassword: "user",
ownerPassword: "owner",
userPermissions: ["print", "modify", "copy", "annot-forms"]
}
});
doc.text("Employee Timesheet", 20, 20);
doc.table(30, 30, this.timesheetList, this.headers, { autosize:true });
doc.save("timesheet.pdf");
}
generateData(){
getTimesheets().then(result=>{
## `Heading` ## this.timesheetList = result;
this.generatePDF();
});
}
createHeaders(Timesheet__c) {
let result = [];
for (let i = 0; i < Timesheet__c.length; i += 1) {
result.push({
EmployeeName__c,
ProjectName__c,
StartDate__c,
Login__c,
LoginOut__c,
});
}
return result;
}
}"
html
class
public with sharing class Generatepdf {
#AuraEnabled
public static List<Timesheet__c> getTimesheetsController(){return [SELECT EmployeeName__c,ProjectName__c,StartDate__c,Login__c,LogOut__c FROM Timesheet__c LIMIT 1000];
}
}`

Related

Javascript class how to make it, with a constructor?

Also what are these:
`from selenium import webdriver`
\`def hladaj(vyraz):
driver = webdriver.Chrome()
driver.get('https://www.bing.com/')
search_bar = driver.find_element_by_name('q')
search_bar.send_keys(vyraz)
search_bar.submit()
def otvor(n):
result_links = driver.find_elements_by_css_selector('.b_algo a')
result_links\[n-1\].click()
class Laptop {
constructor(vyrobca, model, rocnik) {
this.vyrobca = vyrobca;
this.model = model;
this.rocnik = rocnik;
}
vypis() {
return `${this.vyrobca},${this.model},${this.rocnik}`;
}
}\`
`<script> // Ziskanie tlacidla var button = document.getElementById("remove"); // Pridanie event listenera na stlacenie tlacidla button.addEventListener("click", function() { // Ziskanie vsetkych elementov s triedou "col" var elements = document.getElementsByClassName("col"); // Prechod cez vsetky elementy for (var i = 0; i < elements.length; i++) { // Zistenie textu v elemente var text = elements[i].textContent; // Ak element obsahuje retazec "Row" if (text.includes("Row")) { // Zmazanie elementu elements[i].parentNode.removeChild(elements[i]); } } }); </script>`
`function o2a(obj){ let final= []; final = Object.keys(objs).map(key=> { let arr = []; arr.push(key); arr.push(obj[key]); return arr; }) return final; }`
`function a2o(arr){ let obj = {} arr.forEach(item=> { obj[item[0]] = item[1]; }); return obj; `
\`import React, { useState } from "react";
function Inp() {
const \[value, setValue\] = useState("");
return (
\<input
value={value}
onChange={(e) =\> setValue(e.target.value)}
placeholder="Input value"
/\>
);
}
function But() {
const \[clicked, setClicked\] = useState(false);
return (
\<button onClick={() =\> setClicked(true)}\>Submit\</button\>
);
}
function Out({ value }) {
return \<div\>{value}\</div\>;
}
function App() {
const \[inputValue, setInputValue\] = useState("");
const handleClick = () =\> {
setInputValue(inputValue);
};
return (
\<div\>
\<Inp /\>
\<But onClick={handleClick} /\>
\<Out value={inputValue} /\>
\</div\>
);
}
export default App;\`
Jazyk javascript bezi defaultne na jednom jadre. Na rozhodnutie toho kedy spusti ktoru funkciu, pouziva event Loop.
Multi-threaded funkcionalitu vieme dosiahnut ponocou builtin API ktore sa nazyva Webliorker. Tento API umoznuje beh paralelnych procesov.
A este tab a browser maju vlastne javascript thready a tak aj prehliadaci je multi thread
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8084 });
let counter = 0;
setInterval(() => {
counter += 2;
}, 2000);
wss.on('connection', (ws) => {
console.log('Connected');
setInterval(() => {
ws.send(counter.toString());
}, 2000);
});
const WebSocket = require('ws');
const ws = new WebSocket('ws://localhost:8084');
ws.on('message', (message) => {
const counter = parseInt(message);
const span = document.createElement('span');
span.textContent = `Aktualny stav pocitadla: ${counter}`;
document.body.appendChild(span);
});
1.prehliada precita kod ako text
2. parsuje to na AST (Abstract Syntax Tree)
3.optimalizuje to
4. vnutorne si ho za behu to kompiluje do bytecode a za behu kontroluje. Pocas kontroly sa engine pozera ze ktore funkcie su ako casto volane, alebo vypoctovo narocne a podla toho ich optimalizuje
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res)=>{
if (req.method !== 'GET') {
res.end({"error": "error"}")
}else{
if (req.url === '/indexFile'){
fs.readFile('./index.html', function (err, html) {
if (err) {
throw err;
res.writeHeader (200, "Content-Type": "text/html"});
res.write(html);
}
res.end();
if(req.url === '/response'){
const data = fetch('http://esh.op/order').then(res => res.data);
res.writeHead (200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(data));
}
}
});
server.listen(8080)
function conv(str){
str = str.replaceAll(',',"");
str = str.replaceAll(';', "");
str = str.replaceAll('.',"");
return str.split('').sort((a,b) => b.localeCompare(a))
}

Updating data doesnt expand the data tree inside material-table

Im trying to build a table with nested tree folder inside.
When trying to add nested data into the datasource data the structure will not updated and will not toggle anymore.
Code below:
https://stackblitz.com/edit/angular-table-tree-example-k2zqmt?file=app%2Ftable-basic-example.ts&file=app%2Ftable-basic-example.html,app%2Ftable-basic-example.ts
Environment
Angular:
Material Table
Material tree system
These are the things that are happening when logNode method is called
The item is getting added but the treeControl.toggle method does not work anymore.
When you are assigning a new dataset to the dataSource all the nodes get reset and the tree closes, so this.treeControl.toggle is trying to toggle a node that does not exist.
You need to find the node to be toggled from the list you get from treeControl.dataNodes
I would suggest having the toggle code in a separate method and adding a node code in a separate method, and a separate button to add the node.
The below code should work for your scenario, also remove this line from your HTML, (click)="treeControl.toggle(data)"
interface ExampleFlatNode {
expandable: boolean;
RoleName: string;
Access: boolean;
level: number;
CatId: number;
}
private transformer = (node: FoodNode, level: number) => {
return {
expandable:
!!node.CategoryPermissions && node.CategoryPermissions.length > 0,
RoleName: node.RoleName,
Access: node.Access,
level: level,
CatId: node.CatId,
};
};
tempNodes = []
constructor() {
this.dataSource.data = TREE_DATA;
}
logNode(clickedNode) {
this.tempNodes = [];
this.treeControl.dataNodes.forEach((node) =>
this.tempNodes.push({
...node,
expanded: this.treeControl.isExpanded(node),
})
);
if (!this.treeControl.isExpanded(clickedNode)) {
const temp = {
Access: true,
RoleName: 'test 1 2',
CatId: 113,
};
const clickedNodeIdx = this.treeControl.dataNodes.findIndex(
(node: any) =>
node.CatId === clickedNode.CatId &&
node.RoleName === clickedNode.RoleName &&
node.level === clickedNode.level
);
const childIdx = 1;
let child;
if (clickedNode.level === 0) {
child =
this.dataSource.data[clickedNodeIdx].CategoryPermissions[childIdx];
} else {
this.dataSource.data.forEach(
(item) => (child = this.findDataSource(item, clickedNode))
);
}
child.CategoryPermissions.push(temp);
this.dataSource.data = this.dataSource.data;
const addedNode = this.treeControl.dataNodes.find(
(node: any) =>
node.CatId === temp.CatId && node.RoleName === temp.RoleName
);
this.expandParent(addedNode);
this.setPreviousState();
} else {
this.treeControl.collapse(clickedNode);
}
}
findDataSource(item, node) {
if (item.RoleName === node.RoleName) {
return item;
} else if (item.CategoryPermissions) {
let matchedItem;
item.CategoryPermissions.forEach((e) => {
const temp = this.findDataSource(e, node);
if (temp) {
matchedItem = temp;
}
});
return matchedItem;
}
}
setPreviousState() {
for (let i = 0, j = 0; i < this.treeControl.dataNodes.length; i++) {
if (
this.tempNodes[j] &&
this.treeControl.dataNodes[i].RoleName === this.tempNodes[j].RoleName &&
this.treeControl.dataNodes[i].CatId === this.tempNodes[j].CatId &&
this.treeControl.dataNodes[i].level === this.tempNodes[j].level
) {
if (this.tempNodes[j].expanded) {
this.treeControl.expand(this.treeControl.dataNodes[i]);
}
j++;
}
}
}
expandParent(node: ExampleFlatNode) {
const { treeControl } = this;
const currentLevel = treeControl.getLevel(node);
const index = treeControl.dataNodes.indexOf(node) - 1;
for (let i = index; i >= 0; i--) {
const currentNode = treeControl.dataNodes[i];
if (currentLevel === 0) {
this.treeControl.expand(currentNode);
return null;
}
if (treeControl.getLevel(currentNode) < currentLevel) {
this.treeControl.expand(currentNode);
this.expandParent(currentNode);
break;
}
}
}

Flutter: How to do this emoji firework animation?

I want to do this emoji fireworks animation in a flutter widget:
https://codepen.io/z3vin/pen/QEqqdY
The code is in TypeScript:
class Firework {
constructor(app) {
this.app = app;
this.rnd = app.rnd;
this.bursts = [];
this.reset();
}
reset() {
this.color = `hsl(${this.rnd.int(360)},90%,50%)`;
this.alive = true;
this.bursting = false;
this.pos = new Vec( this.rnd.int(0,this.app.w), this.app.h+40 );
this.vel = new Vec(0,-this.rnd.real(16.0,this.app.h/40));
this.acc = new Vec(0,0);
this.size = this.rnd.real(0.25,5.0);
this.emoji = this.rnd.pick(this.app.emojis);
}
applyForce(f){
this.vel.add(f);
}
update() {
this.applyForce(this.app.forces.gravity);
this.vel.add(this.acc);
this.pos.add(this.vel);
if(this.vel.y > 1) {
this.bursting = true;
const maxBursts = Math.floor(this.app.w / 4);
const numBursts = this.rnd.chance(5) ? this.rnd.int(100,maxBursts) : this.rnd.int(20,80);
for(let i = 1; i < numBursts; i++){
this.bursts.push(new Burst(this.pos, this));
}
}
}
draw() {
const ctx = this.app.ctx;
if(!this.bursting) {
this.update();
ctx.save();
ctx.fillStyle = this.color;
ctx.font = `${this.size}em sans-serif`;
ctx.fillText(this.emoji,this.pos.x,this.pos.y);
//ctx.fillRect(this.pos.x, this.pos.y, this.size, this.size);
ctx.restore();
} else {
this.bursts.forEach(burst=>{
if(!burst.alive){
without(this.bursts,burst);
if(this.bursts.length ===0){
this.alive = false;
}
}
burst.draw();
});
}
}
}
class Burst {
constructor(origin,firework){
this.firework = firework;
this.app = firework.app;
this.pos = origin.clone();
this.rnd = firework.rnd;
this.lifespan = this.rnd.int(5,50);
this.vel = new Vec(this.rnd.real(-8.0,8.0),this.rnd.real(-8.0,8.0));
this.acc = new Vec(0,0);
this.color = this.firework.color;
this.size = this.rnd.real(0.5,15.0);
const sparkle = this.rnd.chance(20) ? 2 : 1;
this.sizeStep = this.size/(this.lifespan/sparkle);
this.alive = true;
this.rotate = this.rnd.real(0,Math.PI*2);
}
applyForce(f){
this.vel.add(f);
}
update() {
this.applyForce(this.app.forces.gravity);
this.vel.add(this.acc);
this.pos.add(this.vel);
//this.size -= this.sizeStep;
//this.rotate += 0.1;
}
draw() {
const ctx = this.app.ctx;
this.update();
ctx.save();
ctx.translate(this.pos.x,this.pos.y)
ctx.rotate(this.rotate);
ctx.font = `${this.firework.size/2}em sans-serif`;
ctx.fillText(this.firework.emoji,0,0);
ctx.restore();
this.lifespan--;
if(this.lifespan<=0){
this.alive = false;
}
}
}
class App {
constructor(){
this.ctx = document.getElementById('cnv').getContext('2d');
this.sizeCanvas();
this.initEvents();
this.rnd = new Random();
this.fireworks = [];
this.forces = {
gravity: new Vec(0,0.25)
};
this.emojis = ['😊','🍕','💩','☘','👀','🐟','💥','⚡️','🍉','🍟','⚽️'];
window.requestAnimationFrame((t)=>{this.draw(t)});
log(this);
}
sizeCanvas(){
this.w = this.ctx.canvas.width = window.innerWidth;
this.h = this.ctx.canvas.height = window.innerHeight;
}
clearIt() {
//this.ctx.clearRect(0,0,this.w,this.h);
this.ctx.save();
this.ctx.fillStyle = 'hsla(220,60%,10%,0.12)';
this.ctx.fillRect(0,0,this.w,this.h)
this.ctx.restore();
}
draw(t){
this.clearIt();
window.requestAnimationFrame((t)=>{this.draw(t)});
if(this.rnd.chance(this.w/80)){
this.fireworks.push(new Firework(this));
}
this.fireworks.forEach(f=>{
if(!f.alive){
without(this.fireworks,f);
}
//log(this.fireworks.length)
f.draw();
});
}
initEvents(){
window.onresize = (e)=>{this.sizeCanvas(e)};
}
}
const foo = 'dsdsa';
const log = console.log.bind(console);
const Vec = TinyVector;
document.addEventListener('DOMContentLoaded', function () {
const app = new App();
});
function without (arr, el) {
arr.splice(arr.indexOf(el),1);
}
Can someone guide me to do this kind of UI making in flutter?
I'm desesperate to find the solution but i don't understand how animation works and i found nothing on stack or other website to do this.
Thanks a lot to people who know how to do that.
I already tried the confetti package but it's not my final goal.

Change content on the same page

i'm trying to sort an array dynamically, in other words, I'm using a popover with 2 options to sort and when i click on each options, i sort the array and i navigate to the same page to change the content but i think it is in cache it does nothing. If i navigate to other page and then i go back it changes. I let you same screenshots and the code.
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouteReuseStrategy, RouterModule } from '#angular/router';
import { IonicModule, IonicRouteStrategy } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '#angular/common/http';
import { IonicStorageModule } from '#ionic/storage';
import { TranslateModule } from '#ngx-translate/core';
import { ComponentsModule } from './components/components.module';
import { Globalization } from '#ionic-native/globalization/ngx';
import { NgxDatatableModule } from '#swimlane/ngx-datatable';
#NgModule({
declarations: [AppComponent,],
entryComponents: [],
imports: [
BrowserModule, IonicModule.forRoot(), AppRoutingModule,
HttpClientModule, IonicStorageModule.forRoot(),
TranslateModule.forRoot(), ComponentsModule, NgxDatatableModule,
RouterModule.forRoot(routes, { initialNavigation : false }), //I get here error on routes and i dont know why
],
providers: [
Globalization,
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent,]
})
export class AppModule {}
orders.page.ts
async showPopOver(evento){
const popover = await this.popoverController.create({
component: PopOptionsComponent,
event: evento,
mode: 'ios',
backdropDismiss:false
});
popover.present();
}
pop-options.component.ts
selectedOpt(index: number){ //Onclick on any option
console.log('item: ', index);
this.popoverCtrl.dismiss({
item: index
});
if(index != OrderService.sort){ //check if the selected option is already in use
OrderService.sort = index;
this.router.navigate(['category/orders'], {skipLocationChange: false});
}
}
order.service.ts
async sortArray(opt: number) {
let day = 0;
let month = 0;
let year = 0;
let day_i = 0;
let month_i = 0;
let year_i = 0;
let order: Order;
if (opt == 1) {
for (let i = 0; i < Order.arrayOrders.length; i++) {
year = Number(Order.arrayOrders[i].creation_date.split('/')[2]);
month = Number(Order.arrayOrders[i].creation_date.split('/')[1]);
day = Number(Order.arrayOrders[i].creation_date.split('/')[0]);
for (let j = 0; j < Order.arrayOrders.length; j++) {
year_i = Number(Order.arrayOrders[j].creation_date.split('/')[2]);
if (year > year_i) {
order = Order.arrayOrders[j];
Order.arrayOrders[j] = Order.arrayOrders[i];
Order.arrayOrders[i] = order;
} else if (year == year_i) {
month_i = Number(Order.arrayOrders[j].creation_date.split('/')[1]);
if (month > month_i) {
order = Order.arrayOrders[j];
Order.arrayOrders[j] = Order.arrayOrders[i];
Order.arrayOrders[i] = order;
} else if (month == month_i) {
day_i = Number(Order.arrayOrders[j].creation_date.split('/')[0]);
if (day > day_i) {
order = Order.arrayOrders[j];
Order.arrayOrders[j] = Order.arrayOrders[i];
Order.arrayOrders[i] = order;
}
}
}
}
}
} else {
for (let i = 0; i < Order.arrayOrders.length; i++) {
year = Number(Order.arrayOrders[i].creation_date.split('/')[2]);
month = Number(Order.arrayOrders[i].creation_date.split('/')[1]);
day = Number(Order.arrayOrders[i].creation_date.split('/')[0]);
for (let j = 0; j < Order.arrayOrders.length; j++) {
year_i = Number(Order.arrayOrders[j].creation_date.split('/')[2]);
if (year < year_i) {
order = Order.arrayOrders[j];
Order.arrayOrders[j] = Order.arrayOrders[i];
Order.arrayOrders[i] = order;
} else if (year == year_i) {
month_i = Number(Order.arrayOrders[j].creation_date.split('/')[1]);
if (month < month_i) {
order = Order.arrayOrders[j];
Order.arrayOrders[j] = Order.arrayOrders[i];
Order.arrayOrders[i] = order;
} else if (month == month_i) {
day_i = Number(Order.arrayOrders[j].creation_date.split('/')[0]);
if (day < day_i) {
order = Order.arrayOrders[j];
Order.arrayOrders[j] = Order.arrayOrders[i];
Order.arrayOrders[i] = order;
}
}
}
}
}
}
}
async getCustomerOrders() {
let url = "orders/customer";
let token = "";
let status = 200;
await this.authService.getSessionToken().then(data => token = data);
/**
* Declaracion del header http
*/
let reqHeader = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
});
Order.arrayOrders.splice(0);
/**
* Declaracion params
*/
//Obtenemos la configuracion y la procesamos
await this.http.get(`${APIREST}` + url, { headers: reqHeader, params }).toPromise().then(data => {
let jsonArray: any = data;
for (let i = 0; i < jsonArray.length; i++) {
let statusLabel = "";
if (jsonArray[i].status == 1) {
statusLabel = Language.arrayLanguage[centinelLang].createdOrderStatus;
} else if (jsonArray[i].status == 2) {
statusLabel = Language.arrayLanguage[centinelLang].productionOrderStatus;
} else if (jsonArray[i].status == 3) {
statusLabel = Language.arrayLanguage[centinelLang].shippedOrderStatus;
} else if (jsonArray[i].status == 4) {
statusLabel = Language.arrayLanguage[centinelLang].deliveredOrderStatus;
}
let order = {
order_id: String(jsonArray[i].order_id),
order_amount: Number(jsonArray[i].amount),
creation_date: String(jsonArray[i].creation_date),
status: statusLabel,
order_customer_cod: String(jsonArray[i].customer_cod)
}
Order.arrayOrders.push(order);
}
this.sortArray(OrderService.sort); //here is where i sort the arry
}).catch(err => {
status = err.status;
});
return status;
}
if you call the same url... your component is not reloaded.
You don't show the code regarding the sorting, which method do you use ? What is this OrderService.sort?
skipLocationChange is just about the navigation history..
First add this import:
import { ChangeDetectorRef } from '#angular/core';
Next add in your constructor :
private ref: ChangeDetectorRef
Finally add this in the place of the array structure should change :
this.ref.detectChanges(); // trigger change detection cycle
    
And thats all.

Refresh sticky mobile leaderboard ad slot by changing the content URL in infinite scroll

I want to refresh sticky mobile leaderboard slot when the URL changes in infinite scroll. What do you think is the best way to go? Please let me know if you have any suggestions.
class DFPAds {
constructor() {
this.slots = [];
this.onScroll = throttle(this.loopAds, 300);
this.addEvents();
this.createAdObject = this.createAdObject.bind(this);
this.createSlotForAd = this.createSlotForAd.bind(this);
this.displayAd = this.displayAd.bind(this);
}
static get() {
return DFPAds._instance;
}
static set() {
if (!DFPAds._instance) {
DFPAds._instance = new DFPAds();
return DFPAds._instance;
} else {
throw new Error("DFPAds: instance already initialized");
}
}
addEvents() {
window.addEventListener("scroll", e => this.onScroll());
}
loopAds() {
this.slots.map(slot => this.displayAd(slot));
}
createAdObject(ad) {
let id = ad.id;
let attributes = getDataSet(ad);
let sizes = JSON.parse(attributes.sizes);
let sizeMapping;
if (attributes.sizemapping) {
attributes.sizemapping.length
? (sizeMapping = JSON.parse(attributes.sizemapping))
: (sizeMapping = null);
}
attributes.id = id;
attributes.sizes = sizes;
attributes.sizemapping = sizeMapping;
return attributes;
}
createSlotForAd(adObject) {
let {
id,
adtype,
position,
slotname,
sizes,
sizemapping,
shouldlazyload,
pagenumber,
pageid
} = adObject;
googletag.cmd.push(() => {
let slot = googletag.defineSlot(slotname, sizes, id);
if(position){
slot.setTargeting("position", position);
}
if(pagenumber){
slot.setTargeting("pagenumber", pagenumber);
}
if(pageid){
slot.setTargeting("PageID", pageid)
}
if (sizemapping) {
let mapping = googletag.sizeMapping();
sizemapping.map(size => {
mapping.addSize(size[0], size[1])
});
slot.defineSizeMapping(mapping.build());
}
slot.addService(googletag.pubads());
googletag.display(id);
shouldlazyload
? this.slots.push({ slot: slot, id: id })
: googletag.pubads().refresh([slot]);
console.log("SlotTop", slot)
});
}
displayAd(slot) {
console.log("Slottwo", slot)
let item = document.getElementById(slot.id);
if (item) {
let parent = item.parentElement;
let index = this.slots.indexOf(slot);
let parentDimensions = parent.getBoundingClientRect();
if (
(parentDimensions.top - 300) < window.innerHeight &&
parentDimensions.top + 150 > 0 &&
parent.offsetParent != null
) {
googletag.cmd.push(function() {
googletag.pubads().refresh([slot.slot]);
});
this.slots.splice(index, 1);
}
}
}
setUpAdSlots(context = document) {
let ads = [].slice.call(context.getElementsByClassName("Ad-data"));
if (ads.length) {
ads.map(ad => compose(this.createSlotForAd, this.createAdObject)(ad));
}
}
}
export default DFPAds;
And this is my Infinite Scroll code:
export default class InfiniteScroll {
constructor() {
this._end = document.getElementById('InfiniteScroll-End');
this._container = document.getElementById('InfiniteScroll-Container');
if(!this._end || !this._container)
return;
this._articles = { };
this._triggeredArticles = [];
this._currentArticle = '';
this._apiUrl = '';
this._count = 1;
this._timedOut = false;
this._loading = false;
this._ended = false;
this._viewedParameter = "&alreadyViewedContentIds=";
this._articleSelector = "InfiniteScroll-Article-";
this._articleClass = "Article-Container";
this.setStartData();
this.onScroll = throttle(this.eventScroll, 200);
this.addEvents();
}
addEvents(){
setTimeout(()=>{
window.addEventListener('scroll', (e) => this.onScroll() );
}, 2000);
}
addToStore(article){
this._articles["a" + article.id] = article;
}
addToTriggeredArticles(id){
this._triggeredArticles.push(id);
}
getRequestUrl(){
return this._apiUrl + this._viewedParameter + Object.keys(this._articles).map(key => this._articles[key].id).join();
}
getLastArticle(){
return this._articles[Object.keys(this._articles)[Object.keys(this._articles).length-1]];
}
setStartData() {
let dataset = getDataSet(this._container);
if(dataset.hasOwnProperty('apiurl')){
let article = Article.get();
if(article){
this._apiUrl = dataset.apiurl;
this._currentArticle = "a" + article.id;
this.addToStore(article);
}else{
throw(new Error('Infinite Scroll: Article not initialized.'));
}
}else{
throw(new Error('Infinite Scroll: Start object missing "apiurl" property.'));
}
}
eventScroll() {
if(this.isApproachingNext()){
this.requestNextArticle();
}
if(!this.isMainArticle(this._articles[this._currentArticle].node)){
this.updateCurrentArticle();
}
}
eventRequestSuccess(data){
this._loading = false;
if(data != ''){
if(data.hasOwnProperty('Id') && data.hasOwnProperty('Html') && data.hasOwnProperty('Url')){
this.incrementCount();
let node = document.createElement('div');
node.id = this._articleSelector + data.Id;
node.innerHTML = data.Html;
node.className = this._articleClass;
this._container.appendChild(node);
this.initArticleUpNext({
img: data.Img,
title: data.ArticleTitle,
category: data.Category,
target: node.id
});
this.addToStore(
new Article({
id: data.Id,
node: node,
url: data.Url,
title: data.Title,
count: this._count,
nielsenProps: {
section: data.NeilsenSection,
sega: data.NeilsenSegmentA,
segb: data.NeilsenSegmentB,
segc: data.NeilsenSegmentC
}
})
);
}else{
this._ended = true;
throw(new Error('Infinite Scroll: Response does not have an ID, Url and HTML property'));
}
}else{
this._ended = true;
throw(new Error('Infinite Scroll: No new article was received.'));
}
}
eventRequestError(response){
this._loading = false;
this._ended = true;
throw(new Error("Infinite Scroll: New article request failed."));
}
requestNextArticle(){
if(!this._loading){
this._loading = true;
return API.requestJSON(this.getRequestUrl())
.then(
(response)=>{this.eventRequestSuccess(response)},
(response)=>{this.eventRequestError(response)}
);
}
}
triggerViewEvent(article){
if(article.count > 1 && !this.isAlreadyTriggeredArticle(article.id)){
this.addToTriggeredArticles(article.id);
Tracker.pushView(article.url, article.count);
if(isFeatureEnabled('Nielsen') && Nielsen.get()){
Nielsen.get().eventInfiniteScroll({
id: article.id,
url: article.url,
section: article.nielsenProps.section,
sega: article.nielsenProps.sega,
segb: article.nielsenProps.segb,
segc: article.nielsenProps.segc
});
NielsenV60.trackEvent(article.title);
}
}
}
updateCurrentArticle(){
Object.keys(this._articles).map( key => {
if(this._currentArticle !== key && this.isMainArticle(this._articles[key].node)){
this._currentArticle = key;
this.updateUrl(this._articles[key]);
this.triggerViewEvent(this._articles[key]);
}
});
}
updateUrl(article){
try{
if(history.replaceState){
if(window.location.pathname !== article.url){
history.replaceState('', article.title, article.url);
}
}
}catch(e){}
}
incrementCount(){
this._count = this._count + 1;
}
initArticleUpNext(data){
this.getLastArticle().initUpNext(data);
}
isApproachingNext(){
return window.pageYOffset > this._end.offsetTop - (window.innerHeight * 2) && !this._ended && this._end.offsetTop >= 100;
}
isMainArticle(node){
if(node.getBoundingClientRect){
return (node.getBoundingClientRect().top < 80 && node.getBoundingClientRect().bottom > 70);
}else{
return false;
}
}
isAlreadyTriggeredArticle(id){
return this._triggeredArticles.indexOf(id) > -1;
}
}