Показаны сообщения с ярлыком js. Показать все сообщения
Показаны сообщения с ярлыком js. Показать все сообщения

четверг, 19 июня 2014 г.

Bitrix: применяем стили визуального редактора правильно

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

Для решения этой проблемы я решил обернуть весь текст из визуального редактора в div с определенным классом и все стили наследовать от него.
Т.е. в файле стилей нам можно будет прописать оформление для всех элементов наследников этого класса. Тогда оформление будет выглядеть одинаково как в самом визуальном редакторе, так и в любой части страницы, т.к. весь код будет обернут в этот div.
Остается только вставлять этот див автоматически в визуальный редактор.
Для этого в init.php добавляем обработчик события подключения визуального редактора и при его инициализации создаем div в который поместим весь контент.
<?php
//событие подключения визуального редактора
AddEventHandler("fileman", "OnIncludeHTMLEditorScript", array("MyHandlers", "OnIncludeHTMLEditorScript"));


class MyHandlers {

   public static function OnIncludeHTMLEditorScript()
   {
      ?>
      <script type="text/javascript">
      //получаем указатель на полотно визуального редактора
      BXHTMLEditor.prototype.SetView_ = BXHTMLEditor.prototype.SetView;
      BXHTMLEditor.prototype.SetView = function (sType) {
         var result = this.SetView_(sType);
         var html = undefined;
         if(BX.browser.IsIE()) {
            try {
               html = this.pEditorDocument.body;
            } catch (e) {
               //
            }         
         } else {
            try {
               html = this.pEditorWindow.document.body;
            } catch (e) {
              //
            }
         }
         if( sType == "html" && html ) {
            //обертываем в DIV, если его еще нет
            if( html.innerHTML.indexOf('<div class="content">') == -1 ) {
              html.innerHTML = '<div class="content">'+html.innerHTML+'</div>';
            }
         }
         return result;
      };
      </script>
      <?
   }
}
?>

вторник, 25 декабря 2012 г.

Firefox: пишем расширение для браузера

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

Внедерение своего скрипта в тело страницы
//защищенная часть скрипта - оборачиваем в анонимную функцию, чтобы не было повторов имен переменных
(function() {
    var YT_global_doc = undefined;

    var YT_loader = new function(){};
    YT_loader.run = function(e) {
        //проверяем адрес сайта
	var unsafeWin = e.target.defaultView;
	var unsafeLoc = new XPCNativeWrapper(unsafeWin, 'location').location;
	var href = new XPCNativeWrapper(unsafeLoc, 'href').href;
	if (!href.match(/^http:\/\/www\.xxxx\.com\/watch(.*)?$/i) )
	      return;

        //обращаемся к dom сайта
	YT_global_doc = e.target.defaultView.document;

	if(YT_global_doc) {

          //подгружаем наш скрипт
	  var script = YT_global_doc.createElement( 'script' );
	  script.type = 'text/javascript';
	  script.src = 'chrome://xxx/content/yyy.js';
	  YT_global_doc.body.appendChild(script);

	}
    };

    var yt_load = function() {
        //событие загрузки вкладки с сайтом, выполняется каждый раз при загрузке страницы
        window.document.addEventListener("DOMContentLoaded", YT_loader.run, true);
    };
    //событие загрузки приватной части - выполняется один раз
    window.addEventListener("load", yt_load, false);

})();


Правильное создание новых узлов в DOM
Внутренними правилами firefox запрещено обращаться и работать с dom через innerHtml. Взамен этого необходимо пользоваться шаблонами. В своих аддонах я пользуюсь JQuery Templating.
Вот пример:
$("#pv_actions").prepend (
      $("<a>", {
	href: 	"#",
	target: "_blank",
	text:	"Загрузить оригинал",
	id:	"pv_down_link"
      })
      .css("font-weight", "bold")
      .bind("click", function (o) {
	//
      })
);


Взаимодействие с защищенной частью скрипта
Аддон состоит из 2 частей: защищенной и внедренной (небезопасной части). В безопасной части можно работать с апи браузера: сохранять файл, делать ajax запросы и т.д.
Взаимодействовать эти две изолированные части могут только по средствам событий.
Рассмотрим пример: узнать размер файла.
В незащищённой части создаем событие с нашими параметрами.
  //yt_getFileSizeEvent - название события
  var element = document.createElement("yt_getFileSizeEvent");
  element.setAttribute("attribute_url", "адрес до файла" );
  element.setAttribute("attribute_id",  "индекс файла" );
  document.documentElement.appendChild(element);
  var evt = document.createEvent("Events");
  evt.initEvent("yt_getFileSizeEvent", true, false);
  element.dispatchEvent(evt);
В защищенной части ловим событие:
document.addEventListener("yt_getFileSizeEvent", function(e) { YT_secureEvent.getFileSize(e); }, false, true);
После этого обрабатываем и повторяем все в обратном порядке, чтобы передать данные в незащищённую часть скрипта.

среда, 29 сентября 2010 г.

Кастомизация визуального редактора Bitrix

Довольно частая вещь как вставка изображения через визуальный редактор с возможностью увеличения в Bitrix никак не решена.

Можно конечно загрузить 2 варианта изображения (большое и маленькое), в текст вставить изображение превью и указать ссылку на большое. Но хотелось бы автоматизировать этот процесс.

Официальная тех. поддержка отказалась решать эту проблему, а документация не содержала списка событий. Хорошо хоть была возможность перегрузить js класс редактора (Документация). Не понятно было какой из сотен методов мне нужен.

Методом перебора был найден один интересный метод SAttr в котором происходила установка атрибутов абсолютно всех html элементов внутри редактора.
Он принимает внутрь 3 параметра: Объект, Свойство, Значение.

