Разработка callback-виджета от Oblax

от автора

В данной статье я хочу рассказать про мой callback-виджет, который я решил разработать для поставленной задачи!

Суть задачи заключалась в следующем:

  • 1. Разработать удобный для заказчика и клиента виджет средства связи
  • 2. Оперативно и быстро написать его
  • 3. С поддержкой Cross Domain requests
  • 4. С быстрой установкой в одну строчку кода
  • 5. Быстро настраиваемый
  • 6. E-mail рассылка

Решение:

Перед тем как начать писать код, я продумал архитектуру и из самых простых инструментов для backend я использовал php, а front-end native js + angular без использования других jquery-подобных библиотек. Для того, чтобы виджет был уникальным, каждый виджет имеет свой универсальный ключ, по которому мы и будем получать все данные по виджету.

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

Приступим к разбору узких мест!

Как выглядит код для вставки на сайт (index.html):

<script type="text/javascript" charset="utf-8" src="http://domain.ru/widget-get?key=a3234cc36aa23123456a59c281e51e50"></script> 

(key — это сгенерированный md5 ключ, по которому я получаю всю информацию по виджету, а не по ID это очень важно, а рекомендуемое место вставки это до закрываеющего тега </body>)

Как выглядит backend код написанный на php, который отдаёт нам необходимые элементы для вставки:

Обработчик:

<?php class ControllerWidgetGet extends Controller { 	public function index(){         if (isset($this->request->get['key'])){             $data['key'] = $this->db->escape($this->request->get['key']);             if ($row = $this->checkValidKey($data['key'])){                 $data['row'] = $row;                 $this->response->setOutput($this->load->view('/widget/get.tpl', $data));             }else{                 echo 'alert("Проверьте правильность вашего ключа");';             }         }     }      public function checkValidKey($key){         $query_key = $service = $this->db->query("SELECT * FROM `" . DB_PREFIX . "widget` WHERE `key_get` = '" . $key . "'");         return $query_key->row;     } } 

Шаблон (get.tpl):

document.write('<link href="http://domain.ru/widget/production/tracker.css" rel="stylesheet"/><script src="http://yastatic.net/angularjs/1.3.16/angular.min.js"></script><script src="http://domain.ru/widget/production/tracker.js"></script><div ng-app="widgetApp"><widget scolor="<?=$row['s_color'];?>" spoints="<?=$row['s_points'];?>" spmenu="<?=$row['s_p_menu'];?>" spwidget="<?=$row['s_p_widget'];?>" sworktime="<?=$row['s_work_time'];?>" key="<?=$key;?>"></widget></div>'); 

где:
<link href="http://domain.ru/widget/production/tracker.css" rel="stylesheet"/> - наши стили

<script src="http://yastatic.net/angularjs/1.3.16/angular.min.js"></script> - cdn используемая библиотека

<script src="http://domain.ru/widget/production/tracker.js"></script> - логика нашего приложения

<div ng-app="widgetApp"><widget scolor="<?=$row['s_color'];?>" spoints="<?=$row['s_points'];?>" spmenu="<?=$row['s_p_menu'];?>" spwidget="<?=$row['s_p_widget'];?>" sworktime="<?=$row['s_work_time'];?>" key="<?=$key;?>"></widget></div> - инициализация нашего angular приложения, с передаваемыми параметрами в Виджет

Читая различные маны(stackoverflow и др.) по вставке элементов в html с использованием js, железно работает только document.write. Но на этом вся история ещё не останавливается, на данный момент у нас только получилось загрузить к нам на сайт *.css, *.js, но нам также для вывода нашего виджета потребуется много html разметки, и тут стали приходить различные варианты!

Директива Angular поддерживает следующий template:

#1

.directive('myDialog', function() {   return {     templateUrl: 'http://domain.ru/my-dialog.html'   }; 

#2

.directive('myDialog', function() {   return {     template: '<div ng-controller="MyController"><h1>{{textHello}}</h1></div>'   }; 

Комментарий к #1:
Не кроссдоменное решение, он забирает методом GET .html разметку и выпадают ошибки вида:

“No ‘Access-Control-Allow-Origin’ header is present on the requested resource”

посмотрим что скажет на это stackoverflow

Комментарий к #2:
Здесь понятно, что внутри нашего /tracker.js мы не прибегаем к загрузке html с другого источника, а у нас есть возможность вставить его просто в параметр template, супер! Но казалось бы как так? Разве мы не можем сделать кроссдоменный запрос типа JSONP и забрать HTML, подумали вы? НЕТ!

Смотрим сюда stackoverflow

Просто замечтательно!

Инструменты напоследок:

Для сжатия я использовал следующий конфигурационный файл gulp.js

var gulp = require('gulp'),     minifyHTML = require('gulp-minify-html'),     sass = require('gulp-sass'); autoprefixer = require('gulp-autoprefixer'),     minifycss = require('gulp-minify-css'),     rename = require('gulp-rename'),     concat = require('gulp-concat'),     uglify = require('gulp-uglify');  gulp.task('p-ht', function() {     var opts = {         conditionals: true,         spare:true     };     return gulp.src('src/html/index.html')         .pipe(minifyHTML(opts))         .pipe(gulp.dest('dest/html/')) });  gulp.task('p-st', function() {     //return gulp.src('src/styles/main.scss')         //.pipe(sass({style: 'expanded'}))     return gulp.src('src/styles/tracker.css')         .pipe(autoprefixer('last 2 version'))         .pipe(gulp.dest('dest/styles/'))         //.pipe(rename({suffix: '.min'} ))         .pipe(minifycss())         .pipe(gulp.dest('dest/styles/')) });  gulp.task('p-sc', function() {     return gulp.src('src/scripts/*.js')         .pipe(concat('tracker.js'))         .pipe(gulp.dest('dest/scripts/'))         //.pipe(rename({suffix: '.min'}))         .pipe(uglify())         .pipe(gulp.dest('dest/scripts/')) });  gulp.task('watch', function() {     gulp.watch('src/scripts/*.js', ['p-sc']) });   gulp.task('dev', ['p-st', 'p-sc', 'watch'], function () {  });  gulp.task('build', ['p-st', 'p-sc', 'p-ht'], function () {  });  

Комментарий: при сжатии html символ одинарной кавычки экранируйте при использовании с ng-class={\’test-class\’: expression}, и следите за символами в регулярных выражениях, js-редактор обычно подсвечивает, подсвеченные символы экранируйте

Для копирования кода в буфер я использовал следующий код, расположенный на stackoverflow

Заключение:

Хотелось бы отметить для более точного понимания, данный код работает на любых сайтах, а не только на локальном! Запросы, которыми я обмениваюсь со своим сервером исключительно JSONP!

Всем удачи в разработке!

ссылка на оригинал статьи http://habrahabr.ru/post/264211/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *