I have to create a button that exports a Vaadin-grid as a CSV file.
But if the table has too many entries it starts to do lazy loading / paging and it only exports the loaded entries.
How do i export the entire table in those cases?
I'm pretty new to javascript and all i could find where java solutions that disable lazy loading entirely (which is not optimal since most tables are very big)
here is the exporter class:
export class TableCSVExporter {
constructor(table, content, includeHeaders = true) {
this.table = table;
this.content = Array.from(content.querySelectorAll('vaadin-grid-cell-content'));
this.rows = Array.from(table.querySelectorAll('tr'));
if (!includeHeaders && this.rows[0].querySelectorAll('th').length) {
this.rows.shift();
}
}
convertToCSV() {
const lines = [];
const numCols = this._findLongestRowLength();
console.log(this.content);
let l = 0;
let rows = this.content.length / numCols;
// const row of this.rows
for (let y = 0; y < rows; y++) {
let line = '';
for (let i = 0; i < numCols; i++) {
if (y == 0) {
line += TableCSVExporter.parseHeaderCell(this.content[l]);
} else {
line += TableCSVExporter.parseCell(this.content[l]);
}
l++;
line += (i !== (numCols - 1)) ? ',' : '';
}
lines.push(line);
}
return lines.join('\n');
}
_findLongestRowLength() {
return this.rows.reduce((l, row) => row.childElementCount > l ? row.childElementCount : l, 0);
}
static parseCell(tableCell) {
let parsedValue = tableCell.textContent;
return this.formatCellContent(parsedValue);
}
static parseHeaderCell(tableCell) {
let parsedValue = "";
let input = tableCell.querySelector('vaadin-text-field');
if(input != null) {
parsedValue = input.placeholder;
}
return this.formatCellContent(parsedValue);
}
static formatCellContent(parsedValue) {
// Replace all double quotes with two double quotes
parsedValue = parsedValue.replace(/\n/g, '');
parsedValue = parsedValue.replace(/"/g, `""`);
parsedValue = parsedValue.trim();
// If value contains comma, new-line or double-quote, enclose in double quotes
parsedValue = /[",\n]/.test(parsedValue) ? `"${parsedValue}"` : parsedValue;
return parsedValue;
}
}
and this is the table class:
import {
LitElement, html,
} from 'lit-element';
import { render } from 'lit-html';
import '#vaadin/vaadin-grid/theme/material/vaadin-grid';
import '#vaadin/vaadin-grid/theme/lumo/vaadin-grid';
import '#vaadin/vaadin-grid/vaadin-grid-filter';
import '#vaadin/vaadin-grid/vaadin-grid-sorter';
import './theme/vaadin-grid';
import '#vaadin/vaadin-context-menu/vaadin-context-menu';
import { createGridOutput } from '../../../js/LdGlobal';
import { LdGridStyles } from './styles';
import '../modules/assets/assets-charts/availability/swimlane';
import '#polymer/paper-button/paper-button';
import '#polymer/paper-fab/paper-fab';
import { TableCSVExporter } from './TableCSVExporter';
/**
* Displays a <vaadin-grid> element with given items
* #extends LitElement
*/
class LdGrid extends LitElement {
// --------------------------------------------------------------------------------------
static get properties() {
return {
gridItems: { type: Object, hasChanged: () => true },
gridTitle: { type: String, hasChanged: () => true },
gridColumns: { type: Object, hasChanged: () => true },
multiSort: { type: Boolean, value: false, hasChanged: () => true },
loading: { type: Boolean, value: false, hasChanged: () => true },
userInformation: { type: Object, hasChanged: () => true },
_height: { type: String, hasChanged: () => true },
};
}
// --------------------------------------------------------------------------------------
static get styles() {
return [LdGridStyles];
}
// --------------------------------------------------------------------------------------
constructor() {
super();
this.addEventListener('keyup', () => this.calculateHeight());
}
// --------------------------------------------------------------------------------------
updated(changedProperties) {
if (changedProperties.has('gridColumns')) {
if (changedProperties.get('gridColumns') === this.gridColumns) {
this.calculateHeight();
}
}
}
// --------------------------------------------------------------------------------------
render() {
const gridColumns = [];
this.gridColumns.forEach(item => {
if (!item.hidden) {
let _contextMenuOptions = '';
let _contextMenuPrefix = '';
let _contextMenuField = '';
let _contextMenuSuffix = '';
const _column = {};
let _contextMenuOptionsLength;
let _contextMenuLinksLength;
if (item.icon) {
_column.style = typeof item.icon.style !== 'undefined' ? item.icon.style : '';
_column.src = typeof item.icon.src !== 'undefined' ? item.icon.src : '';
_column.title = typeof item.icon.title !== 'undefined' ? item.icon.title : '';
}
if (item.link) {
_column.link = {};
_column.link.prefix = typeof item.link.prefix !== 'undefined' ? item.link.prefix : '';
_column.link.suffix = typeof item.link.suffix !== 'undefined' ? item.link.suffix : '';
_column.link.field = typeof item.link.field !== 'undefined' ? item.link.field : '';
}
_column.subkey = typeof item.subKey !== 'undefined' ? item.subKey : '';
_column.chart = typeof item.charts !== 'undefined' ? item.charts : '';
_column.assetId = typeof item.assetId !== 'undefined' ? item.assetId : '';
_column.dateRange = typeof item.timestamp !== 'undefined' ? item.timestamp : '';
if (!item.visible_for_user_group) {
item.visible_for_user_group = [this.userInformation.main_group];
}
const _columnWidth = (typeof item.column_width !== 'undefined') ? item.column_width : '100px';
const _disableTitle = typeof item.disable_title !== 'undefined' && item.disable_title;
const _linkPrefix = (typeof _column.link !== 'undefined' && typeof _column.link.prefix !== 'undefined') ? _column.link.prefix : null;
const _linkField = (typeof _column.link !== 'undefined' && typeof _column.link.field !== 'undefined') ? _column.link.field : null;
const _linkSuffix = (typeof _column.link !== 'undefined' && typeof _column.link.suffix !== 'undefined') ? _column.link.suffix : null;
const _iotOnlineTime = (typeof item.iot !== 'undefined' && typeof item.iot.onlineTime !== 'undefined') ? item.iot.onlineTime : null;
const _iotColor = (typeof item.iot !== 'undefined' && typeof item.iot.color !== 'undefined') ? item.iot.color : null;
if (item.contextMenuOptions) {
item.contextMenuOptions.inputOptions.forEach((option, index) => {
_contextMenuOptions += (typeof option !== 'undefined') ? `${option},` : '';
});
item.contextMenuOptions.link.forEach((option, index) => {
_contextMenuPrefix += (typeof option.prefix !== 'undefined') ? `${option.prefix},` : '';
_contextMenuField += (typeof option.field !== 'undefined') ? `${option.field},` : '';
_contextMenuSuffix += (typeof option.suffix !== 'undefined') ? `${option.suffix},` : '';
});
_contextMenuLinksLength = item.contextMenuOptions.link.length;
}
if (item.visible_for_user_group[0].match(this.userInformation.main_group)) {
gridColumns.push(html`
<vaadin-grid-column
path='${item.id}'
subKey='${_column.subkey}'
initialSort='${item.initialSort}'
header='${item.title}'
sort='${item.sort}'
sortPath='${item.sortPath}'
filter='${item.filter}'
iconSrc='${_column.src}'
iconTitle='${_column.title}'
iconStyle='${_column.style}'
linkPrefix='${_linkPrefix}'
linkField='${_linkField}'
linkSuffix='${_linkSuffix}'
iotColor='${_iotColor}'
iotOnlineTime='${_iotOnlineTime}'
chart='${_column.chart}'
assetId='${_column.assetId}'
dateRange='${_column.dateRange}'
contextMenuPrefix='${_contextMenuPrefix}'
contextMenuField='${_contextMenuField}'
contextMenuSuffix='${_contextMenuSuffix}'
contextMenuOptionsLength='${_contextMenuOptionsLength}'
contextMenuLinksLength='${_contextMenuLinksLength}'
contextMenuOptions='${_contextMenuOptions}'
width='${_columnWidth}'
columnAlign='${item.column_align}'
disableTitle='${_disableTitle}'
.headerRenderer='${this.__searchAndFilterHeaderRenderer}'
.renderer='${this._columnRenderer}'
>
</vaadin-grid-column>`);
}
}
});
return html`
<vaadin-grid visible-rows='1' theme='row-stripes wrap-cell-content no-border' ?loading='${this.loading}' aria-label='${this.gridTitle}' .items='${this.gridItems}' ?multi-sort='${this.multiSort}'>
${gridColumns}
</vaadin-grid>
<paper-fab class='fab-item-left'
#click='${e => this._onDownloadCsvClick(e)}'
icon='add'
title='Export to CSV'></paper-fab>
`;
}
// --------------------------------------------------------------------------------------
__searchAndFilterHeaderRenderer(root, column) {
const _path = column.getAttribute('path');
const _title = column.getAttribute('header');
const _initialSort = column.getAttribute('initialSort');
const _filter = column.getAttribute('filter');
const _sort = column.getAttribute('sort');
const _sortPath = column.getAttribute('sortPath');
const _disableTitle = column.getAttribute('disableTitle');
if (_disableTitle) {
render(html``, root);
}
let _vaadinGridSorter;
let _vaadinGridFilter;
if (_sort !== 'undefined' && _sort) {
if (_initialSort !== 'undefined') {
_vaadinGridSorter = html`
<vaadin-grid-sorter id='sorter_${_path}' path='${_sortPath !== 'undefined' ? _sortPath : _path}'
direction='${_initialSort}'></vaadin-grid-sorter>
`;
} else {
_vaadinGridSorter = html`
<vaadin-grid-sorter path='${_sortPath !== 'undefined' ? _sortPath : _path}'></vaadin-grid-sorter>`;
}
}
if (_filter !== 'undefined' && _filter) {
_vaadinGridFilter = html`
<vaadin-grid-filter path='${_path}'>
<vaadin-text-field
id='filter_${_path}'
slot='filter'
focus-target
theme='small'
placeholder='${_title}'
#value-changed='${e => e.target.parentNode.value = e.detail.value}'>
</
>
</vaadin-grid-filter>`;
} else {
_vaadinGridFilter = html`
<vaadin-grid-column
path='${_path}'
class='header'>${_title}
</vaadin-grid-column>
`;
}
render(html`
${_vaadinGridSorter}
${_vaadinGridFilter}
`, root);
}
// --------------------------------------------------------------------------------------
_columnRenderer(root, column, rowData) {
const _path = column.getAttribute('path');
const _subKey = column.getAttribute('subKey');
const _iconSrc = column.getAttribute('iconSrc');
const _iconTitle = column.getAttribute('iconTitle');
const _linkPrefix = column.getAttribute('linkPrefix');
const _linkField = column.getAttribute('linkField');
const _linkSuffix = column.getAttribute('linkSuffix');
const _chart = column.getAttribute('chart');
const _assetId = column.getAttribute('assetId');
const _dateRange = column.getAttribute('dateRange');
const _iotColor = column.getAttribute('iotColor');
let _contextMenuPrefix = column.getAttribute('contextMenuPrefix');
let _contextMenuField = column.getAttribute('contextMenuField');
let _contextMenuSuffix = column.getAttribute('contextMenuSuffix');
const _contextMenuLinksLength = column.getAttribute('contextMenuLinksLength');
let _contextMenuOptions = column.getAttribute('contextMenuOptions');
const _iotOnlineTime = column.getAttribute('iotOnlineTime');
const _columnAlign = column.getAttribute('columnAlign');
let _link = null;
let _inputOptions = null;
const _vaadinItem = [];
let _output = createGridOutput(_path, rowData);
const _title = createGridOutput(_path, rowData);
if (_subKey !== '') {
_output = html`<b>${_output}</b><br />${rowData.item[_subKey]}`;
}
// TODO: testing against empty string?
if (_linkField !== 'null') {
_link = `${_linkPrefix}${rowData.item[_linkField]}${_linkSuffix}`;
}
let _vaadinGrid;
/**
* Create Icon and/or Link
*/
if (_contextMenuField !== '' && _contextMenuOptions !== '') {
for (let i = 0; i < Number(_contextMenuLinksLength); i++) {
// get the string from Prefix Field / Suffix until ,
_link = `${_contextMenuPrefix.substr(0, _contextMenuPrefix.indexOf(','))}${_contextMenuField.substr(0, _contextMenuField.indexOf(','))}/${rowData.item[_contextMenuSuffix.substr(0, _contextMenuSuffix.indexOf(','))]}`;
// get the string for the label until ,
_inputOptions = _contextMenuOptions.substr(0, _contextMenuOptions.indexOf(','));
// create the vaadin-item
_vaadinItem.push(html`
<vaadin-item theme='custom'>
<a href='${_link}'>${_inputOptions}</a>
</vaadin-item>
`);
// delete the used string
_contextMenuPrefix = _contextMenuPrefix.substr(_contextMenuPrefix.indexOf(',') + 1);
_contextMenuSuffix = _contextMenuSuffix.substr(_contextMenuSuffix.indexOf(',') + 1);
_contextMenuField = _contextMenuField.substr(_contextMenuField.indexOf(',') + 1);
_contextMenuOptions = _contextMenuOptions.substr(_contextMenuOptions.indexOf(',') + 1);
}
_vaadinGrid = html`
<vaadin-context-menu open-on='click'>
<div style='text-align:${_columnAlign}'>
<iron-icon icon='${_iconSrc}' style='cursor: pointer;'></iron-icon>
</div>
<template>
<vaadin-list-box>
${_vaadinItem}
</vaadin-list-box>
</template>
</vaadin-context-menu>
`;
} else if (_path === 'icon' && _link !== null) {
_vaadinGrid = html`
<a title='${_iconTitle}' id='${_title}' class='title' href='${_link}'>
<div style='text-align:${_columnAlign}'>
<iron-icon icon='${_iconSrc}'></iron-icon>
</div>
</a>`;
} else if (_path === 'icon' && _link === null) {
_vaadinGrid = html`
<div title='${_iconTitle}' id='${_title}' style='text-align:${_columnAlign}'>
<iron-icon icon='${_iconSrc}' style='cursor: pointer;'>
</iron-icon>
</div>`;
} else if (_link !== null) {
_vaadinGrid = html`
<a title='${_title}' id='${_title}' href='${_link}'>${_output}</a>`;
} else if (_path === 'iotLabel') {
_vaadinGrid = html`
<span title='${rowData.item[_iotOnlineTime]}' id='${rowData.item[_iotOnlineTime]}'
class='circle ${rowData.item[_iotColor]}'></span>
<span class='suffix'>${_output}</span>`;
} else if (_path === 'trend') {
_vaadinGrid = html`
<span>${_output}</span>`;
} else {
_vaadinGrid = html`
<span title='${_title}' id='${_title}'>${_output}</span>`;
}
/**
* create charts in an grid
*/
if (_chart !== '') {
// dot at machineId is needed in edge. Without machineId is null
_vaadinGrid = html`
<ld-availability-swimlane-chart .machineId='${rowData.item[_assetId]}'
.dateRange='${rowData.item[_dateRange]}'></ld-availability-swimlane-chart>`;
}
render(html`
${_vaadinGrid}
`, root);
}
// --------------------------------------------------------------------------------------
calculateHeight() {
setTimeout(() => {
const vaddinGridTable = this.shadowRoot.querySelector('vaadin-grid');
if (vaddinGridTable !== null) {
this._height = `${vaddinGridTable.shadowRoot.querySelector('#table').clientHeight}px`;
vaddinGridTable.setAttribute('style', `height:${this._height}`);
}
}, 500);
}
_onDownloadCsvClick(e) {
let dataTable = null;
const vaddinGridContent = this.shadowRoot.querySelector('vaadin-grid');
if (vaddinGridContent !== null) {
dataTable = vaddinGridContent.shadowRoot.querySelector('#table');
}
// console.log(dataTable);
const exporter = new TableCSVExporter(dataTable, vaddinGridContent);
const csvOutput = exporter.convertToCSV();
const csvBlob = new Blob([csvOutput], { type: 'text/csv' });
const blobUrl = URL.createObjectURL(csvBlob);
const anchorElement = document.createElement('a');
anchorElement.href = blobUrl;
anchorElement.download = 'table-export.csv';
anchorElement.click();
}
}
customElements.define('ld-grid', LdGrid);
Related
I am trying to read an excel document which has a datetime column.Uploading it to the website,instead of date column i get those numbers which represent the time.I know that using xlsx utils sheet to json we can convert the date cell to the format we want,but i am using a big function to parse this document and the only thing i use from xlsx is xlsx.read . in this function i wrote celldate to true but my web app throws the error that i can not use date object as react child and i dont understand how to convert it as string or at least to read objects property. Could you help me please?
excelToJson utility function which i use:
const XLSX = require("xlsx");
const extend = require("node.extend");
const excelToJson = (function () {
let _config = {};
const getCellRow = (cell) => Number(cell.replace(/[A-z]/gi, ""));
const getCellColumn = (cell) => cell.replace(/[0-9]/g, "").toUpperCase();
const getRangeBegin = (cell) => cell.match(/^[^:]*/)[0];
const getRangeEnd = (cell) => cell.match(/[^:]*$/)[0];
function getSheetCellValue(sheetCell) {
if (!sheetCell) {
return undefined;
}
if (sheetCell.t === "z" && _config.sheetStubs) {
return null;
}
return sheetCell.t === "n" || sheetCell.t === "d"
? sheetCell.v
: (sheetCell.w && sheetCell.w.trim && sheetCell.w.trim()) || sheetCell.w;
}
const parseSheet = (sheetData, workbook) => {
const sheetName =
sheetData.constructor === String ? sheetData : sheetData.name;
const sheet = workbook.Sheets[sheetName];
const columnToKey = sheetData.columnToKey || _config.columnToKey;
const range = sheetData.range || _config.range;
const headerRows =
(sheetData.header && sheetData.header.rows) ||
(_config.header && _config.header.rows);
const headerRowToKeys =
(sheetData.header && sheetData.header.rowToKeys) ||
(_config.header && _config.header.rowToKeys);
let strictRangeColumns;
let strictRangeRows;
if (range) {
strictRangeColumns = {
from: getCellColumn(getRangeBegin(range)),
to: getCellColumn(getRangeEnd(range)),
};
strictRangeRows = {
from: getCellRow(getRangeBegin(range)),
to: getCellRow(getRangeEnd(range)),
};
}
let rows = [];
for (let cell in sheet) {
// !ref is not a data to be retrieved || this cell doesn't have a value
if (
cell === "!ref" ||
(sheet[cell].v === undefined &&
!(_config.sheetStubs && sheet[cell].t === "z"))
) {
continue;
}
const row = getCellRow(cell);
const column = getCellColumn(cell);
// Is a Header row
if (headerRows && row <= headerRows) {
continue;
}
// This column is not _configured to be retrieved
if (columnToKey && !(columnToKey[column] || columnToKey["*"])) {
continue;
}
// This cell is out of the _configured range
if (
strictRangeColumns &&
strictRangeRows &&
(column < strictRangeColumns.from ||
column > strictRangeColumns.to ||
row < strictRangeRows.from ||
row > strictRangeRows.to)
) {
continue;
}
const rowData = (rows[row] = rows[row] || {});
let columnData =
columnToKey && (columnToKey[column] || columnToKey["*"])
? columnToKey[column] || columnToKey["*"]
: headerRowToKeys
? `{{${column}${headerRowToKeys}}}`
: column;
let dataVariables = columnData.match(/{{([^}}]+)}}/g);
if (dataVariables) {
dataVariables.forEach((dataVariable) => {
let dataVariableRef = dataVariable.replace(/[\{\}]*/gi, "");
let variableValue;
switch (dataVariableRef) {
case "columnHeader":
dataVariableRef = headerRows
? `${column}${headerRows}`
: `${column + 1}`;
// break;
default:
variableValue = getSheetCellValue(sheet[dataVariableRef]);
}
columnData = columnData.replace(dataVariable, variableValue);
});
}
if (columnData === "") {
continue;
}
rowData[columnData] = getSheetCellValue(sheet[cell]);
if (sheetData.appendData) {
extend(true, rowData, sheetData.appendData);
}
}
// removing first row i.e. 0th rows because first cell itself starts from A1
rows.shift();
// Cleaning empty if required
if (!_config.includeEmptyLines) {
rows = rows.filter((v) => v !== null && v !== undefined);
}
return rows;
};
const convertExcelToJson = function (config = {}) {
_config = config.constructor === String ? JSON.parse(config) : config;
// ignoring empty lines by default
_config.includeEmptyLines = _config.includeEmptyLines || false;
// source has to be defined and should have a value
if (!(_config.source)) {
throw new Error(":: 'source' required for _config :: ");
}
let workbook = XLSX.read(_config.source, {
type: "array",
});
let sheetsToGet =
_config.sheets && _config.sheets.constructor === Array
? _config.sheets
: Object.keys(workbook.Sheets).slice(
0,
(_config && _config.sheets && _config.sheets.numberOfSheetsToGet) ||
undefined
);
let parsedData = {};
sheetsToGet.forEach((sheet) => {
sheet =
sheet.constructor === String
? {
name: sheet,
}
: sheet;
parsedData[sheet.name] = parseSheet(sheet, workbook);
});
return parsedData;
};
return convertExcelToJson;
})();
export default excelToJson;
That is how i use it:
const convertExcelToObject = (file) => {
const reader = new FileReader();
reader.onload = function (event) {
const data = new Uint8Array(event.target.result);
let result = excelToJson({ source: data });
onUploadExcelFile(result.Transactions);
};
reader.readAsArrayBuffer(file);
};
And this is how i map it:
if (!excelData.length) {
return <div className="noFileContainer">No File Uploaded</div>;
}
const table = excelData;
const tableBody = table?.slice(1);
const tableHead = table[0];
const keys = Object.keys(tableHead);
tableBody.forEach(row => {
data.push({
transactionDate: excelDateToJson(row.A),
transactionAccount: row.B,
Category: row.C,
Item: row.D,
Amount: row.E,
transactionType: row.F,
currency: row.G
});
});
return (
<div className="displayData">
<table>
<thead>
<tr>
{keys.map((key) => (
<th>{tableHead[key]}</th>
))}
</tr>
</thead>
<tbody>
{tableBody.map((row) => (
<tr key={row.id}>
{keys.map((key) => (
<td>{row[key]}</td>
))}
</tr>
))}
</tbody>
</table>
</div>
);
};
The excel document comes from asp.net web api as a base64string. Thanks in advance!
I've implemented BST to compare to others objects types, as Map, {} and Array.
But the weird thing is that insertion in BST takes too long, but search and delete operations in BST is faster than in any other data type.
I'm guessing that is due to many instances of Node, but i don't even sure if that makes sense..
export class BinarySearchTree{
constructor(root = null){
this.root = root;
this.length = 1;
}
search(key){
let cur_node = this.root;
while(true){
if(cur_node === null || cur_node === undefined) return null;
if(cur_node.key === key) return cur_node;
if(key < cur_node.key) cur_node = cur_node.left;
else cur_node = cur_node.right;
}
}
add(key, value = key){
const new_node = new Node(key, value);
let cur_node = this.root;
let parent_node = null;
if(!this.root){
this.root = new_node;
return;
}
while(true){
if(cur_node === null) break;
parent_node = cur_node;
if(parent_node.key === key) return;
if(key < cur_node.key) cur_node = cur_node.left;
else cur_node = cur_node.right;
}
const side = key < parent_node.key ? 'left' : 'right';
parent_node[side] = new_node;
this.length++;
}
delete(key){
let cur_node = this.root;
let parent_node = null;
while(true){
if(cur_node === null || cur_node.key === key) break;
parent_node = cur_node;
if(key < cur_node.key) cur_node = cur_node.left;
else cur_node = cur_node.right;
}
let children = cur_node.getChildren();
const side = parent_node !== null ? parent_node.getChildByKey(key)[0] : 'root';
if(children.length === 0) parent_node[side] = null;
else if(children.length === 1) parent_node[side] = children[0][1];
else if(children.length === 2){
const min_node_map = this.minNode(cur_node.right);
cur_node.key = min_node_map.get('min').key;
cur_node.value = min_node_map.get('min').value;
min_node_map.get('parent').left = null;
}
this.length--;
}
minNode(node = this.root){
let parent_node = null;
let cur_node = node;
while(cur_node.left) {
parent_node = cur_node;
cur_node = cur_node.left;
}
const map = new Map();
map.set('min', cur_node);
map.set('parent', parent_node);
return map;
}
}
export class Node{
constructor(key, value){
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
getChildByKey(key){
return this.getChildren().find(x => x[1].key === key);
}
getChildren(){
const map = new Map();
map.set('left', this.left);
map.set('right', this.right);
return [...map].filter(x => x[1] !== null);
}
}
import { BinarySearchTree } from "./binary-search-tree.js";
const INTERACTIONS = 999999;
//random keys
const random_values = new Array(INTERACTIONS);
for(let i = 0; i < INTERACTIONS; i++)random_values[i] = random(0, INTERACTIONS);
//just to test SEARCH
const SPECIAL_KEY = 1234567;
random_values[Math.floor((random_values.length - 1)/2)] = SPECIAL_KEY;
const item = 'any constant data';
const show = () => {
let arr = [];
console.log('array');
performance('insert', () => {
for(let i = 0; i < INTERACTIONS; i++)
arr.push(random_values[i])
});
performance('search', () => arr.find(x => x === SPECIAL_KEY));
performance('delete', () => arr.splice(arr.indexOf(SPECIAL_KEY), 1));
const obj = {};
console.log(`obj`);
performance('insert', () => {
for(let i = 0; i < INTERACTIONS; i++)
obj[random_values[i]] = item
});
performance('search', () => obj[SPECIAL_KEY]);
performance('delete', () => delete obj[SPECIAL_KEY]);
const map = new Map();
console.log(`map`);
performance('insert', () => {
for(let i = 0; i < INTERACTIONS; i++)
map.set(random_values[i], item)
});
performance('search', () => map.get(SPECIAL_KEY));
performance('delete', () => map.delete(SPECIAL_KEY));
const bst = new BinarySearchTree();
console.log(`binary search tree`);
performance('insert', () => {
for(let i = 0; i < INTERACTIONS; i++)
bst.add(random_values[i], item)
});
performance('search', () => bst.search(SPECIAL_KEY).value);
performance('delete', () => bst.delete(SPECIAL_KEY));
}
show();
function random(min, max){
return Math.floor(Math.random() * (max - min) + min);
}
function performance(title, callback){
const start_time = process.hrtime();
callback();
const end_time = process.hrtime(start_time);
console.log(`${title} ending... ${end_time} seconds`);
}
I am building a JavaScript snippet that I am using to check which CSS classes are NOT in use on a page. Here is the code:
function httpGet(theUrl) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
function getAllClasses() {
//get inline css classes
let headContent = document.getElementsByTagName('head')[0].innerHTML;
let classes = getAllCSSClasses(headContent);
//get external linraties
let csses = document.querySelectorAll('link[rel="stylesheet"]');
for (i = 0; i < csses.length; ++i) {
if (csses[i].href && csses[i].href.indexOf("cookieconsent") == -1){
let styledata = httpGet(csses[i].href);
let cclasses = getAllCSSClasses(styledata);
if ( cclasses instanceof Array )
classes = classes.concat( cclasses );
else
classes.push( cclasses );
//console.log(csses[i].href)
//classes = Object.assign([], classes, cclasses);
//console.log(classes)
//classes.concat(cclasses);
}
}
return classes;
}
function getAllCSSClasses(cssdata) {
var re = /\.[a-zA-Z_][\w-_]*[^\.\s\{#:\,;]/g;
var m;
let classes = [];
do {
m = re.exec(cssdata);
if (m) {
for(let key in m) {
if(
(typeof m[key] == "string") &&
(classes.indexOf(m[key]) == -1) &&
(m[key].indexOf(".") == 0)
)
classes.push(m[key].replace(/\s/g, " "));
}
}
} while (m);
return classes;
}
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x != "" && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (typeof e.className == "string"){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return [];
}
}, []);
return htmlclasses;
}
function getUndefinedClasses(cssclasses, htmlclasses) {
var undefinedclasses = [];
for (let key in htmlclasses) {
if(cssclasses.indexOf("." + htmlclasses[key]) == -1 ) {
undefinedclasses.push(htmlclasses[key]);
}
}
return undefinedclasses;
}
var cssclasses = getAllClasses();
var htmlclasses = getHTMLUsedClasses();
var un = getUndefinedClasses(cssclasses, htmlclasses);
console.log(un )
//copy(un);
Now, the problem is in getHTMLUsedClasses, it doesn't work well.
For example, HTML has an 'img-responsive' class, but the output doesn't show it
var unique = function (list, x) {
if (x != "" && list.indexOf(x) === -1) {
//img-responsive here exists
list.push(x);
}
return list;
};
but:
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (typeof e.className == "string"){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return [];
}
}, []);
//doesn't exists in the final htmlclasses
return htmlclasses;
So I am guessing that [].slice.call(e.classList).reduce(unique, acc) is not working well. I don't quite understand what 'reduce' is doing here (I took this from another example). Can anyone explain?
I think I've found what was the issue. I read that "reduce() does not execute the function for array elements without values." and some classes can come empty so "return [];" will destroy all that is in the array so far. And instead I think that I have to return accumulator like this:
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (e.classList.length > 0){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return acc;
}
}, []);
return htmlclasses;
}
Now the resulting array looks much better, I have in it "img-responsive".
Here is the whole code again:
function httpGet(theUrl) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
function getAllClasses() {
//get inline css classes
let headContent = document.getElementsByTagName('head')[0].innerHTML;
let classes = getAllCSSClasses(headContent);
//get external linraties
let csses = document.querySelectorAll('link[rel="stylesheet"]');
for (i = 0; i < csses.length; ++i) {
if (csses[i].href && csses[i].href.indexOf("cookieconsent") == -1){
let styledata = httpGet(csses[i].href);
let cclasses = getAllCSSClasses(styledata);
if ( cclasses instanceof Array )
classes = classes.concat( cclasses );
else
classes.push( cclasses );
}
}
return classes;
}
function getAllCSSClasses(cssdata) {
var re = /\.[a-zA-Z_][\w-_]*[^\.\s\{#:\,;]/g;
var m;
let classes = [];
do {
m = re.exec(cssdata);
if (m) {
for(let key in m) {
if(
(typeof m[key] == "string") &&
(classes.indexOf(m[key]) == -1) &&
(m[key].indexOf(".") == 0)
)
classes.push(m[key].replace(/\s/g, " "));
}
}
} while (m);
return classes;
}
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (e.classList.length > 0){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return acc;
}
}, []);
return htmlclasses;
}
function getUndefinedClasses(cssclasses, htmlclasses) {
var undefinedclasses = [];
for (let key in htmlclasses) {
if(cssclasses.indexOf("." + htmlclasses[key]) == -1 ) {
undefinedclasses.push(htmlclasses[key]);
}
}
return undefinedclasses;
}
//console.log(cssclasses)
var cssclasses = getAllClasses();
var htmlclasses = getHTMLUsedClasses();
var un = getUndefinedClasses(cssclasses, htmlclasses);
console.log(un )
//copy(un);
I have a filterscript that is displayed as select dropdown. I would transform this to regular clickable text in a ul list. Is it possible to replace the select selector in the script somehow and keep the script intact?
<select id="ram" name="ram" class="select single" onchange="location.href=this.options[this.selectedIndex].value">
<option value="" selected="selected">Select / Reset</option>
<option value="2GB">2 GB</option>
<option value="4GB">4 GB</option>
<option value="8GB">8 GB</option>
</select>
Script:
$(document).ready(function(){
new function(settings) {
var $separator = settings.separator || '&';
var $spaces = settings.spaces === false ? false : true;
var $suffix = settings.suffix === false ? '' : '[]';
var $prefix = settings.prefix === false ? false : true;
var $hash = $prefix ? settings.hash === true ? "#" : "?" : "";
var $numbers = settings.numbers === false ? false : true;
jQuery.query = new function() {
var is = function(o, t) {
return o != undefined && o !== null && (!!t ? o.constructor == t : true);
};
var parse = function(path) {
var m, rx = /\[([^[]*)\]/g, match = /^([^[]+)(\[.*\])?$/.exec(path),base = match[1], tokens = [];
while (m = rx.exec(match[2])) tokens.push(m[1]);
return [base, tokens];
};
var set = function(target, tokens, value) {
var o, token = tokens.shift();
if (typeof target != 'object') target = null;
if (token === "") {
if (!target) target = [];
if (is(target, Array)) {
target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
} else if (is(target, Object)) {
var i = 0;
while (target[i++] != null);
target[--i] = tokens.length == 0 ? value : set(target[i], tokens.slice(0), value);
} else {
target = [];
target.push(tokens.length == 0 ? value : set(null, tokens.slice(0), value));
}
} else if (token && token.match(/^\s*[0-9]+\s*$/)) {
var index = parseInt(token, 10);
if (!target) target = [];
target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
} else if (token) {
var index = token.replace(/^\s*|\s*$/g, "");
if (!target) target = {};
if (is(target, Array)) {
var temp = {};
for (var i = 0; i < target.length; ++i) {
temp[i] = target[i];
}
target = temp;
}
target[index] = tokens.length == 0 ? value : set(target[index], tokens.slice(0), value);
} else {
return value;
}
return target;
};
var queryObject = function(a) {
var self = this;
self.keys = {};
if (a.queryObject) {
jQuery.each(a.get(), function(key, val) {
self.SET(key, val);
});
} else {
self.parseNew.apply(self, arguments);
}
return self;
};
queryObject.prototype = {
queryObject: true,
parseNew: function(){
var self = this;
self.keys = {};
jQuery.each(arguments, function() {
var q = "" + this;
q = q.replace(/^[?#]/,''); // remove any leading ? || #
q = q.replace(/[;&]$/,''); // remove any trailing & || ;
if ($spaces) q = q.replace(/[+]/g,' '); // replace +'s with spaces
jQuery.each(q.split(/[&;]/), function(){
var key = decodeURIComponent(this.split('=')[0] || "");
var val = decodeURIComponent(this.split('=')[1] || "");
if (!key) return;
if ($numbers) {
if (/^[+-]?[0-9]+\.[0-9]*$/.test(val)) // simple float regex
val = parseFloat(val);
else if (/^[+-]?[0-9]+$/.test(val)) // simple int regex
val = parseInt(val, 10);
}
val = (!val && val !== 0) ? true : val;
self.SET(key, val);
});
});
return self;
},
has: function(key, type) {
var value = this.get(key);
return is(value, type);
},
GET: function(key) {
if (!is(key)) return this.keys;
var parsed = parse(key), base = parsed[0], tokens = parsed[1];
var target = this.keys[base];
while (target != null && tokens.length != 0) {
target = target[tokens.shift()];
}
return typeof target == 'number' ? target : target || "";
},
get: function(key) {
var target = this.GET(key);
if (is(target, Object))
return jQuery.extend(true, {}, target);
else if (is(target, Array))
return target.slice(0);
return target;
},
SET: function(key, val) {
var value = !is(val) ? null : val;
var parsed = parse(key), base = parsed[0], tokens = parsed[1];
var target = this.keys[base];
this.keys[base] = set(target, tokens.slice(0), value);
return this;
},
set: function(key, val) {
return this.copy().SET(key, val);
},
REMOVE: function(key) {
return this.SET(key, null).COMPACT();
},
remove: function(key) {
return this.copy().REMOVE(key);
},
EMPTY: function() {
var self = this;
jQuery.each(self.keys, function(key, value) {
delete self.keys[key];
});
return self;
},
load: function(url) {
var hash = url.replace(/^.*?[#](.+?)(?:\?.+)?$/, "$1");
var search = url.replace(/^.*?[?](.+?)(?:#.+)?$/, "$1");
return new queryObject(url.length == search.length ? '' : search, url.length == hash.length ? '' : hash);
},
empty: function() {
return this.copy().EMPTY();
},
copy: function() {
return new queryObject(this);
},
COMPACT: function() {
function build(orig) {
var obj = typeof orig == "object" ? is(orig, Array) ? [] : {} : orig;
if (typeof orig == 'object') {
function add(o, key, value) {
if (is(o, Array))
o.push(value);
else
o[key] = value;
}
jQuery.each(orig, function(key, value) {
if (!is(value)) return true;
add(obj, key, build(value));
});
}
return obj;
}
this.keys = build(this.keys);
return this;
},
compact: function() {
return this.copy().COMPACT();
},
toString: function() {
var i = 0, queryString = [], chunks = [], self = this;
var encode = function(str) {
str = str + "";
if ($spaces) str = str.replace(/ /g, "+");
return encodeURIComponent(str);
};
var addFields = function(arr, key, value) {
if (!is(value) || value === false) return;
var o = [encode(key)];
if (value !== true) {
o.push("=");
o.push(encode(value));
}
arr.push(o.join(""));
};
var build = function(obj, base) {
var newKey = function(key) {
return !base || base == "" ? [key].join("") : [base, "[", key, "]"].join("");
};
jQuery.each(obj, function(key, value) {
if (typeof value == 'object')
build(value, newKey(key));
else
addFields(chunks, newKey(key), value);
});
};
build(this.keys);
if (chunks.length > 0) queryString.push($hash);
queryString.push(chunks.join($separator));
return queryString.join("");
}
};
return new queryObject(location.search, location.hash);
};
}(jQuery.query || {}); // Pass in jQuery.query as settings object
function removeFSS() {
ga("send", "event", "button", "click", "filter-clear");
var t = encodeURI(unescape($.query.set("fss", '')));
var n = window.location.href.split("?")[0]; window.location.href = n + t
}
function getFSS() {
var D = jQuery('.filterGenius input, .filterGenius select').serializeArray();
var O = {};
jQuery.each(D, function(_, kv) {
if (O.hasOwnProperty(kv.name)) {
O[kv.name] = jQuery.makeArray(O[kv.name]);
O[kv.name].push(clean(kv.value, ""));
}
else {
O[kv.name] =kv.value;
}
});
var V = [];
for(var i in O)
if(jQuery.isArray(O[i]))
V.push(O[i].join("+"));
else
V.push(O[i]);
V = jQuery.grep(V,function(n){ return(n) });
return V.join("+");
}
$(document).ready(function () {
$(".filterGenius input").each(function () {
if (window.location.href.indexOf($(this).val()) >= 0) {
$(this).attr("checked", "checked")
}
});
$(".filterGenius select option").each(function () {
if (window.location.href.indexOf($(this).val()) >= 0) {
$(this).attr('selected', true);
}
});
$(".filterGenius input, .filterGenius select").change(function () {
var s = encodeURI(unescape(jQuery.query.set("fss", getFSS())));
var o = window.location.href.split("?")[0];
$(".filterGenius input, .filterGenius select").attr("disabled", true);
window.location.href = o + s
});
});
});
try to this way
$(function() {
$("<ul />").appendTo("nav");
$("nav select option").each(function() {
var el = $(this);
var li = $("<li />", {
"text" : el.text(),
}).appendTo("nav ul");
$(li).html('' + $(li).html() + '');
});
});
https://jsfiddle.net/99sgm51y/3/
This is my first post on StackOverflow and might I say, what a great and helpful resource this is. I have been able to find many answers to my questions and hope to do the same with this one. On to the issue at hand... I am currently using the instafeed.js (http://instafeedjs.com/) script to pull in images from instagram and display them on my site.
What I'm trying to accomplish is to have 9 items display, then if I hit the "next" button, it would replace the current 9 images and load the next 9 images and, if the "previous" button is clicked it would go back and show the previous 9 images.
Currently it only renders one image thumb that scrolls through 9 images then stops. Swapping only the one image at a time. A sample of the current working code with only 1 image displaying can be found here - http://codepen.io/stevenschobert/pen/iHxfw
Here is my JavaScript for the instafeed call:
var count = 1;
var feed;
feed = new Instafeed({
clientId: '68be8b63013048ff81bb4ac8b02b606e',
limit: 9,
resolution: 'standard_resolution',
template: '<img src="{{image}}" /><div class="likes">♥ {{likes}}</div>',
mock: true,
after: function () {
var images = $("#instafeed").find('a');
$.each(images, function(index, image) {
var delay = (index * 75) + 'ms';
$(image).css('-webkit-animation-delay', delay);
$(image).css('-moz-animation-delay', delay);
$(image).css('-ms-animation-delay', delay);
$(image).css('-o-animation-delay', delay);
$(image).css('animation-delay', delay);
$(image).addClass('animated fadeInUp pic-'+count++);
});
},
custom: {
images: [],
currentImage: 0,
showImage: function () {
var result, image;
image = this.options.custom.images[this.options.custom.currentImage];
result = this._makeTemplate(this.options.template, {
model: image,
id: image.id,
link: image.link,
image: image.images[this.options.resolution].url,
caption: this._getObjectProperty(image, 'caption.text'),
likes: image.likes.count,
comments: image.comments.count,
location: this._getObjectProperty(image, 'location.name')
});
$("#instafeed").html(result);
}
},
success: function (data) {
this.options.custom.images = data.data;
this.options.custom.showImage.call(this);
}
});
feed.run();
$(".next").click(function () {
var length, current;
current = feed.options.custom.currentImage;
length = feed.options.custom.images.length;
if (current < length - 1) {
feed.options.custom.currentImage++;
feed.options.custom.showImage.call(feed);
}
});
$(".prev").click(function () {
var length, current;
current = feed.options.custom.currentImage;
length = feed.options.custom.images.length;
if (current > 0) {
feed.options.custom.currentImage--
feed.options.custom.showImage.call(feed);
}
});
My HTML:
<div id="instafeed"></div>
<div class="controls">
<div class="prev"><- prev</div>
<div class="next">next -></div>
</div>
The Instafeed.js code:
(function() { var Instafeed, root; Instafeed = (function() {
function Instafeed(params) {
var option, value;
this.options = {
target: 'instafeed',
get: 'popular',
resolution: 'thumbnail',
sortBy: 'most-recent',
links: true,
limit: 15,
mock: false
};
if (typeof params === 'object') {
for (option in params) {
value = params[option];
this.options[option] = value;
}
}
this.unique = this._genKey();
}
Instafeed.prototype.run = function() {
var header, instanceName, script;
if (typeof this.options.clientId !== 'string') {
if (typeof this.options.accessToken !== 'string') {
throw new Error("Missing clientId or accessToken.");
}
}
if (typeof this.options.accessToken !== 'string') {
if (typeof this.options.clientId !== 'string') {
throw new Error("Missing clientId or accessToken.");
}
}
if ((this.options.before != null) && typeof this.options.before === 'function') {
this.options.before.call(this);
}
if (typeof document !== "undefined" && document !== null) {
script = document.createElement('script');
script.id = 'instafeed-fetcher';
script.src = this._buildUrl();
header = document.getElementsByTagName('head');
header[0].appendChild(script);
instanceName = "instafeedCache" + this.unique;
window[instanceName] = new Instafeed(this.options);
window[instanceName].unique = this.unique;
}
return true;
};
Instafeed.prototype.parse = function(response) {
var anchor, fragment, header, htmlString, image, imageString, images, img, instanceName, reverse, sortSettings, _i, _j, _len, _len1;
if (typeof response !== 'object') {
if ((this.options.error != null) && typeof this.options.error === 'function') {
this.options.error.call(this, 'Invalid JSON data');
return false;
} else {
throw new Error('Invalid JSON response');
}
}
if (response.meta.code !== 200) {
if ((this.options.error != null) && typeof this.options.error === 'function') {
this.options.error.call(this, response.meta.error_message);
return false;
} else {
throw new Error("Error from Instagram: " + response.meta.error_message);
}
}
if (response.data.length === 0) {
if ((this.options.error != null) && typeof this.options.error === 'function') {
this.options.error.call(this, 'No images were returned from Instagram');
return false;
} else {
throw new Error('No images were returned from Instagram');
}
}
if ((this.options.success != null) && typeof this.options.success === 'function') {
this.options.success.call(this, response);
}
if (this.options.sortBy !== 'most-recent') {
if (this.options.sortBy === 'random') {
sortSettings = ['', 'random'];
} else {
sortSettings = this.options.sortBy.split('-');
}
reverse = sortSettings[0] === 'least' ? true : false;
switch (sortSettings[1]) {
case 'random':
response.data.sort(function() {
return 0.5 - Math.random();
});
break;
case 'recent':
response.data = this._sortBy(response.data, 'created_time', reverse);
break;
case 'liked':
response.data = this._sortBy(response.data, 'likes.count', reverse);
break;
case 'commented':
response.data = this._sortBy(response.data, 'comments.count', reverse);
break;
default:
throw new Error("Invalid option for sortBy: '" + this.options.sortBy + "'.");
}
}
if ((typeof document !== "undefined" && document !== null) && this.options.mock === false) {
document.getElementById(this.options.target).innerHTML = '';
images = response.data;
if (images.length > this.options.limit) {
images = images.slice(0, this.options.limit + 1 || 9e9);
}
if ((this.options.template != null) && typeof this.options.template === 'string') {
htmlString = '';
imageString = '';
for (_i = 0, _len = images.length; _i < _len; _i++) {
image = images[_i];
imageString = this._makeTemplate(this.options.template, {
model: image,
id: image.id,
link: image.link,
image: image.images[this.options.resolution].url,
caption: this._getObjectProperty(image, 'caption.text'),
likes: image.likes.count,
comments: image.comments.count,
location: this._getObjectProperty(image, 'location.name')
});
htmlString += imageString;
}
document.getElementById(this.options.target).innerHTML = htmlString;
} else {
fragment = document.createDocumentFragment();
for (_j = 0, _len1 = images.length; _j < _len1; _j++) {
image = images[_j];
img = document.createElement('img');
img.src = image.images[this.options.resolution].url;
if (this.options.links === true) {
anchor = document.createElement('a');
anchor.href = image.images['standard_resolution'].url;
anchor.rel = "lightbox";
anchor.appendChild(img);
fragment.appendChild(anchor);
} else {
fragment.appendChild(img);
}
}
document.getElementById(this.options.target).appendChild(fragment);
}
header = document.getElementsByTagName('head')[0];
header.removeChild(document.getElementById('instafeed-fetcher'));
instanceName = "instafeedCache" + this.unique;
delete window[instanceName];
}
if ((this.options.after != null) && typeof this.options.after === 'function') {
this.options.after.call(this);
}
return true;
};
Instafeed.prototype._buildUrl = function() {
var base, endpoint, final;
base = "https://api.instagram.com/v1";
switch (this.options.get) {
case "popular":
endpoint = "media/popular";
break;
case "tagged":
if (typeof this.options.tagName !== 'string') {
throw new Error("No tag name specified. Use the 'tagName' option.");
}
endpoint = "tags/" + this.options.tagName + "/media/recent";
break;
case "location":
if (typeof this.options.locationId !== 'number') {
throw new Error("No location specified. Use the 'locationId' option.");
}
endpoint = "locations/" + this.options.locationId + "/media/recent";
break;
case "user":
if (typeof this.options.userId !== 'number') {
throw new Error("No user specified. Use the 'userId' option.");
}
if (typeof this.options.accessToken !== 'string') {
throw new Error("No access token. Use the 'accessToken' option.");
}
endpoint = "users/" + this.options.userId + "/media/recent";
break;
default:
throw new Error("Invalid option for get: '" + this.options.get + "'.");
}
final = "" + base + "/" + endpoint;
if (this.options.accessToken != null) {
final += "?access_token=" + this.options.accessToken;
} else {
final += "?client_id=" + this.options.clientId;
}
final += "&count=" + this.options.limit;
final += "&callback=instafeedCache" + this.unique + ".parse";
return final;
};
Instafeed.prototype._genKey = function() {
var S4;
S4 = function() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};
return "" + (S4()) + (S4()) + (S4()) + (S4());
};
Instafeed.prototype._makeTemplate = function(template, data) {
var output, pattern, varName, varValue, _ref;
pattern = /(?:\{{2})([\w\[\]\.]+)(?:\}{2})/;
output = template;
while (pattern.test(output)) {
varName = output.match(pattern)[1];
varValue = (_ref = this._getObjectProperty(data, varName)) != null ? _ref : '';
output = output.replace(pattern, "" + varValue);
}
return output;
};
Instafeed.prototype._getObjectProperty = function(object, property) {
var piece, pieces;
property = property.replace(/\[(\w+)\]/g, '.$1');
pieces = property.split('.');
while (pieces.length) {
piece = pieces.shift();
if ((object != null) && piece in object) {
object = object[piece];
} else {
return null;
}
}
return object;
};
Instafeed.prototype._sortBy = function(data, property, reverse) {
var sorter;
sorter = function(a, b) {
var valueA, valueB;
valueA = this._getObjectProperty(a, property);
valueB = this._getObjectProperty(b, property);
if (reverse) {
if (valueA > valueB) {
return 1;
} else {
return -1;
}
}
if (valueA < valueB) {
return 1;
} else {
return -1;
}
};
data.sort(sorter.bind(this));
return data;
};
return Instafeed;})(); root = typeof exports !== "undefined" && exports !== null ? exports : window; root.Instafeed = Instafeed;}).call(this);
Any help with this issue would be GREATLY appreciated.
Thank You,
Jason