Webdev

Web development

PHP: ++$i быстрее $i++ в 1.6 раз

- Posted in Webdev by

Проверил услышанное (усомнился, что разница будет хоть сколько-нибудь заметная).

Удивлён? Не то слово! У меня разница получилась в 1.6-1.7 раз. Я думал, что если и будет, то какие-то копейки. А тут - полтора-два раза?!

Это на PHP 7.0.22, OS 64-битная (x86_64 GNU/Linux).

Есть ли разница на C++ или Java, и насколько большая - не знаю, не проверял. Если кто подскажет - было бы интересно.

Понятно, что если смотреть на абсолютные цифры и не жить в мире нагруженных проектов - на разницу можно махнуть рукой и сказать, что это экономия на спичках. Но вот в композеровских библиотеках поискал - очень много используют именно префиксную форму (там, где нет никакой разницы, что возвращает операция, и цель - только в инкременте).

Чего и всем желаю. Применяйте ++$i на автопилоте.

Обсудить

Sticky-меню и sticky-footer - кошмар для мобильных пользователей

- Posted in Webdev by

Что за тренды такие? То делают повсеместно буквы такие громадные, как будто люди без очков на Земле кончились. А те, что остались, обожают листать по 5-10 строчек текста вместо того, чтоб читать. Там, где легко 50 помещалось до того, как дизайнерам не сказали, что теперь круто - это интерфейсы для пальцев и буквы как для слепых. Были палмы с экранами 160x160 и 320x320 - на них комфортно помещалось 20-25 строк текста. Теперь экраны телефонов в 3 раза больше физически, разрешение то 480 на хрен-знает-сколько, то 800x480. А количество строк текста стало не 50, а 20 или и того меньше меньше...

Теперь вот ещё замечаю чуть ли не на каждом сайте то меню, то футер с соц-иконками, которые хотят остаться на экране постоянно.

Алё! Вы вообще представляете, сколько места остаётся на гигантских по вчерашним меркам экранах современных телефонов для полезного текста, за которым приходят пользователи? Мне даже на нетбуке часто очень некомфортно оказывается из-за всех этих стики и тем более поп-апов с подписками и предварительной дружбой в соцсетях.

Желаю всем веб-мастерам поставить на sticky-menu кнопку закрытия. И отслеживать аналитику кликов по убиранию вашего мусора с наших экранов. Не нужно на экране постоянно ни меню, ни футер, ни соцкнопки. Мы прекрасно помним, где они находятся, а время нахождения на сайте эти ухищрения не увеличат. Скорее уменьшат. Видеть кусочек полезного контента сквозь крохотную оставшуюся амбразуру на весьма больших экранах мобильных устройств и одновременно радоваться такому неудобству - задачи несовместимые.

А ещё "радуют" выпрыгивающие на смартфоне поп-апы, которые намного больше экрана телефона и закрыть их невозможно, т.к. изменение масштаба на странице заботливо вырезано и недоступно, а при прокрутке окошко позиционируется посредине.

How to run rsync via non-standard ssh port

- Posted in Webdev by

Не знали, как запустить rsync через нестандартный порт (при работе через SSH, без ответного Rsync демона на сервере)?

Теперь знайте:

rsync -avz -e "ssh -p 12345" ./public_html/ username@yourserver.com:/var/www/html/

Здесь 12345 - номер порта, username - ваш логин и yourserver.com - доменное имя или IP вашего сервера.

Пришлось немного повозиться с чтением манов и поэкспериментировать. Надеюсь, кому-то сэкономит время.

[FWD] Сравнение производительности четырёх JS-библиотек

- Posted in Webdev by

Сравнение производительности четырёх JS-библиотек: native Javascript, Google Closure, jQuery, ExtJS.

Результаты там наглядные и поразительные. jQuery оказывается заметным тормозом.

См. также:

На графике по горизонтали - количество операций за миллисекунду. Чем длиннее, тем быстрее работа:

