Блог

API Twitter - Origin null is not allowed by Access-Control-Allow-Origin

Эта ошибка возникает, когда вы пытаетесь сделать ajax-запрос к какому-либо сервису с локалхоста. Исправляется очень просто - припишите в конце адреса, на который делаете запрос, &callback=?.

Пример:

$.ajax({
    type : "GET",
    url : "http://api.twitter.com/1/users/show.json?screen_name="+groupname+'&callback=?',
    dataType: "json",
    success : function(data) { ... }
});

Подробнее читайте тут.

javascript

Создание zip архива папки с вложенными папками в PHP

Для такой задачи потребуется рекурсивный обход вложенных папок, и добавление их в архив. Эту задачу (в данном случае) выполняет функция ZipDirectory, которая вызывается рекурсивно. Функция ZipFull же проверяет, возможно ли создать zip-архив, запускает ZipDirectory и закрывает файл при завершении обхода папок.

function ZipDirectory($src_dir, $zip, $dir_in_archive='') {
    $dirHandle = opendir($src_dir);
    while (false !== ($file = readdir($dirHandle))) {
        if (($file != '.')&&($file != '..')) {
            if (!is_dir($src_dir.$file)) {
                $zip->addFile($src_dir.$file, $dir_in_archive.$file);
            } else {
                $zip->addEmptyDir($dir_in_archive.$file);
                $zip = ZipDirectory($src_dir.$file.DIRECTORY_SEPARATOR,$zip,$dir_in_archive.$file.DIRECTORY_SEPARATOR);
            }
        }
    }
    return $zip;
}

function ZipFull($src_dir, $archive_path) {
    $zip = new ZipArchive();
    if ($zip->open($archive_path, ZIPARCHIVE::CREATE) !== true) {
        return false;
    }
    $zip = ZipDirectory($src_dir,$zip);
    $zip->close();
    return true;
}

Использование, например, следующее:

if (ZipFull('D:/test/','D:/result.zip')) {
    echo 'Архив успешно создан!';
} else {
    echo 'Ошибка при создании архива!';
}

Более подробно про ZipArchive вы можете почитать здесь - http://php.net/manual/en/ziparchive.open.php.

php

Как написать хак для IE, Firefox, Chrome

Увы, приходится иногда использовать и хаки - сложная не своя верстка, в которой нет времени разбираться, например…

У оперы хаки от версии к версии меняются, поэтому можно в css написать для нее как основы, а остальных поправить хаками (если требуется).

/* firefox */
@-moz-document url-prefix() {
    .myclass {
        font-size:16px;
    }
    /* ... */
}
/* chrome и safari */
@media all and (-webkit-min-device-pixel-ratio:0) {
    .myclass {
        font-size: 18px;
    }
    /* ... */
}

Для Internet Explorer - самое удобное. Подход называется “Conditional comments”. См. пример:

<!--[if IE]>
Special instructions for IE here
<![endif]-->

Внутри можно, например, подключить css, которая выполнится только в IE:

<!--[if IE]>
<link rel="stylesheet" type="text/css" href="/css/ie.css">
<![endif]-->

Также, можно указывать версию IE:

<!--[if IE 6]> <![endif]-->
<!--[if IE 7]> <![endif]-->
<!--[if IE 8]> <![endif]-->

Или указывать версию больше или меньше:
gt: больше, чем.
lt: меньше, чем.
Если добавляется “e”, то еще и равно значению

<!--[if gt IE 6]>Больше 6-ого<![endif]-->
<!--[if lte IE 7]>Седьмой или меньше<![endif]-->

И помните, хаки - плохой выход.

верстка

Плавно перемещаем скролл к элементу

Можно сделать красивый якорь - т.е. плавное перемещение к любому DOM-элементу. Для этого сделаем такой скрипт:

$('a[href^="#"]').click(function() {
    $('html:not(:animated)' +( !$.browser.opera ? ',body:not(:animated)' : '')).animate({ scrollTop: $($(this).attr('href')).offset().top}, 1000 );
return false;
});

Этот код заменяет все якоря на плавные. Время перемещения до якоря - 1000 мс, вы, конечно же, можете легко поменять его.

$('element').offset().top - определить расстояние (высоту) от начала (самого верха) страницы до выбранного элемента.

Проверил работу в браузерах IE8, Chrome 19, Opera 12.00, Firefox 13.01. Везде хорошо работает.

И не забудьте подключить jQuery в блоке head!

<head>
...
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
...
</head>

Источники:
http://loco.ru/materials/96-jquery-scroll-to-top
http://api.jquery.com/offset/

javascript

Как получить координаты в формате Excel из числового вида

