<div class="news"></div>
(function($) {
'use strict';
/**
* Объект общих параметров
**/
var setting = {
// jQuery selector куда будут выводится новости
$container: $('.news'),
// Объект GET параметров URL для запроса
// https://news.investforum.ru/feed/filter/full/?channels=******&other=******&any=*******
params: {
channels: 'satellits'
},
// Функция определяющая объект методов
// которые используются для формирования новости
store: function() {
return {
// Функция форматирования даты из timestamp к пользовательскому виду по переданному шаблону
// например: store.date('{DD}/{MM}/{YYYY} {hh}:{mm}:{ss}', 1536873967304) >>> 14/09/2018 00:25:35
date: function(template, timestamp) {
// Делаем объект Date из timestamp
// умножаем на 1000 для получения милисекунд
var date = new Date(timestamp * 1000);
// Возвращаем строку форматированную шаблонизатором по переданному шаблону
return tag(template, {
// Объект названий/значений переменной
// Год: {YYYY} -> 2018
YYYY: date.getFullYear(),
// Год: {YY} -> 18
YY: String(date.getFullYear()).slice(2),
// Месяц: {M} -> 9
M: date.getMonth() + 1,
// Месяц: {MM} -> 09
MM: doubleDigits(date.getMonth() + 1),
// День: {D} -> 5
D: date.getDate(),
// День: {DD} -> 05
DD: doubleDigits(date.getDate()),
// Часы: {h} -> 3
h: date.getHours(),
// Часы: {hh} -> 03
hh: doubleDigits(date.getHours()),
// Минуты: {m} -> 8
m: date.getMinutes(),
// Минуты: {mm} -> 08
mm: doubleDigits(date.getMinutes()),
// Секунды: {s} -> 7
s: date.getSeconds(),
// Секунды: {ss} -> 07
ss: doubleDigits(date.getMinutes())
});
},
// Функция перебора объекта/массива для формирования строки
// @params {object|array} data - массив или объект данных для перебора
// @params {function} callback - функция перебора, которая должна возвращать строку
// @returns {string} - строка собранная из значений callback функции
loop: function(data, callback) {
// Создаём переменную куда будут добавлятся строки
var string = '';
// Если данные для перебора - массив
if (Array.isArray(data)) {
// Используем метод перебора массива forEach
data.forEach(function() {
// Записываем в строку значения, которое возвращает callback функция
// Передаём в функцию все аргументы функции forEach: элемент, номер итерации, массив
string += callback.apply(null, arguments);
});
// Если данные для перебора - объект
} else {
// Создадим переменную, чтобы знать количество итераций
var index = 0;
// Пройдемся циклом по объекту
for (var key in data) {
// Запишем в строку знечения, которое возвращает callback функция
// Передадим аргументы в функцию: ключ, значение, номер итерации, объект
string += callback.apply(null, key, data[key], index++, data);
}
}
// Возвращаем созданную строку
return string;
},
// Функция определяющая нужна ли запятая.
// Если последний элемент, то нет, если не последний, то да
// @params {number} total - всего итераций
// @params {number} current - текущая итерация
// @returns {string} - запятая с пробелом или пустая строка
semiclon: function(total, current) {
return total !== current ? ', ' : '';
}
};
},
// Функция возвращающая строку html одной новости
// Шаблон новости. Функция выполняется в цикле
template: function(news, store) {
return `
<article>
<h2>${news.Title}</h2>
<div>
${store.loop(news.Channels, function(channel, index) {
return `<span>${channel.Name} (${channel.ID})</span>${store.semiclon(news.Channels.length, ++index)}`;
})}
</div>
<hr>
<small>
<a href="${news.Link}">${news.Link}</a>
</small>
<hr>
<p>${news.Description}</p>
<hr>
<div>
${store.loop(news.Tags, function(tag, index) {
return `<span>${tag.Name}</span>${store.semiclon(news.Tags.length, ++index)}`;
})}
</div>
<small>${news.Creator} | ${store.date('{DD}/{MM}/{YYYY} {hh}:{mm}:{ss}', news.PublishDate)}</small>
</article>
`;
}
};
/**
* Делаем AJAX запрос
* При успешном запросе формируем html новостей и вставляем в DOM
**/
getNews(setting.params).done(function(response) {
// Формируем jQuery коллекцию элементов из строки шаблона новости
var $html = outputTemplate(response);
// Если коллекция есть, то вставим её в DOM
if ($html && $html.length) setting.$container.append($html);
});
/**
* Шаблонизатор
* Используется для форматирования/редактирования
* и навешывания событий перед вставкой в DOM
* @params {string} html - строка html кода одной новости
* @params {object} data - объект данных новости
* @params {object} store - объект методов store
* @returns {jQuery Collection} - jQuery коллекция DOM элементов
**/
function templateEngine(html, data, store) {
// Делаем из строки html - jQuery коллекцию
var $html = $(html);
// Функция нахождения нужного jQuery селектора
// Передаём контекст $html, эквевалент: $html.find(selector)
var $selector = function(selector) {
return $(selector, $html);
};
// Если переданный селектор есть
if ($selector('p').length) {
// Пройдемся циклом $.each по элементам
$.each($selector('p'), function() {
// Повешаем событие клика
$(this).on('click', function() {
alert($(this).text());
});
});
}
// Возвращаем форматированную jQuery коллекция элементов
return $html;
}
/**
* Сделать число двойным
* Из 4 сделать 04
* @params {number} value - исходное число
* @returns {number|string} - форматированое число или исходное
**/
function doubleDigits(value) {
// Если число меньше 10, то вернём 0*
// если нет то вернем переданное число
return value < 10 ? '0' + value : value;
}
/**
* Шаблонизатор
* На входе принимается строка с шаблонными тегами вида {key}
* и объект значений, которые будут замененны с исходной строкой
* Ключ - название переменной {ключ}, Значение - значение переменной
* @params {string} input - строка с шаблонными тегами
* @params {object<string|number>} data - объект значений.
* @returns {string} - строка с заменёнными тегами
**/
function tag(input, data) {
// Пройдемся циклом по объекту значений
for (var key in data) {
// Изменим переданную строку
// Находим переменную по ключу объекта
// и заменяем переданную строку на значение объекта
input = input.replace(new RegExp('{'+ key +'}', 'gi'), data[key]);
}
// Возвращаем форматированую строку
return input;
}
/**
* Формирование html новостей
* Цикл по массиву данных новостей
* @params {array<object>} - массив объектов данных новостей
* @returns {jQuery Collection} - jQuery коллекция DOM элементов всех новостей
**/
function outputTemplate(data) {
// Создадим массив, куда будем вставлять jQuery коллекцию элементов одной новости
var $collection = [];
// Выполним функцию store, чтобы получить объект методов store
var store = setting.store() || {};
// Пройдемся циклом по массиву объектов данных новостей, полученных с AJAX
for (var item in data) {
// Соеденим текущую jQuery коллекцию с новой, каждую итерацию
// Выполним функцию template, чтобы получить строку html одной новости
// передадим строку html в функцию шаблонизатор для формирования jQuery коллекции из строки
// добавляем в массив коллекции
$.merge($collection, templateEngine(setting.template(data[item], store, Number(item)), data[item], store) || []);
}
// Возвращаем jQuery коллекцию элементов всех новостей
// Именно эти элементы будет вставлять в DOM
return $collection;
}
/**
* Сделать AJAX запрос для получения данных новостей
* @params {object<string>} - объект строк GET параметров URL (https://site.com?get_params...)
* @returns {object<function>} - $.Deferred объект (promise)
**/
function getNews(params) {
// Возвращаем $.Deferred объект AJAX запроса для получения данных новостей
return ajax('https://news.investforum.ru/feed/filter/full/', params);
}
/**
* Функция AJAX запроса
* @params {string} link - ссылка, куда куда будем делать запрос
* @params {object} params - объект GET параметров URL
* @params {object} setup - объект параметров $.ajax функции
* @returns {object<function>} - $.Deferred объект (promise)
**/
function ajax(link, params, setup) {
// Возвращаем $.Deferred объект AJAX запроса
return $.ajax($.extend(true, {}, {
// Параметры запроса по умолчанию
method: 'GET',
dataType: 'json'
// Объеденить параметры по умолчанию
// с переданным объектом параметров setup
}, setup || {}, {
// Формирования URL запроса
url: params ? link + '?' + $.param(params) : link
}));
}
})(jQuery);
This Pen doesn't use any external CSS resources.