Сравнение производительности четырёх JS-библиотек</a>: native Javascript, Google Closure, jQuery, ExtJS

Обсудить

PhantomJS - утилита для тестирования дизайна на разных экранах

- Posted in Webdev by

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

Базируется на движке WebKit. Технически - это обычный броузер, но без интерфейса пользователя. Результаты рендеринга страницы и Javascript можно записать в виде картинки.

Testing your responsive design with PhantomJS.

Там описана установка из репозиториев для Ubuntu и MacOSX и пример использования -- результаты в виде скриншотов тоже можно разглядеть. Я с инструментом не работал, так что вряд ли смогу что-то добавить к тому, что написано в указанной статье.

SafePatch - альтернатива vQmod

- Posted in Webdev by

Идея патчей и vQmod совершенно одинаковая. И в одном, и другом случае файл с изменениями накладывается на некую известную основу. И если эта основа изменилась -- и патч, и vQmod могут "поломаться": не смогут внести изменения, если не найдут точного соответствия, необходимого для внесения правок.

Поэтому те, кто наивно полагает, что vQmod спасёт их от всех бед и является волшебной таблеткой и позволит без проблем обновлять версии и ни о чем не беспокоиться - сильно заблуждаются.

А те, кто знает об этом и вынужден хоть так, хоть иначе контролировать логи ошибок -- знают, что заниматься отладкой vQmod гораздо менее удобно, чем иметь изменения сразу на месте, в коде, и не гадать, откуда именно берется исполняемый код и где его искать в исходниках.

К тому же vQmod - рантайм решение. То есть работает при каждом запросе к серверу. Конечно, многое решается кешированием. Но я из тех разработчиков, которые не совсем понимают, зачем нужно вводить лишнее звено, если то же самое делается без дополнительных костылей (а технологии внесения и убирания этих изменений существуют уже лет 40 и протестированы не одним поколением программистов -- я говорю об утилитах patch и diff).

Причём убрать изменения так же просто, как и наложить патч.

Применить изменения к коду: git apply fix-some-problem.diff или patch -p1 fix.diff

Убрать изменения: git apply -R fix-some-problem.diff или patch -R fix.diff

И где здесь сложная часть? Это ничуть не сложнее удаления VQmod файла. При использовании vQmod надо управляться с набором XML файлов. При использовании стандартного подхода -- с набором DIFF файлов. Невелика разница. А преимущества серьёзные.

И вот совсем недавно, в поисках PHP-реализации утилиты patch или автоматического конвертера DIFF в vQmod XML, я наткнулся на замечательный вариант: утилиту SafePatch.

http://code.google.com/p/safepatch/

UPD: в связи с закрытием Google Code проект переместился на Github: progerxp/safepatch.

Если кратко и своими словами -- это "менеджер пакетов" (расширений). Но в отличие от vQmod (runtime) он эти изменения вносит непосредственно в исходный код (как и patch). При этом понимает формат VQmod и может использовать эти файлы тоже.

Так что те, кто интересуется вопросом - встречайте. По-моему, хороший инструмент. Это не совсем то, что я искал, но отличное готовое решение проблемы.

See also:

2012-05: webdev links

- Posted in Webdev by

Живые блоги с публикациями о CodeIgniter:

Руководство по оформлению HTML/CSS кода от Google. Руководство вообще-то странное: местами непоследовательное и противоречащее самому себе, а местами и вовсе вредное, на мой взгляд. Видимо, сказываются особенности высоконагруженных проектов. В общем, я бы не стал слепо придерживаться всех изложенных там рекомендаций, но просмотреть список и причины появления таких правил -- полезно.

Обсудить

Не хватает сбора-подсчета спамерских IP в MaxSite CMS

- Posted in Webdev by

При модерируемых комменатриях от анонимов иногда возникают наплывы спам-ботов, которые мешают.

Для начала я выделил розовым фоном запрещенные комментарии. Это уже заметно облегчило разборки.