Допустим, нам надо представить ячейку с координатами (5,4) в Excel-формате, т.е. как “E4”. Либо (27,3) как “AA3”. Эту задачу легко выполнить, если представить буквенный формат таблицы Excel в виде 26ричной системы счисления, состоящей из букв.

Т.е., нам потребуется словарь, мы можем представить его одной алфавитной строкой, и собственно, сам алгоритм, который несложен сам по себе.

Для того, чтобы получать правильные координаты ячейки Excel, будем использовать начало координат не (0,0), а (1,1), как в экселе.

Получился такой вот код:


function getExcelCell($x,$y) {
    if (($x < 1) || ($y < 1)) { return False; }
    $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $excelX = '';
    while ($x > 0) {
        $r = $x % 26;
        $x = (int)($x / 26);
        if ($r == 0) {
            $r = 26; $x = $x - 1;
        }
        $excelX = $alphabet[$r-1] . $excelX;
    }
    $excelCell = $excelX . $y;
    return $excelCell;
}

// Тест

for ($i = -10; $i < 1500; $i++) {
    $res = getExcelCell($i,$i);
    if ($res) {
        echo $res . "<br>";
    } else {
        echo 'Значение (' . $i . ', ' . $i . ') не может быть обработано!<br>';
    }
}

Как видите, в случае, если передаются отрицательные значения (или 0) в $x или $y, то функция возвращает False.

php

Cufon не меняет цвет ссылок при наведении

<p>Обнаружил такую проблему: <a title=”Cufon” href="https://github.com/sorccu/cufon” target=”_blank” rel=”noopener”>Cufon</a> (заменитель шрифтов, см. <a title=”Cufón – используйте шрифты, какие душа пожелает” href=”http://habrahabr.ru/post/61033/" target=”_blank” rel=”noopener”>здесь</a> и <a title=”Нестандартный шрифт средствами js” href=”http://www.marketer.ru/adv/production/dizajn/tipografika/cufon-nestandartnyj-shrift-sredstvami-js/" target=”_blank” rel=”noopener”>здесь</a>) прекрасно менял все шрифты, цвета и т.п. Но в одном месте ни в какую не хотел изменять цвет шрифта при наведении (:hover).<br />Оказалось, что если ссылка, которая должна hover’иться, находится внутри другого блока текста, который уже обработан Cufon’ом, то она не сможет изменить цвет (!), border и некоторые другие свойства будут меняться без проблем.<br />Итак, ниже показываю, в каких случаях hover’а не происходит, а в каких происходит (в коде все понятно). Либо можно скачать <a href=”/media/uploads/2018/11/09/cufon-test.zip” target=”_blank” rel=”noopener”>архив, вместе со шрифтами</a>, и самому посмотреть.</p>