Приведу пример, в котором после загрузки изображения в редактор происходит вставка превью, и устанавливается ссылка на оригинал (Добавлять надо в bitrix/php_interface/init.php):
<?
//событие загрузки визуального редактора
AddEventHandler("fileman", "OnIncludeHTMLEditorScript", "OnIncludeHTMLEditorHandler"); 

//наш обработчик
function OnIncludeHTMLEditorHandler()
{
 ?>
 <script>
        //запоминаем ссылку на родителя
        SAttr_= SAttr;
 SAttr = function (e,a,v) { //элемента, свойство, значение
          //выполняем сначала родителя (устанавливаем свойства)
          this.SAttr_(e,a,v);
          //произошла установка title изображения
          //title может быть установлен при изменении или загрузке изображения
          if(a == 'title' && e.tagName == 'IMG') {
            var src = e.src;

            //формируем новое изображение
            var img = '';
            if(e.hspace > 0) img = img + ' hspace='+e.hspace;
            if(e.vspace> 0) img = img + ' vspace='+e.vspace;
            if(e.border> 0) img = img + ' border='+e.border;
            if(e.align != "") img = img + ' align="'+e.align+'"';
            //if(e.alt!= "") img = img + ' alt="'+e.alt+'"';
            if(e.title!= "") img = img + ' title="'+e.title+'"';

            //вставляем наше измененное изображение
            //я использовал плагин zoomie для jquery, без собственно ресайза изображения
            pObj.pMainObj.insertHTML('<img alt="'+src+'" class="zoomi" width='+e.width+' height='+e.height+' src="'+src+'" '+img+'>');
            
            //удаляем неизмененное изображение
            e.parentNode.removeChild(e);
          }  
 }
 </script>
 <?
}
?>

Пример работы

воскресенье, 31 января 2010 г.

Vkontakte: безопасная передача данных от клиента к серверу в iFrame приложениях

Не так давно Vkontakte ввело возможность разработки iFrame приложений. В связи с этим у многих разработчиков встал вопрос как защитить данные, передаваемые между приложением и api.

Я бы хотел предложить свое решение:
Защиту данных можно разделить на следующие аспекты:

1. Подтверждение информации о пользователе.
Чтобы получить достоверные подписанные данные о пользователе, необходимо использовать первый запрос к API в настройках приложения.
method=getProfiles&uids={viewer_id}&format=json&v=2.0
Тем самым мы получаем несколько параметров, один из которых нужный нам - viewer_id, а также сигнатуру данных (auth_key), подписанных секретным ключом, который гарантирует нам верность данных.
Т.е. на следующих этапах мы можем использовать информацию о пользователе, не боясь что данные были подменены.

2. Передача данных от пользователя к приложению
Чтобы скрыть секретный ключ и при этом иметь возможность передать данные на сервер придется использовать промежуточное звено - наш ajax обработчик.
Клиентский JavaScript:
function secureSend(_data, _callback) {
  $.ajax({
   type: "POST",
   url: "ajax.php",
   data: (_data),
   dataType: "json",
   success: function(data) {
     if(data.error != undefined) {
        error(data.error);
        return false;
     } else {
      _callback(data.response);
     }
   }
 });
}
На сервере же расположить скрипт обрабатывающий только обращения к API, которые пересылают данные от пользователя к серверу. Разрешить можно все действия, т.к. пользователя мы проверили на предыдущем этапе и уже тут он волен сколько угодно раз пересылать свои голоса к приложению :)
ajax.php, серверный скрипт
$vk_allow_methods = array("secure.withdrawVotes", "secure.getBalance");
$q = $_POST;
$d = "";
if(in_array($q['method'], $vk_allow_methods)) {
  $d = vkSend($q['method']);
}

function vkSend($method) {
  $server = "http://api.vkontakte.ru/api.php?";
  $key = "000";
  $aid = 1;
  
  $qr = array();
  $qr[] = 'method='.$method;
  $qr[] = 'api_id='.$aid;
  $qr[] = 'v=2.0';
  $qr[] = 'format=JSON';
  $qr[] = 'timestamp='.time();
  $qr[] = 'random='.rand(1, 999999);
  $qr[] = 'test_mode=1';
  sort($qr);
  
  $url4sign = implode("", $qr).$key;
  $sign     = md5($url4sign);
  $url      = implode("&", $qr)."&sig=".$sign;
  
  return file_get_contents($server.$url);
}

echo $d;

3. Передача данных от приложения к пользователю.
Такие события не должны ни в коем случае инициироваться клиентским кодом. Если необходимо перевести голоса со счета приложения на счет пользователя, то лучше воспользоваться запароленым скриптом, вызывающимся по cron или вручную администратором.

воскресенье, 29 ноября 2009 г.

Векторный графический редактор в браузере на Raphael

SVG во всю набирает обороты и уже скоро сместит с пьедестала Flash. Не буду рассказывать о преимуществах, о этом можно прочитать в википедии.
На текущий момент у SVG есть один недостаток - нет поддержки в IE. У Microsoft собственный стандарт для векторной графики в браузере - VML.
Для решения этой проблемы разработана специальная библиотека Raphael, предоставляющая общий API для построения векторной графики, не зависимо от браузера.

В свою очередь я хочу представить графический редактор для построения векторной графики на основе RaphaelJS и чистоного SVG/VML.

Пример работы:
Opera (Firefox, Chrome, Safari - аналогично)
Internet Explorer
svg, raphael, canvas
Трансформация, поворот, масштабирование, закругление:
svg, raphael, canvas, Трансформация, поворот, масштабирование, закругление
svg, raphael, canvas

Попробовать демо редактора

Для просмотра списка возможностей читайте далее.