Но вот просто удалять спамерские комментарии мне не хочется. Шаблон у меня такой: если это разовое - то удалю и забуду, пусть тешатся, а если где-то бот поселился - хотелось бы подождать и убедиться, что это регулярное явление и забанить IP. Из-за одного спам-комментария банить весь IP как-то чересчур. Но сейчас приходится заниматься этим вручную.

Пригодился бы подсчёт количества удаленных спам-комменатриев с определенного IP. Чтобы я мог удалять их сразу (десяток в день удалить несложно и руками), но информация об их авторстве не пропадала впустую.

И через отметку галочек удалять или разрешать комментарии тоже очень не нравится: я обычно разрешаю 1-2 комментария. А для этого надо их отметить, промотать список до конца (спамеров гораздо больше успевает накопиться) и там не ошибиться с кнопкой (потому что пока проматываешь, иногда забывается - это я сейчас разрешить полезные хотел и их отметил? Или запретить/удалить бесполезное?).

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

Завёл репозиторий для MaxSite CMS на GitHub-е

- Posted in Webdev by

https://github.com/rb2/MaxSite-CMS

Основная причина - неудобство предлагаемого способа обновления между релизами. Мне не хватает diff-ов и легкого способа их получения для чистых версий, чтобы иметь возможность накатить эти изменения вручную на модифицированный движок. Обновляться заменой файлов мне чрезвычайно неудобно.

Если кто-то хочет присоединиться к переводу на английский или правке украинского - теперь есть куда:

  • Исключительно языковые файлы живут и переводятся в соответствующих ветках репозитория https://github.com/g3d/MaxSite-TC (сейчас там украинский в ветке master и английская заготовка в ветке english).
  • Участвовать в корректировке переводов может любой человек, даже понятия не имеющий и не желающий разбираться с Git-ом: достаточно оставлять комментарии к строкам файлов при их просмотре. Тем, кто дружит с Git-ом, объяснять наверное ничего не надо.
  • Файлы скачивать можно там же: переключиться на соответствующую ветку ("Current branch" справа) и скачать ZIP.

В https://github.com/rb2/MaxSite-CMS живёт полностью CMS. Языки туда по мере готовности будут периодически вливаться.

Если автор MaxSite CMS переберётся на GitHub - это значительно упростит дело: можно будет предлагать/публиковать дополнения гораздо проще. Пока что я предполагаю держать этот репозиторий (по крайней мере основную ветку) только для "чистых" релизов версий CMS. И пускать разработчиков только с условием коммитить любые дополнения и модификации в соседние ветки, но не в master. Master branch сейчас - исключительно для оригиналов и получения списка отличий между ними.

Загрузка jQuery по требованию

- Posted in Webdev by

Оригинал: Load jQuery on demand | Web-developer notepad

Для загрузки jQuery по требованию вы можете пользоваться скриптом loadJquery.js.

Быстрый старт

Загрузите скрипт по этой ссылке, отредактируйте его нижнюю часть после слов PUT YOUR CODE HERE, вот эту:

(function () {
...
    /* PUT YOUR CODE HERE  */
    loadJquery({
        url: 'http://code.jquery.com/jquery-latest.min.js',
        timeout: 5000, //ms
        success: function ($) {
            $('h1').css('border', '2px solid red');
        },
        error: function () {
            alert("Can't load jQuery.");
        }
    });
}());

Преимущества скрипта:

  • кроссбраузерность
  • основан на коде jquery 1.7.2
  • отлов исключений при помощи try/catch
  • возможность указания таймаута загрузки
  • загрузка не будет производиться, если jQuery уже загружен.
  • простота использования для конечного пользователя: просто пишите свой код в success/error-колбеки
  • отсутствие конфликтов с другими js-библиотеками типа prototype.js
  • скрипт проходит jslint-валидацию

Теперь больше информации для тех, кто хочет узнать подробности.