<!doctype html>
<html>
<head>
<script type="text/javascript" src="test/jquery00.js"></script>
<script type="text/javascript" src="test/cufon-yu.js"></script>
<script type="text/javascript" src="test/Plumb_20.js"></script>
<style>
a, a:link, a:visited { color : #0000cc; }
</style>
</head>
<body>
<div class="example">Lorem <a href="#" class="ahref">Ссылка, вложенная в другой элемент с Cufon'ом, обработка сначала внешнего блока, потом ссылки [hover'а нет]</a> ipsum</div>
<div class="example2"><span class="example">Lorem</span> <a href="#" class="ahref">Ссылка, не вложенная в элемент с Cufon'ом, внутри текста</a> <span class="example">ipsum</span></div>
<div class="example2">Lorem <a href="#" class="ahref">Ссылка, вложенная в другой элемент с Cufon'ом, обработка сначала ссылки, потом внешнего блока</a> ipsum</div>
<div class="example2">Lorem <a href="#">Ссылка без явного указания класса [hover'а нет]</a> ipsum</div>
<a class="ahref" href="#" >Ссылка, не вложенная в другие элементы, которые обрабатываются Cufon'ом</a></p>
<p><script type="text/javascript">
Cufon('.example');
Cufon('.ahref', {
color: '#0000cc',
hover: true,
hover: {
color: '#ccc'
}
});
Cufon('.example a', {
color: '#0000cc',
hover: true,
hover: {
color: '#ccc'
}
});
Cufon('.example2');
</script>
</body>
</html>
верстка

Красивая пагинация на битриксе / bitrix pagination

Сделал свою пагинацию на битриксе. Получилось вот так.
Минусы:
- Код некачественный. Если есть идеи по оптимизации, пишите в комментариях, поправлю.
- Игнорирует пагинацию в “обратном порядке”. Не увидел смысла в ней, поэтому отказался.

Тут можно изменять только один параметр:
$countPagesDisplay - это количество отображаемых страничек снизу (помимо первой, последней, стрелок и “…”).

Выглядит вот так:

http://localhost:8001/media/uploads/2018/11/09/pagination.png

<?
if(!defined("B_PROLOG_INCLUDED") || B_PROLOG_INCLUDED!==true)die();

if(!$arResult["NavShowAlways"])
{
    if ($arResult["NavRecordCount"] == 0 || ($arResult["NavPageCount"] == 1 && $arResult["NavShowAll"] == false))
    return;
}

// begin zadavaemie parametri

$countPagesDisplay = 3; // kolichestvo otobrajaemih stranic v paginacii

// end zadavaemie parametri

function addLeftBorder($lb) {
    if ($lb > 1) {
        $lb = $lb - 1;
    }
    return $lb;
}

function addRightBorder($rb,$max) {
    if ($rb < $max) {
        $rb = $rb + 1;
    }
    return $rb;
}

$i = 1;
$left_border = $arResult["NavPageNomer"];
$right_border = $arResult["NavPageNomer"];
$max = $arResult["NavPageCount"];

while($i < $countPagesDisplay) {
    if($i % 2 == 0) {
        $lb = $left_border;
        $left_border = addLeftBorder($left_border);
        if ($left_border == $lb) {
            $rb = $right_border;
            $right_border = addRightBorder($right_border, $max);
            if ($right_border == $rb) {
                $i = $countPagesDisplay;
            }
        }
    } else {
        $rb = $right_border;
        $right_border = addRightBorder($right_border, $max);
        if ($right_border == $rb) {
            $lb = $left_border;
            $left_border = addLeftBorder($left_border);
            if ($left_border == $lb) {
                $i = $countPagesDisplay;
            }
        }
    }
    $i++;
}
$arResult["nStartPage"] = $left_border;
$arResult["nEndPage"] = $right_border;

//echo "<pre>"; print_r($arResult);echo "</pre>";

$strNavQueryString = ($arResult["NavQueryString"] != "" ? $arResult["NavQueryString"]."&amp;" : "");
$strNavQueryStringFull = ($arResult["NavQueryString"] != "" ? "?".$arResult["NavQueryString"] : "");

?>
<div class="paginator">

<font class="text">

<?if ($arResult["NavPageNomer"] > 1):?>

    <?if($arResult["bSavePage"]):?>
        <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=($arResult["NavPageNomer"]-1)?>">&larr;</a>
        <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=1">1</a>
    <?else:?>
        <?if ($arResult["NavPageNomer"] > 2):?>
            <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=($arResult["NavPageNomer"]-1)?>">&larr;</a>
        <?else:?>
            <a href="<?=$arResult["sUrlPath"]?><?=$strNavQueryStringFull?>">&larr;</a>
        <?endif?>
        <?if ($arResult["nStartPage"] != 1):?>
            <a href="<?=$arResult["sUrlPath"]?><?=$strNavQueryStringFull?>">1</a>
        <?endif?>
    <?endif?>

<?else:?>
    &larr;&nbsp;
<?endif?>

<?if ($arResult["nStartPage"] > 2):?>
    <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=($arResult["nStartPage"]-1)?>">...</a>
<?endif?>

<?while($arResult["nStartPage"] <= $arResult["nEndPage"]):?>
    <?if ($arResult["nStartPage"] == $arResult["NavPageNomer"]):?>
        <span><?=$arResult["nStartPage"]?></span>
    <?elseif($arResult["nStartPage"] == 1 && $arResult["bSavePage"] == false):?>
        <a href="<?=$arResult["sUrlPath"]?><?=$strNavQueryStringFull?>"><?=$arResult["nStartPage"]?></a>
    <?else:?>
        <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=$arResult["nStartPage"]?>"><?=$arResult["nStartPage"]?></a>
    <?endif?>
    <?$arResult["nStartPage"]++?>
<?endwhile?>

<?if ($arResult["nEndPage"] < ($arResult["NavPageCount"] - 1)):?>
    <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=($arResult["nEndPage"]+1)?>">...</a>
<?endif?>

<?if($arResult["NavPageNomer"] < $arResult["NavPageCount"]):?>
    <?if($arResult["nEndPage"] < $arResult["NavPageCount"]):?>
        <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=$arResult["NavPageCount"]?>"><?=$arResult["NavPageCount"]?></a>
        <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=($arResult["NavPageNomer"]+1)?>">&rarr;</a>
    <?else:?>
        <a href="<?=$arResult["sUrlPath"]?>?<?=$strNavQueryString?>PAGEN_<?=$arResult["NavNum"]?>=<?=($arResult["NavPageNomer"]+1)?>">&rarr;</a>
    <?endif?>
<?else:?>
    &nbsp;&rarr;
<?endif?>

</div>
bitrix

Делаем теги и ссылки к ним в статьях битрикса

Можно решить эту задачу так. Для этого в конец компонента bitrix:news (скопировав его) следует вставить функцию:

<?
function addLinkForTag($tagname) {
    $taglink = str_replace(' ','+',$tagname); // Пробелы должны заменяться плюсами
    return '<a href="/search/?tags='.$taglink.'">'.$tagname.'</a>'; // Добавляем ссылку. Внимание, у вас ссылка может быть не "/search/", а какая-либо другая!
}
?>

И для тех же статей (при условии, что все стандартно) в компоненте bitrix:news.list можно написать что-либо подобное:

<?foreach($arItem["FIELDS"] as $code=>$value):?> // Это уже было - стандартный перебор свойств каждой новости
    <small>
    <?
    if (GetMessage("IBLOCK_FIELD_".$code) == 'Теги') { // Желательно написать как-нибудь по другому, но на данный момент идей как правильно - нет :)
        if(CModule::IncludeModule("search")) { // Необходимо подключить модуль поиска. Без него работать не будет
            $tags_array = tags_prepare($value, "s1"); // Распиливаем теги в массив
            echo GetMessage("IBLOCK_FIELD_".$code).': '; // Выводим название "Теги"
            $tags_array = array_map("addLinkForTag",$tags_array); // Применяем функцию для создания ссылок для элементов массивов
            $result_tags = implode(", ", $tags_array); // Соединяем все обратно в одну строку
            echo $result_tags; // Выводим результат
        }
    } else { // Если у нас не Тег, то просто выводим как обычно "ключ" : "значение" (эта строка была по умолчанию)
        echo GetMessage("IBLOCK_FIELD_".$code).': '.$value;
    }
    ?>
    </small>
    <br />
<?endforeach;?>

Затем создаем страницу в битриксе и вставляем в нее компонент поиска bitrix:search.page. Собственно, ссылка на него и будет ссылкой, на которую надо поменять мой “/search/”.

bitrix

Обработка отправления почты в bitrix

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

Для написания пригодилось знать следующее:

Событие http://dev.1c-bitrix.ru/api_help/main/events/onbeforeeventadd.php вызывается в момент добавление почтового события в таблицу b_event. Как правило, задача обработчика данного события - изменить или добавить какое-либо значение, передаваемое в макросы почтового шаблона.

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

Почтовая система

Итак, сам код. Его надо разместить в /bitrix/php_interface/init.php.

<?
AddEventHandler("main", "OnBeforeEventAdd", array("MailCheredator", "OnBeforeEventAddHandler"));

class MailCheredator {
    function OnBeforeEventAddHandler(&$event, &$lid, &$arFields) {
        $arFields["SALE_EMAIL"] = "sale_mail@example.ru";
        $arFields["BCC"] = "";
        if (intval($arFields["ORDER_ID"]) % 2 == 1) {
            $arFields["EMAIL"] = $arFields["EMAIL"]. ",email1@example.ru";
        } else {
            $arFields["EMAIL"] = $arFields["EMAIL"]. ",email2@example.ru";
        }
    }
}
?>

Здесь,
SALE_EMAIL - в моем случае, адрес, с которого отправляется письмо (у вас может быть другой!).
BCC - сюда отправляются копии письма, которые не должен видеть тот, кому отправляется письмо (можно было email1 и email2 сюда записать).
EMAIL - адрес, куда отправится письмо. Можно перечислять через запятую.

bitrix

Просмотр всех свойств элемента инфоблока

Пригодится для просмотра в API битрикса всех данных об элементах инфоблока. А потом найденное можно будет изменить. Подробности можно прочитать тут: http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php

<?
$arFilter = Array(
    "IBLOCK_ID"=>IntVal(2), //id инфоблока
    "ACTIVE"=>"Y", // только активные
    "SECTION_ID"=>38, // id раздела в инфоблоке
    "INCLUDE_SUBSECTIONS"=>"Y" // чтобы включались подразделы
);
$res = CIBlockElement::GetList(Array("SORT"=>"ASC", "PROPERTY_PRIORITY"=>"ASC"), $arFilter);
while($ob = $res->GetNextElement())
{
    $arFields = $ob->GetFields();
    echo $arFields["NAME"]."<br />";
    print_r($arFields);
    $arProps = $ob->GetProperties();
    print_r($arProps);
    echo "<br /><br />";
}
?>
bitrix