Ответы пользователя по тегу JavaScript
  • Как правильно сделать такой один массив с объектами из трёх массивов с объектами (javascript)?

    lazalu68
    @lazalu68
    Salmon
    Если все три массива отсортированы по возрастающей относительно key/id объектов, то итерируете по массиву №1, в каждой итерации добавляете текущему элементу свойство text и присваиваете ему значение равное результату конкатенации значения свойства text соответствующего элемента массива №2, пробела и значения свойства text соответствующего элемента массива №3.
    Ответ написан
    Комментировать
  • Как оптимизировать код jquery?

    lazalu68
    @lazalu68
    Salmon
    Это специфика setInterval/Timeout - гарантируется выполнение не ровно через N секунд, а не раньше чем через N секунд.

    ЗЫ: в JS можно не ставить символ $ в начале имени переменной.
    Ответ написан
    Комментировать
  • Дублируется селектор в Frame. Как исправить?

    lazalu68
    @lazalu68
    Salmon
    1. Не вижу в тексте вопроса ни одного селектора. К тому же ваш кусок кода не может добавлять элемент ко всем body дочерних фреймов текущего документа если он выполнен в контексте этого документа. Такое может произойти только если он выполнен по отдельности в контексте каждого фрейма,
    2. Скорее всего проблема в том что у вас адрес целевых страниц задаётся с помощью wildcard, типа так: *site.com/*, таким образом вы выполняете скрипт не только на исходной странице, но и на дочерних фреймах. Если это так, то решить проблему можно просто не выполняя скрипт для фреймов:

    if (window.top != window.self)  {
        return;
    }
    Ответ написан
    Комментировать
  • Почему ajax не срабатывает?

    lazalu68
    @lazalu68
    Salmon
    Проблема была в том, в обработчике был вызов var_dump, который естественно чуть-чуть портил JSON. А ещё в попытке закодировать в JSON PDOStatement, вместо массива который можно было получить с помощью fetch/fetchAll.
    Ответ написан
    Комментировать
  • Как задать/изменить data-attribute?

    lazalu68
    @lazalu68
    Salmon
    Вы с помощью .data() изменяете не атрибуты, а значения в скрытом объекте.

    Пользуйтесь .attr()
    Ответ написан
    1 комментарий
  • Как убрать белый фон при помощи Greasemonkey и js?

    lazalu68
    @lazalu68
    Salmon
    Если нужно убрать фон для всех элементов у которых фон белый или близок к белому, то вполне можно проверять все элементы на предмет цвета, а потом раздавать им ваш цвет.

    Можно например так:
    1. Собрать все нужные элементы. Т.к. белые цвета фона используются чаще для контейнеров, то и собирать можно только соответствующие, типа div, main, footer, header и т.д.
    2. Рассортировать элементы по цветам,
    3. Отсеять группы элементов, не соответствующие по цвету. Цвет не соответствует критериям, при которых он считается белым, если 1) его недостаточно хорошо видно - высокий уровень прозрачности и 2) сумма цветовых компонентов недостаточно высока, цвет достаточно далёк от оттенка который можно было бы назвать белым,

    Пример кода
    // white_like_thresold - minimal accepted value of color/white rate, colors that has higher rate is treated as white
    // min_transparency - minimal accepted transparency (alpha), colors that has lesser transparency is treated as transparent
    
    (function() {
    	const rgb_max_intens_sum = 255 + 255 + 255;
    
    	RegExp.integers = /\d+(\.\d+)?/g;
    
    	var accepted_tags = ['article','aside','footer','header','hgroup','nav','section','div','main','pre','table','form'],
    		white_like_thresold = 0.9, 
    		min_transparency = 0.3,
    		bg_color = '#fafbfc',
    		$$result_collection = [];
    
    	collectElements();
    	setColor();
    
    	function collectElements() {
    		var background_color_key = 'background-color',
    			rgba,
    			color,
    			collections = {},
    			$$all = document.querySelectorAll(accepted_tags.join(','))
    
    		for (var l = $$all.length, i = 0; i < l; i++) {
    			color = getComputedStyle($$all[i])[ background_color_key ];
    			if (!(color in collections)) {
    				collections[ color ] = [];
    			}
    			collections[ color ].push( $$all[i] );
    		}
    
    		for (color in collections) {
    			rgba = color.match( RegExp.integers ).map(Number);
    			if ((rgba.length === 4 && rgba[3] < min_transparency) || (rgba[0]+rgba[1]+rgba[2])/rgb_max_intens_sum <= white_like_thresold) {
    				continue;
    			} else {
    				$$result_collection = $$result_collection.concat( collections[color] );
    			}
    		}
    	}
    	function setColor() {
    		var i = $$result_collection.length,
    			$el;
    
    		while (i--) {
    			$el = $$result_collection[i];
    			if (!$el._old_style) {
    				$el._old_style = {
    					backgroundColor: $el.style.backgroundColor
    				};
    			}
    		    $el.style.backgroundColor = bg_color;
    		}
    	}
    })();


    Если кажется, что алгоритм оперирует со слишком большим количеством элементов, то достаточно сказать, что если брать в качестве примера эту страницу, то в результате выполнения было найдено 287 элементов из которых было сформировано 7 цветовых групп, из которых в свою очередь критерию соответствовали только 24.
    Ответ написан
    Комментировать
  • Как понять метод navigator.userAgent у js?

    lazalu68
    @lazalu68
    Salmon
    Вики по теме.

    ЗЫ
    navigator.userAgent это свойство, а не метод.
    Ответ написан
    Комментировать
  • Как запретить одновременный вызов функции?

    lazalu68
    @lazalu68
    Salmon
    Одним из решений может быть любая реализация очереди.
    Ответ написан
    Комментировать
  • Кто может объяснить или дать источник, который объясняет что вот это значит - function(event, ui)?

    lazalu68
    @lazalu68
    Salmon
    function(event, ui) {}

    Эта запись означает, что при вызове функции внутри функции первый переданный ей аргумент будет доступен по идентификатору event, а второй - по идентификатору ui. Event это объект события, а в случае с jQuery UI ui это объект который передаёт вам jQuery UI, его содержимое зависит от контекста.

    Вы никогда не поймёте что происходит если будете игнорировать ссылки на образовательные материалы, которые вам в каждом вашем вопросе присылают до чёрта. Попробуйте хоть один учебник до конца прочитать. Думаю, тогда вам всё станет понятно.
    Ответ написан
    Комментировать
  • Объясните как работает данный код?

    lazalu68
    @lazalu68
    Salmon
    // Объявление переменной, которая будет доступна для функции highlight
    var selectedButton;
    
    function highlight(node) {
        // Если существует активная кнопка
        if (selectedButton){
            // то снять с неё класс highlight
            selectedButton.classList.remove('highlight');
        }
        // Теперь выбранной кнопкой считается переданный элемент
        selectedButton = node;
        // Поэтому вешаем на него класс highlight
        selectedButton.classList.add('highlight');
    }
    Ответ написан
    6 комментариев
  • Как вывести улицу и дом пользователя через javascript geolocation api?

    lazalu68
    @lazalu68
    Salmon
    Ну, как бы без карт можно, но вам всё равно придётся пользоваться геокодером либо Яндекса, либо гугла. Как именно - подробно описано у них на сайте.
    Ответ написан
    Комментировать
  • Kак заблокировать сообщения в консоле разработчика?

    lazalu68
    @lazalu68
    Salmon
    Ну, можно просто переопределить console.log:

    console.log = function() {
        // no action
    }


    Коричневая чума

    Консоль, она чья, она моя. Дательный падеж - как заблокировать сообщения в консоли.

    Ответ написан
  • Как вызвать функцию после полной загрузки асинхронного скрипта?

    lazalu68
    @lazalu68
    Salmon
    Стоило заглянуть в документацию, это второй пункт в соответствующем разделе.

    При инициализации счетчика выбираете опцию triggerEvent:

    var yaCounterXXXXXX = new Ya.Metrika({
        id: XXXXXX,
        triggerEvent: true
    });


    После этого в коде можете вешать обработчик, который будет вызван когда счетчик инициализируется:

    document.addEventListener('yacounterXXXXXinited', function () {
        console.log('the yaCounterXXXXX counter can be used');
    });
    Ответ написан
    5 комментариев
  • Разное поведение браузеров при загрузке файлов через XMLHttpRequest. Как избежать моментальной псевдо 100% загрузки файла?

    lazalu68
    @lazalu68
    Salmon
    Илья Кантор советует использовать xhr.upload для этого:

    xhr.upload.onprogress = function(event) {
      alert( 'Загружено на сервер ' + event.loaded + ' байт из ' + event.total );
    }
    
    xhr.upload.onload = function() {
      alert( 'Данные полностью загружены на сервер!' );
    }
    
    xhr.upload.onerror = function() {
      alert( 'Произошла ошибка при загрузке данных на сервер!' );
    }


    А если вы пользуетесь xhr.onprogress, то вы банально не в ту сторону смотрите, xhr.onprogress следит за скачиванием.
    Ответ написан
    Комментировать
  • Почему cookies сохраняются в такой форме?

    lazalu68
    @lazalu68
    Salmon
    Если вы вручную устанавливаете element.dataset.lang, то как раз в нем и ошибка. Вероятно, вы изначально записываете такое вот дикое значение в data-lang вашего элемента.

    Если речь о языке, то можно его брать из html, то есть document.documentElement.lang, как-то так:

    var l = document.documentElement.lang,
        expires = "",
        date = new Date();
    
    date.setTime(date.getTime() + (360*24*60*60*1000));
    expires = "; expires=" + date.toUTCString();
    document.cookie = 'language' + "=" + l + expires + "; path=/";
    
    // "language=ru; expires=Sat, 18 Aug 2018 20:30:14 GMT; path=/"
    Ответ написан
    3 комментария
  • Как эта страница работает?

    lazalu68
    @lazalu68
    Salmon
    Не-не-не, вы неправильно поняли принцип работы UpUp, суть в другом. Предположим, хотим чтобы страница "example.com" была доступна в оффлайне. Вдобавок, хотим чтобы пользователь из оффлайна видел содержимое страницы "example.com/offline.html", а не исходной. То есть пользователь при попытке зайти на "example.com" будет видеть содержимое страницы "example.com/offline.html". Для этого нужно в этот же каталог ("/", это важно) положить скрипты UpUp, и тогда при загрузке страницы "example.com" нужно выполнить такой скрипт:

    UpUp.start({
      'content-url': 'offline.html'
    });


    Этот скрипт загрузит в кеш содержимое страницы "example.com/offline.html", то есть выполнит запрос по этому адресу:

    fetch("example.com/offline.html", { mode: 'no-cors' }).then(function(response) {
    	return cache.put('sw-offline-content', response);
    });


    (Можно было бы в вызов UpUp.start() передать например content: 'Hey, seems you are offline!', тогда эта строка была бы контентом доступным из оффлайна по адресу "example.com", но это неинтересно)

    Технически, объект window.caches страницы "example.com" будет содержать запись с ключом 'sw-offline-content', в которой будет храниться содержимое страницы "example.com/offline.html". ServiceWorker слушает событие fetch, при котором он проверяет зафейлился запрос или нет. Если запрос успешный, то возвращает исходный event.request. Если запрос не прошёл, то пытается вернуть закешированную версию страницы, только не ту которую мы сохранили с помощью UpUp, а ту которую браузер сам себе сохранил. Если страница не найдена и в кеше, то тогда наконец UpUp возвращает контент, который мы сохранили с его помощью в кеш: caches.match('sw-offline-content'). Вообще на гите всё расписано подробно:

    event.respondWith(
    	// try to return untouched request from network first
    	fetch(event.request).catch(function() {
    		// if it fails, try to return request from the cache
    		return caches.match(event.request).then(function(response) {
    			if (response) {
    				return response;
    			}
    			// if not found in cache, return default offline content
    			// (only if this is a navigation request. In older browsers we check if this is a text/html request. Thanks @jeffposnick)
    			if (event.request.mode === 'navigate' || (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) {
    				return caches.match('sw-offline-content');
    			}
    		})
    	})
    );


    В целом, их собственное описание принципа работы UpUp мне кажется удовлетворительным:

    How Does It Work?

    UpUp uses service workers to determine when network requests fail. A service worker is a special script that runs in the browser in the background, and can see the status of network requests.

    When the user first visits your site, UpUp registers a service worker with your browser, and gives it a list of files to cache for later.

    The next time the user visits your site, the service worker listens for network errors. If a network request fails, and the service worker finds that file in the cache, it will return that file, as if it came from the network.
    Ответ написан
    Комментировать
  • Как запретить скролл?

    lazalu68
    @lazalu68
    Salmon
    Можно скрыть overflow для body и скроллить только с помощью document.body.scrollTop, получится как раз то что вы просите: пользователь будет в состоянии скроллить документ только с помощью предложенных вами элементов управления, как-то так.
    Ответ написан
  • Cannot read property 'data' of undefined, после Ajax, Rivets.js?

    lazalu68
    @lazalu68
    Salmon
    В общем проблема была в повторной инициализации приложения и попытке установки обработчика для элемента управления приложения сторонними средствами - с помощью jQuery.

    Можно байндить только нужный вам контейнер, это вроде решение с минимальным изменением кода. Просто после добавления элементов в список байндите их:

    $.ajax({
        url: '/demo.php',
        type: 'POST',
        data: data,
        success: function (html) {
            $goods_list.empty().append(html);
            rivets.bind($goods_list, model);
            toTopAfterAjaxUpdatePagination();
        }
    });


    Изменённый код main.js
    var $ = jQuery;
    
    $(function(){
      var $goods_list = $('ul.goods__list'),
          model = {
            data: JSON.parse(localStorage.getItem('g_zakazi')) || {
              title: 'Welcome',
              //juzer_id: $('#juzer-id').text(),
              subtotal: 0,
              zakazi: []
            },
            controller: controller
          };
    
      rivets.bind(document.querySelector('#rivetsSpace'), model);
    
      $('.goods__pagination').on('click', '.goods__page', function(){
    
        console.log('Клик по пагинации');
        var data = { id: $(this).text() };
    
            $.ajax({
                url: '/demo.php',
                type: 'POST',
                data: data,
                success: function (html) {
                    //console.log(data);
                    $goods_list.empty().append(html);
                    rivets.bind($goods_list, model);
                    toTopAfterAjaxUpdatePagination();
                }
            });
      });
    
    });
    
    function returnFalse(){
      console.log('Выходим');
      return false;
    }
    
    var controller = {
    
      onAtbClick: function(e, model) {
           var ID = $(this).data("id");
    
              var goods = model.data.zakazi.filter(function (goods) {
                      return goods.ID === ID;
              })[0];
    
              if (goods) {
                  goods.quantity++;
                  returnFalse();
    
              } else {
    
                model.data.zakazi.push({
                      ID: ID,
                      quantity: 1
    
                    });
              }
    
    		model.controller.updatePrice(model.data);
    		model.controller.saveData(model.data);
    
       },
    
       updatePrice: function(data) {
        var zakazi = data.zakazi,
          product,
          subtotal = 0;
    
        data.subtotal = subtotal;
    
      },
    
       removeGoods: function(e, model) {
    
            e.stopImmediatePropagation();
    
            var index = model.index,
                zakazi = model.data.zakazi;
    
          zakazi.splice(index, 1);
          model.controller.saveData(model.data);
    
        },
    	
       saveData: function(data) {
        localStorage.setItem( 'g_zakazi', JSON.stringify( data ) );
       }
    }
    
    function toTopAfterAjaxUpdatePagination() {
      var scrollGoods = $('section.goods').offset().top;
      $(document).scrollTop(scrollGoods - 50);
    }
    
    
    
    rivets.formatters.length = function(val) {
      return val.length;
    };
    Вариант решения который не подошёл

    Не знаю как это вообще делают, но у меня получилось решить с помощью индивидуального байнда для каждого элемента. Можно было конечно и с помощью компонента оформить, было бы красивее и проще, но в целом это уже детали, можно сделать как нравится. Вот архив. То есть теперь при загрузке приложения в глобальной области видимости создаётся массив для инициализации блока goods:

    window.items = [
    	{ id: 1 },
    	{ id: 2 },
    	{ id: 3 },
    	...
    ]

    При инициализации приложения этот массив обрабатывается с помощью функции контроллера processGoods:

    model.$goods_list.append( controller.processGoods(window.items, model) );
    ...
    var controller = {
        processGoods: function(data, model) {
          var elements = new Array(data.length),
              temp_fragment = document.createDocumentFragment();
    
          for (var i = 0; i < data.length; i++) {
            elements[ i ] = model.controller.createElementFromTemplate('goods__item', model);
            rivets.bind(elements[i], Object.assign({ item: data[i] }, model));
            temp_fragment.appendChild( elements[ i ] );
          }
    
          return temp_fragment;
        },
        createElementFromTemplate: function(item, model) {
          return document.importNode(model.templates[ item ].content.children[0], true);
        },
        ...
    }

    Также эта функция участвует при обработке данных пришедших от pagination запроса:

    $('.goods__pagination').on('click', '.goods__page', function() {
        var data = {
            id: $(this).text()
        };
        $.ajax({
            url: '/demo.php',
            type: 'POST',
            data: data,
            dataType: 'json',
            success: function(data) {
                model.$goods_list.empty().append( controller.processGoods(data, model) );
                toTopAfterAjaxUpdatePagination();
            }
        });
    });
    Ответ написан
    1 комментарий
  • Как добавить в CKEDITOR навигацию выравнивая текста?

    lazalu68
    @lazalu68
    Salmon
    Второй пример на сайте.

    Код второго примера.
    CKEDITOR.replace( 'editor1', {
    		// Define the toolbar: http://docs.ckeditor.com/#!/guide/dev_toolbar
    		// The full preset from CDN which we used as a base provides more features than we need.
    		// Also by default it comes with a 3-line toolbar. Here we put all buttons in a single row.
    		toolbar: [
    			{ name: 'document', items: [ 'Print' ] },
    			{ name: 'clipboard', items: [ 'Undo', 'Redo' ] },
    			{ name: 'styles', items: [ 'Format', 'Font', 'FontSize' ] },
    			{ name: 'basicstyles', items: [ 'Bold', 'Italic', 'Underline', 'Strike', 'RemoveFormat', 'CopyFormatting' ] },
    			{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
    			{ name: 'align', items: [ 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock' ] },
    			{ name: 'links', items: [ 'Link', 'Unlink' ] },
    			{ name: 'paragraph', items: [ 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'Blockquote' ] },
    			{ name: 'insert', items: [ 'Image', 'Table' ] },
    			{ name: 'tools', items: [ 'Maximize' ] },
    			{ name: 'editing', items: [ 'Scayt' ] }
    		],
    		// Since we define all configuration options here, let's instruct CKEditor to not load config.js which it does by default.
    		// One HTTP request less will result in a faster startup time.
    		// For more information check http://docs.ckeditor.com/#!/api/CKEDITOR.config-cfg-customConfig
    		customConfig: '',
    		// Sometimes applications that convert HTML to PDF prefer setting image width through attributes instead of CSS styles.
    		// For more information check:
    		//  - About Advanced Content Filter: http://docs.ckeditor.com/#!/guide/dev_advanced_content_filter
    		//  - About Disallowed Content: http://docs.ckeditor.com/#!/guide/dev_disallowed_content
    		//  - About Allowed Content: http://docs.ckeditor.com/#!/guide/dev_allowed_content_rules
    		disallowedContent: 'img{width,height,float}',
    		extraAllowedContent: 'img[width,height,align]',
    		// Enabling extra plugins, available in the full-all preset: http://ckeditor.com/presets-all
    		extraPlugins: 'tableresize,uploadimage,uploadfile',
    		/*********************** File management support ***********************/
    		// In order to turn on support for file uploads, CKEditor has to be configured to use some server side
    		// solution with file upload/management capabilities, like for example CKFinder.
    		// For more information see http://docs.ckeditor.com/#!/guide/dev_ckfinder_integration
    		// Uncomment and correct these lines after you setup your local CKFinder instance.
    		// filebrowserBrowseUrl: 'http://example.com/ckfinder/ckfinder.html',
    		// filebrowserUploadUrl: 'http://example.com/ckfinder/core/connector/php/connector.php?command=QuickUpload&type=Files',
    		/*********************** File management support ***********************/
    		// Make the editing area bigger than default.
    		height: 800,
    		// An array of stylesheets to style the WYSIWYG area.
    		// Note: it is recommended to keep your own styles in a separate file in order to make future updates painless.
    		contentsCss: [ 'https://cdn.ckeditor.com/4.6.1/full-all/contents.css', 'mystyles.css' ],
    		// This is optional, but will let us define multiple different styles for multiple editors using the same CSS file.
    		bodyClass: 'document-editor',
    		// Reduce the list of block elements listed in the Format dropdown to the most commonly used.
    		format_tags: 'p;h1;h2;h3;pre',
    		// Simplify the Image and Link dialog windows. The "Advanced" tab is not needed in most cases.
    		removeDialogTabs: 'image:advanced;link:advanced',
    		// Define the list of styles which should be available in the Styles dropdown list.
    		// If the "class" attribute is used to style an element, make sure to define the style for the class in "mystyles.css"
    		// (and on your website so that it rendered in the same way).
    		// Note: by default CKEditor looks for styles.js file. Defining stylesSet inline (as below) stops CKEditor from loading
    		// that file, which means one HTTP request less (and a faster startup).
    		// For more information see http://docs.ckeditor.com/#!/guide/dev_styles
    		stylesSet: [
    			/* Inline Styles */
    			{ name: 'Marker', element: 'span', attributes: { 'class': 'marker' } },
    			{ name: 'Cited Work', element: 'cite' },
    			{ name: 'Inline Quotation', element: 'q' },
    			/* Object Styles */
    			{
    				name: 'Special Container',
    				element: 'div',
    				styles: {
    					padding: '5px 10px',
    					background: '#eee',
    					border: '1px solid #ccc'
    				}
    			},
    			{
    				name: 'Compact table',
    				element: 'table',
    				attributes: {
    					cellpadding: '5',
    					cellspacing: '0',
    					border: '1',
    					bordercolor: '#ccc'
    				},
    				styles: {
    					'border-collapse': 'collapse'
    				}
    			},
    			{ name: 'Borderless Table', element: 'table', styles: { 'border-style': 'hidden', 'background-color': '#E6E6FA' } },
    			{ name: 'Square Bulleted List', element: 'ul', styles: { 'list-style-type': 'square' } }
    		]
    	} );


    Ответ написан
    3 комментария
  • Как подставлять в инлайн стили динамическое значение из функции?

    lazalu68
    @lazalu68
    Salmon
    Ошибка логическая: вы пытаетесь получить разницу ширин после того как запрещаете overflow:

    document.documentElement.style.overflow = 'hidden'
    document.documentElement.style.paddingRight = scrollSize()


    Т.к. ширина скроллбара постоянная, то можно сохранить её в переменную и потом использовать это значение:

    const scrollSize = window.innerWidth - document.documentElement.clientWidth;
    
    if (!this.isActive) {
    	document.documentElement.style.removeProperty('overflow')
    	document.documentElement.style.removeProperty('padding-right')
    	document.querySelector('.headroom').style.removeProperty('padding-right')
    } if (this.isActive) {
    	document.documentElement.style.overflow = 'hidden'
    	document.documentElement.style.paddingRight = scrollSize
    	document.querySelector('.headroom').style.paddingRight = scrollSize
    }
    Ответ написан
    1 комментарий