ФорумПрограммированиеPHP для идиотов → Sass для PHP

Sass для PHP

  • AndryG

    Сообщения: 237 Репутация: N Группа: Адекваты

    Spritz Окт. 2, 2009, 9:52 п.п., спустя 3 часа 2 минуты 8 секунд

    Обновил ссылку
    Спустя 235 сек.
    Вычисление проходит прямо при синт. анализе.
    Данные хранятся в внутреннем формате (значение, тип) Для цвета значение - массив (R,G,B)
    Под конец всё выводится в человеческом виде.

    Начало заложено для приведения типов … но не реализовано.

    Ухожу я в отпуск. Но тему в избранное добавил.
    Всем пока.
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 2, 2009, 10:06 п.п., спустя 13 минут 38 секунд

    пока
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 10:30 д.п., спустя 2 дня 12 часов 23 минуты

    Немного улучшил обработку ошибок, расставил коментарии: http://subversion.assembla.com/svn/qb7/cuts/smartcss/testexpr.php
    Теперь в тестовой выдаче видно как алгоритм Бауэра-Замельзона раскладывает выражение на Обратную Полькую запись

    Пример:

    $vars = array('!alfa' => 6, '!beta' => 2, '!gama' => 5);

    echo "\nResult: ".SassExpression::calc('2*!alfa + !beta + !gama', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('2*(!alfa + !beta) + !gama', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('12 + "3"', $vars)."\n";

    =>

    2 !alfa * !beta + !gama +
    Result: 19
    2 !alfa !beta + * !gama +
    Result: 21
    12 "3" +
    Result: "123"


    Я старался работать с PHP как с PHP :) использовать его особенности и нефиговый набор функций. IMHO, получилось красиво.
    Возвращаясь к нашим баранам (Sass), намечу планы: чтобы калькулятор работал с размерностями и цветом надо править только метод _func($a, $op, $b)
    Там понадобится определять тип лексемы и приводить к единой размерности. Увы, AndryG, твой труд слишком "академический" и непрактичный. Держу пари мне понадобится 10-20 строк на это дело. Всё равно спасибо, твой пример будет полезен для "студентов".
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 6, 2009, 8:04 д.п., спустя 21 час 34 минуты 21 секунду

    Плюсуйте меня. Калькулятор умеет обрабатывать цвета и размеры!
    Цвет можно писать как white, #ffffff или #fff
    Размер можно писать как 1in, 72pt, 2.54cm. Проверяется совместимость размерностей. Нет смысла в 1em + 1pt

    Насчет 20 строчек я расхвастался конечно :) Один только массив предопределённых цветов столько занимает.
    Вобщем вот оно:

    $vars = array('!alfa' => 6, '!beta' => 2, '!gama' => 5);

    echo "\nResult: ".SassExpression::calc('2*!alfa + !beta + !gama', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('2*(!alfa + !beta) + !gama', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('12 + "3"', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('white - 1', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('1in + 1pt', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('1cm + 1in + 1pt', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('1em + 2pt', $vars)."\n";
    echo "\nResult: ".SassExpression::calc('12 / "3"', $vars)."\n";

    =>

    2 !alfa * !beta + !gama +
    Result: 19
    2 !alfa !beta + * !gama +
    Result: 21
    12 "3" +
    Result: "123"
    white 1 -
    Result: #fefefe
    1in 1pt +
    Result: 1.014in
    1cm 1in + 1pt +
    Result: 3.575cm
    1em 2pt +
    Result: ERROR: incompatible size dimensions
    12 "3" /
    Result: ERROR: "/" is wrong operation for these arguments


    Я подсматривал в The Sass Lab чтобы узнать пересчетные коэффициенты (in <=> mm) и тому подобные, а также чтобы понять как должны работать операции над цветом. оттуда же я понял, что rgb() и rgba() Sass вычислять не умеет, ну и я не буду заморачиваться.

    Для обсуждения привожу код:

    // Operation ID is a key of this array
    private static $_operations = array(NULL, '(', '+', '-', '*', '/', ')');

    // Size dimensions
    private static $_dimensions = array('in', 'cm', 'mm', 'pt', 'em', 'wm');
    private static $_dimRatio = array(
    array(    1, 2.54, 25.5,  72    ),
    array(0.394, 1,    10,    28.346),
    array(0.039, 0.1,   1,     2.835),
    array(0.014, 0.035, 0.353, 1    ));
    // Operaion ID symblic name
    const OP_ADD = 2;
    const OP_SUB = 3;
    const OP_MUL = 4;
    const OP_DIV = 5;
    // Operand type
    const OT_NUMBER = 1;
    const OT_SIZE   = 2;
    const OT_COLOR  = 3;
    const OT_STRING = 4;

    private static function _funcNumber($a, $op, $b)
    {
    switch ($op) {
    case self::OP_ADD: return $a + $b;
    case self::OP_SUB: return $a - $b;
    case self::OP_MUL: return $a * $b;
    case self::OP_DIV: return $b == 0 ? 0 : $a / $b;
    }
    }

    private static function _func($a, $op, $b)
    {
    list($a, $aType, $aDim) = self::_getValue($a);
    list($b, $bType, $bDim) = self::_getValue($b);
    $resultType = max($aType, $bType);
    if (min($aType, $bType) == self::OT_SIZE && $resultType == self::OT_COLOR)
    throw new Exception('color and size are not compatible');

    switch ($resultType) {
    case self::OT_NUMBER:
    return self::_funcNumber($a, $op, $b);

    case self::OT_SIZE:
    if (is_null($aDim)) $aDim = $bDim;
    if (is_null($bDim)) $bDim = $aDim;
    if ($aDim != $bDim)
    {
    if (!isset(self::$_dimRatio[$aDim][$bDim]))
    throw new Exception('incompatible size dimensions');
    $b *= self::$_dimRatio[$bDim][$aDim];
    }
    return self::_funcNumber($a, $op, $b) . self::$_dimensions[$aDim];

    case self::OT_COLOR:
    if ($aType == self::OT_NUMBER) $a = array($a, $a, $a);
    if ($bType == self::OT_NUMBER) $b = array($b, $b, $b);
    foreach ($a as $key => $dummy)
    $a[$key] = max(0, min(255, self::_funcNumber($a[$key], $op, $b[$key])));
    return sprintf('#%2x%2x%2x', $a[0], $a[1], $a[2]);

    case self::OT_STRING:
    if ($op == self::OP_ADD)
    return '"' . $a . $b . '"';
    break;
    }
    throw new Exception('"'.self::$_operations[$op].'" is wrong operation for these arguments');
    }


    Смотрите полные исходники в репозитарии: http://subversion.assembla.com/svn/qb7/cuts/smartcss/

    Планы: перенести калькулятор в модуль к SassFilter, обрабатывать команды @import file.sass и @import file.css сделал
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 7:11 д.п., спустя 23 часа 7 минут 13 секунд

    ООП. Нужна правильная декомпозиция.

    Есть класс-фильтр для прокачки текста Sass => текст CSS

    Есть класс-калькулятор для выражений внутри правил. К нему по мере надобности будет обращаться фильтр.

    Нужно обрабатывать операции импорта файлов скриптов Sass и готовых файлов CSS. Добавлять такую обработку в фильтр неправильно, это смешение функцинала. Фильтр не должен знать ничего о файловой системе, о расположении "рабочей директории", кешировании и т.п. Как выкрутиться? Предполагаю опциональный аргумент — колбек.

    class SassFilter
    {
    public static function pipe($sass, $style= O_NESTED, $commandCallback = NULL) {…}

    }

    class SassFile
    {
    public static function open($sassFileName, $style= O_NESTED)
    {
    $sass = file_get_contents($sassFileName);
    return SassFilter::pipe($sass, $style, array('SassFile', '_atCommand'));
    }

    public static function _atCommand(…) {…}
    }


    Интересно, смогу я остаться в рамках статических классов, когда здесь напрашивается рекурсивный вызов SassFilter::pipe() … сделал
    ιιlllιlllι унц-унц
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 10:34 д.п., спустя 3 часа 22 минуты 52 секунды

    Взял пример от Stu много колонок одинаковой высоты и расписал его для удобства адаптации.

    Как вам такое:

    @import basic.sass
    @import typography.sass
    @import color.sass

    !inner-width = 60%
    !inner-side-width = 15%
    !inner-middle-width = !inner-width - (2 * !inner-side-width)
    !outer-side-width = (100% - !inner-width) / 2

    // these columns will be stretched down
    #left, #mid-left, #mid-center, #mid-right, #right
     +eq-height

    #left
     :float left
     :width = !outer-side-width

    #mid-left
     :float left
     :width = !inner-side-width

    #mid-center
     :float left
     :width = !inner-middle-width

    #mid-right
     :float right
     :width = !inner-side-width

    #right
     :float right
     :width = !outer-side-width

    #topbar
     :float left
     :width = !inner-width

    // hack to compensate for IE and percentage widths rounding errors
    .ie
     #topbar
       :width = !inner-width + 0.6%
     #mid-center
       :width = !inner-middle-width - 0.2%
     #right
       :width = !outer-side-width - 0.8%

    и

    !basic-color = #f0f0f0
    !color-accent = #100000

    !header-color = #a31e39
    !footer-color = #455c5a
    !high-color = #fff

    body
    :background = !basic-color

    #minMax
    :background = !basic-color - 0x10

    #header
    :background = !header-color

    #left
    :background = !basic-color - 0x30 + !color-accent

    #mid-left
    :background = !basic-color - 0x30

    #mid-right
    :background = !basic-color - 0x20

    #right
    :background = !basic-color - 0x40 + !color-accent

    Достаточно изменить ключевые переменные и весь стилевой файл будет пересчитан.
    Обратите внимание как реализуется хак для IE.

    Во вложении архив с этой демкой.
    Статическая страница multicolumn.html использует стиль

    <link rel="stylesheet" media="all" type="text/css" href="sass-on-the-fly.php/eqcolumn.sass" />

    то есть стиль на самом деле генерируется "на лету" скриптом sass-on-the-fly.php
    Sass разбит на четыре файла — главный и из него импортятся вспомогательные, а на выходе будет один компактный CSS.
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5305 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 11:55 д.п., спустя 1 час 21 минуту 3 секунды

    это что другой язык выучить
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 12:29 п.п., спустя 33 минуты 41 секунду

    тебе понравится. стопудов
    ιιlllιlllι унц-унц
  • Troy

    Сообщения: 2532 Репутация: N Группа: Джедаи

    Spritz Окт. 5, 2009, 2:39 п.п., спустя 2 часа 10 минут 8 секунд

    artoodetoo, много времени у тебя на генерацию уходило ?
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 2:46 п.п., спустя 6 минут 58 секунд

    я не мерял пока. на глаз задержки не заметно :) конечно надо продумать кеширование. хотя браузеры стилевые файлы сами кешируют нефигово на клиентской стороне.
    ιιlllιlllι унц-унц
  • phpdude

    Сообщения: 26646 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 2:53 п.п., спустя 7 минут 22 секунды


    я не мерял пока. на глаз задержки не заметно :) конечно надо продумать кеширование. хотя браузеры стилевые файлы сами кешируют нефигово на клиентской стороне.
    при правильных заголовках ;)

    Сапожник без сапог
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 5:52 п.п., спустя 2 часа 58 минут 58 секунд

    Что именно должно быть в правильном заголовке? Content-type я указываю, иначе браузер не воспринимает вывод как "стиль". Что ещё? Дату модификации явно указать?

    edited: Ага, вот тут внимательный читатель может извлечь для себя пользу.
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5305 Репутация: N Группа: в ухо

    Spritz Окт. 5, 2009, 6 п.п., спустя 7 минут 49 секунд

    artoodetoo,
    Expires Mon, 26 Jul 1997 05:00:00 GMT
    Last-Modified Mon, 05 Oct 2009 13:58:56 GMT
    Cache-Control private
    Pragma no-cache
    X-Cache (если прокси)
    E-Tag хз кто его использует кроме оперы давно спеки не перечитывал
  • artoodetoo

    Сообщения: 5147 Репутация: N Группа: в ухо

    Spritz Окт. 6, 2009, 6:31 д.п., спустя 12 часов 31 минуту 7 секунд

    Ок. будем считать с заголовками разобрались. Задача в другом: надо ли стремиться к тому чтобы браузер НЕкешировал или наоборот кешировал стилевые файлы. С одной стороны не хочется создавать лишнюю нагрузку, с другой если стиль обновился, надо чтобы пользователь получил обновление.

    IMHO так — надо указывать что стиль не устареет никогда, а когда надо вынуждать перечитать можно указав новое (виртуальное) имя файла. Это имя может быть либо rand либо timestamp обновленной версии.

    echo '<link rel="stylesheet" media="all" type="text/css" href="sass-on-the-fly.php/'.$updatetime.'/eqcolumn.sass" />';

    или просто выкладывать сгенерированный CSS файл с новым именем и пусть забирают статику. Но тогда мы никак не управляем заголовками.
    Апач можно заставить выдать Expire и Pragma no-cache ? Кто напишет слово "nginx" тот дурак :)
    ιιlllιlllι унц-унц
  • Trej Gun

    Сообщения: 5305 Репутация: N Группа: в ухо

    Spritz Окт. 6, 2009, 10:42 д.п., спустя 4 часа 10 минут 52 секунды

    многие делают style.css?06102009
    но достаточно заголовками указать

    Last-Modified и E-Tag

Пожалуйста, авторизуйтесь, чтобы написать комментарий!