Ответы пользователя по тегу JavaScript
  • Как получить содержимое параграфа в родители с contenteditable=true?

    BRAGA96
    @BRAGA96
    Никогда не работал с contenteditable блоками, может и есть способ получше, но я предложил бы парсинг html из строки (содержимого блока)

    Тестовый html, который был в блоке:
    <p data-test="512">WDaW</p>

    jQuery
    function parseHTML(text, callback) {
    	var $html = $($.parseHTML('<div>'+ text +'</div>'));
    	if (callback) callback($html);
    	return $html.children().unwrap();
    }
    
    parseHTML($('#contenteditable').text(), function($html) {
    	var $p = $('p', $html);
    	console.log({
    		p: $p.text(),
    		data: $p.data('test'),
    		html: $html.html()
    	});
    });


    Pure JavaScript
    function parseHTML(text, callback) {
    	var html = function() {
    		var template = document.implementation.createHTMLDocument();
    		template.body.innerHTML = text;
    		return template.body.children;
    	}();
    	if (callback) callback(html[0]);
    	return html;
    }
    
    parseHTML(document.getElementById('contenteditable').innerText, function(html) {
    	console.log({
    		p: html.innerText,
    		data: html.getAttribute('data-test'),
    		html: html.outerHTML
    	});
    });
    Ответ написан
  • Как правильно пройтись по списку элементов и задать каждому ширину в зависимости от содержания?

    BRAGA96
    @BRAGA96
    Функция трансформирования:
    function transform(value, in_min, in_max, out_min, out_max) {
    	return (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    }


    value - текущее значение
    in_min - минимально возможное значение value
    in_max - максимально возможное значение value
    out_min - минимальное значение, которое хотим получить
    out_max - максимальное значение, которое хотим получить

    Например, максимальная скорость 50 (in_max) и минимальная 0 (in_min). Мы хотим отобразить линию от 0 (out_min) до 100 (out_max), проверять будем значение 25 (value);
    При value 25 мы получим линию со значением 50.
    К этим 50 добавляем потом px или % и добавляем ширину линии.

    Пример: codepen
    var maxSpeed = 50;
    
    $('strong', $('p')).text(maxSpeed);
    
    $.each($('ul li'), function() {
    	var speed = Number($(this).text().replace(/\D/g,''));
    	$(this).append('<div style="width:'+ transform(speed, 0, maxSpeed, 0, 150) +'px"></div>');
    });
    
    function transform(value, in_min, in_max, out_min, out_max) {
      return (value - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
    }
    Ответ написан
    Комментировать
  • Не могу понять как формировать url?

    BRAGA96
    @BRAGA96
    codepen
    $('form').on('submit', function(event) {
      event.preventDefault();
      console.log('https://site.com?' + $(this).serialize());
    });
    Ответ написан
  • Как убрать первый пробел в инпуте, когда условие сработало?

    BRAGA96
    @BRAGA96
    var input = document.getElementById('in');
    input.addEventListener('keydown', function(event) {
    	if (event.keyCode === 32) {
    		this.value = this.value.trim();
    	}
    }, false);
    
    if (!String.prototype.trim) String.prototype.trim = function() {
    	return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
    };
    Ответ написан
    Комментировать
  • Как обработать динамические данные с помощью jquery?

    BRAGA96
    @BRAGA96
    $('.elem', $('.content')).on('click', function() {
    	// ...
    });
    Ответ написан
    Комментировать
  • Как сделать такой счётчик на js?

    BRAGA96
    @BRAGA96
    Достал из своего старого плагина функцию фейковой рандомизации с сидированием. Если интересно погуглите random seeding.
    /**
     * Рандомизация с сидированием
     * @param {number} seed - сид значение
     * @return {number/boolean} - случайное значение из переданного сид значения
    **/
    function Random(seed) {
    	this.number = function(min, max, fixed) {
    		if (!fixed) fixed = 'floor';
    		max = max || 1;
    		min = min || 0;
    		seed = (seed * 9301 + 49297) % 233280;
    		var rnd = seed / 233280;
    		switch(fixed.toLowerCase()) {
    			case 'floor': {
    				return Math.floor(min + rnd * (max - min));
    			}
    			case 'float': {
    				return min + rnd * (max - min);
    			}
    		}
    	},
    	this.boolean = function(rate) {
    		if (!rate) rate = 50;
    		seed++;
    		return Math.sin(seed) <= rate / 100;
    	}
    }


    Как использовать
    var rand = new Random(62086296325); //> seed
    rand.number(1, 5, 'floor'); //> 2 (у всех пользователей)
    Ответ написан
    2 комментария
  • Как при второй инициализации плагина передать только параметры?

    BRAGA96
    @BRAGA96
    Это называется метод. Создайте метод set передайте в него селектор и параметры. В методе сложите переданные параметры и те что были и переинциализируйте плагин, то есть запустите init с новыми параметрами.
    Вот вам шаблон-пример:
    (function($, window, undefined) {
    	'use strict';
    
    	var plugin = {
    		name: 'plugin',
    		data: {
    			setting: 'setting'
    		}
    	}, defaults = {
    		color: 'red',
    		background: 'black'
    	};
    
    	var methods = {
    		init: function($this, setting, type) {
    			var setting = function() {
    				var params = $.extend({}, defaults, setting);
    				$this.data(plugin.data.setting, params);
    				return params;
    			}();
    			/* START */
    			$this.css({
    				color: setting.color,
    				background: setting.background
    			});
    			/* END */
    		},
    		set: function(key, value) {
    			var setting = $(this).data(plugin.data.setting);
    			switch (typeof key) {
    				case 'string':
    					setting[key] = value;
    					break;
    				case 'object':
    					setting = $.extend(true, {}, setting, key);
    					break;
    			}
    			methods.init($(this), setting, 'update');
    		},
    		get: function(key) {
    			var setting = $(this).data(plugin.data.setting);
    			if (key) {
    				return Object.getOwnPropertyDescriptor(setting, key).value;
    			} else {
    				return setting;
    			}
    		},
    		destroy: function() {
    			$(this).removeData(plugin.data.setting).fadeOut(200, function() {
    				$(this).empty().show();
    			});
    		}
    	};
    
    	$.fn[plugin.name] = function(setting, key, value) {
    		if (typeof setting === 'object' || !setting) {
    			return $.each(this, function() {
    				methods.init($(this), setting, 'init');
    			});
    		} else if (typeof setting === 'string') {
    			switch(setting.toLowerCase()) {
    				case 'set':
    					return methods.set.call(this, key, value);
    				case 'get':
    					return methods.get.call(this, key);
    				case 'destroy':
    					return methods.destroy.call(this);
    			}
    		}
    	};
    
    })(jQuery, window);


    Использование:
    // Инициализация с параметрами по умолчанию
    $('.block').plugin();
    // или своими параметрами
    $('.block').plugin({
    	color: 'green',
    	background: 'white'
    });
    
    // Метод SET, изменить параметры и переинциализировать плагин
    $('.block').plugin('set', 'color', 'red');
    // или передать объект новых параметров
    $('.block').plugin('set', {
    	color: 'yellow',
    	background: 'black'
    });
    
    // Метод GET, получить параметры плагина
    $('.block').plugin('get', 'color');
    // или получить все параметры
    $('.block').plugin('get');
    
    // Метод DESTROY, отвязать плагин
    $('.block').destory();
    Ответ написан
    8 комментариев
  • Аналог $.getScript() для локальной разработки?

    BRAGA96
    @BRAGA96
    Запуститесь на любом локальном сервере: gulp(browser-sync), danwer, OpenServer, node serve и т.д
    Ответ написан
  • Как в jquery плагине создать событие?

    BRAGA96
    @BRAGA96
    Так пробовали?
    init: function() {
    	this.element.on('click', this.options.show);
    }
    Ответ написан
  • Как сделать связный запрос через fetch и связать заказы с пользователями?

    BRAGA96
    @BRAGA96
    async/await, promise, promise.all
    Пример на codepen.io
    В этом примере сначала идет запрос на один endpoint, в ответе получаем данные и ссылки на которые нужно кидать следующие запросы.
    Ответ написан
    Комментировать
  • Кто может оценить качество jQuery плагина?

    BRAGA96
    @BRAGA96
    Я написал около 5-ти плагинов и вывел для себе такой шаблон. Если есть не понятные моменты, спрашивай, прокомментирую.
    (function($, window, undefined) {
    	'use strict';
    
    	var plugin = {
    		name: 'plugin',
    		data: {
    			setting: 'setting'
    		}
    	}, defaults = {
    		color: 'red',
    		background: 'black'
    	};
    
    	var methods = {
    		init: function($this, setting, type) {
    			var setting = function() {
    				var params = $.extend({}, defaults, setting);
    				$this.data(plugin.data.setting, params);
    				return params;
    			}();
    			/* START */
    			$this.css({
    				color: setting.color,
    				background: setting.background
    			});
    			/* END */
    		},
    		set: function(key, value) {
    			var setting = $(this).data(plugin.data.setting);
    			switch (typeof key) {
    				case 'string':
    					setting[key] = value;
    					break;
    				case 'object':
    					setting = $.extend(true, {}, setting, key);
    					break;
    			}
    			methods.init($(this), setting, 'update');
    		},
    		get: function(key) {
    			var setting = $(this).data(plugin.data.setting);
    			if (key) {
    				return Object.getOwnPropertyDescriptor(setting, key).value;
    			} else {
    				return setting;
    			}
    		},
    		destroy: function() {
    			$(this).removeData(plugin.data.setting).fadeOut(200, function() {
    				$(this).empty().show();
    			});
    		}
    	};
    
    	$.fn[plugin.name] = function(setting, key, value) {
    		if (typeof setting === 'object' || !setting) {
    			return $.each(this, function() {
    				methods.init($(this), setting, 'init');
    			});
    		} else if (typeof setting === 'string') {
    			switch(setting.toLowerCase()) {
    				case 'set':
    					return methods.set.call(this, key, value);
    				case 'get':
    					return methods.get.call(this, key);
    				case 'destroy':
    					return methods.destroy.call(this);
    			}
    		}
    	};
    
    })(jQuery, window);


    Использование:
    // Инициализация с параметрами по умолчанию
    $('.block').plugin();
    // или своими параметрами
    $('.block').plugin({
    	color: 'green',
    	background: 'white'
    });
    
    // Метод SET, изменить параметры и переинциализировать плагин
    $('.block').plugin('set', 'color', 'red');
    // или передать объект новых параметров
    $('.block').plugin('set', {
    	color: 'yellow',
    	background: 'black'
    });
    
    // Метод GET, получить параметры плагина
    $('.block').plugin('get', 'color');
    // или получить все параметры
    $('.block').plugin('get');
    
    // Метод DESTROY, отвязать плагин
    $('.block').destory();
    Ответ написан
  • Как получить объект из разметки, полученной get запросом (JQuery)?

    BRAGA96
    @BRAGA96
    $.get('https://translate.yandex.ru/', {lang: 'en-ru', text: 'Hello'}, function(html) {
    	var $html = $($.parseHTML(html));
    	var translation = $('#translation', $html).text();
    	$('#translation').text(translation);
    }, 'html');
    Ответ написан
    Комментировать
  • Как при использовании select2 скопировать блок?

    BRAGA96
    @BRAGA96
    $(function() {
    	$('.video-item').clone().appendTo('.video-list');
    	$('.video-list select').select2({
    		width: '100%',
    		language: 'ru',
    		placeholder: 'Не указано',
    	});
    });
    Ответ написан
  • Как убрать смещение экрана при отработке скрипта?

    BRAGA96
    @BRAGA96
    event.preventDefault()
    $('#box-toggler').on('click', function (event) {
    	event.preventDefault();
    	$(this).toggleClass('_active');
    	$('#box').slideToggle();
    });
    Ответ написан
    1 комментарий
  • Вывести данные из API?

    BRAGA96
    @BRAGA96
    Попробуйте потренироваться на API попроще, Вам еще рано. Почитайте про async/await, Promise, асинхронность.
    Пример CodePen.io
    (function() {
    	'use strict';
    
    	const Films = new Swapi('films')
    
    	Films.init({
    		category: ['planets', 'characters'],
    		container() {
    			return document.querySelector('.sw-list')
    		},
    		item(data) {
    			return `
    				<div class="sw-item">
    					<div class="sw-item__info">
    						<h3 class="title">${data.title}</h3>
    						<h3 class="episode_id">${data.episode_id}</h3>
    						<div class="director">${data.director}</div>
    						<div class="producer">${data.producer}</div>
    						<div class="release_date">${data.release_date}</div>
    					</div>
    					<br>
    					<div class="opening_crawl">
    						${Films.method('concat', data.characters, (character) => {
    							return `
    								<h4>Character</h4>
    								<div class="name">Name: ${character.name}</div>
    								<div class="birth">Birth: ${character.birth_year}</div>
    								<hr>
    							`
    						})}
    					</div>
    					<div class="planets">
    						${Films.method('concat', data.planets, (planet) => {
    							return `
    								<h4>Planet</h4>
    								<div class="name">Name: ${planet.name}</div>
    								<hr>
    							`
    						})}
    					</div>
    				</div>
    			`
    		}
    	})
    
    	/**
    	  * Инициализация Swapi
    	  * @param {string} endpoint - категория запроса: flims, ...
    	**/
    	function Swapi(endpoint) {
    		this.init = (setting) => {
    			const container = setting.container()
    			makeRequest(`https://swapi.co/api/${endpoint}/`).then(response => {
    				for (const item in response.results) {
    					makeCategoryRequest(response.results[item], setting.category).then(results => {
    						appendCollection(container, parseHtml(setting.item(results)))
    					})
    				}
    			})
    		},
    		this.method = (name, value, callback) => {
    			switch (name.toLowerCase()) {
    				case 'concat':
    					return filterStrings(value, callback)
    			}
    		}
    	}
    
    	/**
    	  * Сделать все запросы на переданные категории
    	  * @param {object} results - объект данных фильма
    	  * @param {array} types - категории, которые нужно загрузить
    	  * @returns {Promise}
    	**/
    	async function makeCategoryRequest(results, types = ['characters']) {
    		const promises = {};
    		for (const type of types) {
    			promises[type] = makeDeepRequest(results[type])
    		}
    		for (const [type, promise] of Object.entries(promises)) {
    			await promise.then(response => {
    				results[type] = response;
    			}).catch(console.error)
    		}
    		return results
    	}
    
    	/**
    	  * Сделать запрос на url
    	  * @param {string} url - ссылка
    	  * @returns {Promise}
    	**/
    	function makeRequest(url) {
    		return new Promise(resolve => {
    			fetch(url, {
    				method: 'GET',
    				mode: 'cors'
    			}).then(response => {
    				return response.json()
    			}).then(resolve).catch(error => {
    				resolve(null)
    			})
    		})
    	}
    
    	/**
    	  * Сделать запросы на переданные url
    	  * @param {array} urls - массив ссылок
    	  * @returns {Promise}
    	**/
    	function makeDeepRequest(urls) {
    		return new Promise(resolve => {
    			const promises = []
    			for (const url of urls) {
    				promises.push(makeRequest(url))
    			}
    			Promise.all(promises).then(resolve)
    		})
    	}
    
    
    	/**
    	  * Вставка HTMLCollection на страницу
    	  * @param {Node} element - Node элемент, куда будет вставлятся коллекция
    	  * @param {HTMLCollection} collection - масив HTMLCollection
    	**/
    	function appendCollection(element, collection) {
    		element.appendChild(collection[0])
    	}
    
    	/**
    	  * Парсинг HTML из строки
    	  * @param {string} string - html строка
    	  * @returns {HTMLCollection} - html коллекция node узлов
    	**/
    	function parseHtml(string) {
    		const template = document.implementation.createHTMLDocument()
    		template.body.innerHTML = string
    		return template.body.children
    	}
    
    	/**
    	  * Фильтрация массва, запись в строку
    	  * @param {array} - массив данных
    	  * @param {function} filter - функция фильтрации
    	  * @returns {string} - строка с отфильтрованными данными из массива
    	**/
    	function filterStrings(array, filter) {
    		let strings = ''
    		if (filter) {
    			for (let i = 0; i < array.length; i++) {
    				strings += filter(array[i], i)
    			}
    		} else {
    			for (let i = 0; i < array.length; i++) {
    				strings += array[i]
    			}
    		}
    		return strings
    	}
    
    	/**
    	  * Фильтр и перебор по массиву
    	  * @param {array} data - массив данных
    	  * @param {function} filter - функция для фильтрации
    	  * @returns {array} - отфильтрованный массив данных
    	**/
    	function filterArray(data, filter) {
    		const array = []
    		for (let i = 0; i < data.length; i++) {
    			array.push(filter(data[i], i))
    		}
    		return array
    	}
    
    })()
    Ответ написан
    Комментировать
  • Каким образом создать плавную анимацию появления блока?

    BRAGA96
    @BRAGA96
    codepen.io
    (function() {
    	'use strict';
    
    	setTimeout(function() {
    		fadeIn(document.querySelector('.swapi'), 1500);
    	}, 1000);
    
    	function fadeIn(el, time) {
    		el.style.opacity = 0;
    		var last = +new Date();
    		var tick = function(time) {
    			el.style.opacity = +el.style.opacity + (new Date() - last) / (time || 300);
    			last = +new Date();
    			if (+el.style.opacity < 1) {
    				(window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
    			}
    		};
    		tick(time);
    	}
    
    })()
    Ответ написан
  • Не выводятся данные из api?

    BRAGA96
    @BRAGA96
    В таких задачах я бы Вам порекомендовал отделить логику и вывод.
    Всего несколько строк на логику и вы получаете чистый шаблон для вывода данных на страницу.
    (function() {
        'use strict';
    
        // Инициализируем объект методов swapi
        const swapi = {
            // Метод инициализации, принимает массив объектов данных из API и объект настроек
            init(response, setting) {
                // Зададим основной контейнер куда будут вставлятся данные
                // Можно явно указать в свойстве container или создать и вернуть в свойстве create()
                const element = setting.container || setting.create()
                // Выводим данные на страницу
                appendCollectionOutput(element, filterArray(response, (data, index) => {
                    return parseHtml(setting.items(data, index))
                }))
            }
        }
    
        // Инициализация запроса к API
        ajax({
            url: 'https://swapi.co/api/films/',
            method: 'GET',
            contentType: 'application/json; charset=UTF-8',
            success(response) {
                // Инициализируем плагин, передаем данные из API и пишем объект настроек
                swapi.init(JSON.parse(response).results, {
                    // Определяем куда будет вставлятся html из функции items(data)
                    container: document.querySelector('.swapi-container'),
                    // Определяем шаблон вывода
                    items(data) {
                        return `
                            <div class="sw-wrap">
                                <div class="sw-list">
                                    <div class="sw-item">
                                        <div class="sw-item__info">
                                            <h3 class="title">${data.title}</h3>
                                            <h3 class="episode_id">${data.episode_id}</h3>
                                            <div class="director">${data.director}</div>
                                            <div class="producer">${data.producer}</div>
                                            <div class="release_date">${data.release_date}</div>
                                        </div>
                                        <div class="opening_crawl">.</div>
                                    </div>
                                </div>
                            </div>
                        `
                    }
                })
            }
        })
    
        /**
          * Вставка HTMLCollection на страницу
          * @param {Node} element - Node элемент, куда будет вставлятся коллекция
          * @param {HTMLCollection} collection - масив HTMLCollection
        **/
        function appendCollectionOutput(element, collection) {
            for (let i = 0; i < collection.length; i++) {
                element.appendChild(collection[i][0])
            }
        }
    
        /**
          * Парсинг HTML из строки
          * @param {string} string - html строка
          * @returns {HTMLCollection} - html коллекция node узлов
        **/
        function parseHtml(string) {
            const template = document.implementation.createHTMLDocument();
            template.body.innerHTML = string;
            return template.body.children;
        }
    
        /**
          * Фильтр и перебор по массиву
          * @param {array} data - массив данных
          * @param {function} filter - функция для фильтрации
          * @returns {array} - отфильтрованный массив данных
        **/
        function filterArray(data, filter) {
            const array = [];
            for (let i = 0; i < data.length; i++) {
                array.push(filter(data[i], i));
            }
            return array;
        }
    
        /**
          * XMLHttpRequest
          * @param {object} params - параметры запроса
          * url (string), method (string), contentType (string), data (any), async (boolean), success (function), error (function)
        **/
        function ajax(params) {
            var request = new XMLHttpRequest();
            request.open(params.method || 'GET', params.url || window.location.href, params.async || true);
            request.setRequestHeader('Content-Type', params.contentType || 'application/x-www-form-urlencoded; charset=UTF-8');
            request.onreadystatechange = function() {
                if (this.readyState === 4) {
                    if (this.status >= 200 && this.status < 400) {
                        if (params.success) params.success(this.response, this.statusText, this.status);
                    } else {
                        if (params.error) params.error(this);
                    }
                }
            };
            request.send(params.data ? JSON.stringify(params.data) : '');
            request = null;
        }
    
    })()


    В объекте инициализации Вы можете указать куда вставлять html из функции items().
    Или указать уже созданный элемент:
    container: document.querySelector('.swapi-container')

    Или создать и вернуть:
    create() {
    	document.body.insertAdjacentHTML('afterBegin', function() {
    		return '<div class="swapi-container"></div>'
    	}())
    	return document.querySelector('.swapi-container')
    }
    Ответ написан
    Комментировать
  • Обфусцировать, сжать, сконкатенировать js, css с помощью gulp?

    BRAGA96
    @BRAGA96
    uglify вполне достаточно для минификации js файла.
    Для конкатенации я использую gulp-js-import для того чтобы более гибко управлять вставкой js файлов, например
    @import './project/js/plugins/jquery.js'
    Так же очень полезный для меня плагин это gulp-file-include. С его помощью можно вставлять файлы и в html и в js. У меня была задача задать стили через js, с помощью этого плагина я писал стили в sass, gulp-sass генерировал минифицированный css файл и с помощью этого плагина я вставлял css с переменную js, получилось очень удобно.
    var style = '@@include('./modules/airbender/style.css')';
    $('head').append('<style type="text/css">'+ style +'</style>');
    Ответ написан