Скрипт состоит из двух частей: loadScript и loadJquery.

loadScript

Функция практически полностью сделана на основе кода jQuery 1.7.2, актуальной в данный момент. Загрузка скрипта производится посредством добавления тега script в head. Производится контроль исключений при помощи try/catch, теоретически не должно быть никаких ошибок яваскрипта. Предусмотрена возможность указания тайм-аута, по достижению которого будет вызван error-callback.

Пример использования.

loadScript({
    url: 'http://example.com/script.js', //script url
    timeout: 5000, //optional timeout in ms
    success: function () {
        alert('Script loaded callback.');
    },
    error: function () {
        alert('Script was not loaded.');
    }
});

loadJquery

Особенности функции loadJquery следующие:

  • загрузка jQuery не будет производиться, если jQuery уже загружен
  • используется .noConflict(), т.е. можно не беспокоиться о возникновении конфликтов с другой библиотекой типа prototype.js

Полный листинг скрипта

/*!
 *
 * loadJquery.js
 * Load jQuery on demand from javascript
 * Author: contact@slicezilla.com
 * November 2011
 *
 * The script uses part of jQuery JavaScript Library v1.7
 * http://jquery.com/
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
*/
/*global document, setTimeout, clearTimeout, alert, jQuery*/
(function () {
    "use strict";
    var loadScript = function (options) {
        var script, transportTimeout,
            head = document.head || document.getElementsByTagName('head')[0] || document.documentElement,
            transport = {
                send: function (url, successCallback) {
                    script = document.createElement('script');
                    script.async = 'async';
                    script.src = url;
                    // Attach handlers for all browsers
                    script.onload = script.onreadystatechange = function (event, isAbort) {
                        if (isAbort || !script.readyState || /loaded|complete/.test(script.readyState)) {
                            // Handle memory leak in IE
                            script.onload = script.onreadystatechange = null;
                            // Remove the script
                            if (head && script.parentNode) {
                                head.removeChild(script);
                            }
                            // Dereference the script
                            script = undefined;
                            //callback if not abort
                            if (!isAbort && typeof successCallback === 'function') {
                                clearTimeout(transportTimeout);
                                successCallback();
                            }
                        }
                    };
                    // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
                    // This arises when a base node is used (#2709 and #4378).
                    head.insertBefore(script, head.firstChild);
                    //head.appendChild(script);
                },
                abort: function (errorCallback) {
                    clearTimeout(transportTimeout);
                    if (script) {
                        script.onload(0, 1);
                    }
                    if (typeof errorCallback === 'function') {
                        errorCallback();
                    }
                }
            };
        //init timeout
        if (options.timeout > 0) {
            transportTimeout = setTimeout(function () {
                transport.abort(options.error);
            }, options.timeout);
        }
        //get script
        try {
            transport.send(options.url, options.success);
        } catch (e) {
            transport.abort(options.error);
        }
    };
    //function which will load jQuery using loadScript
    function loadJquery(options) {
        if (typeof jQuery !== 'undefined') {
            //jQuery is loaded already, just perform business logic
            if (typeof options.success === 'function') {
                //pass jQuery as parameter, in order to have $ === jQuery in callback
                //just in case that $.noConflict was used already, and $ !== jQuery
                jQuery(options.success);
            }
        } else {
            //jQuery was not loaded on a page
            loadScript({
                url: options.url,
                timeout: options.timeout,
                success: function () {
                    jQuery.noConflict();
                    if (typeof options.success === 'function') {
                        jQuery(options.success);
                    }
                },
                error: options.error
            });
        }
    }
    /* -------- PUT YOUR CODE HERE -------- */
    loadJquery({
        url: 'http://code.jquery.com/jquery-latest.min.js',
        timeout: 5000, //ms
        success: function ($) {
            $('h1').css('border', '2px solid red');
        },
        error: function () {
            alert("Can't load jQuery.");
        }
    });
}());

Обсудить

Page 1 of 2