Сравнить коммиты

..

4 Коммитов

15 изменённых файлов: 264 добавлений и 1 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -18,3 +18,5 @@
###< symfony/web-server-bundle ###
.idea/*
node_modules/*
package-lock.json

24
Gruntfile.js Обычный файл
Просмотреть файл

@ -0,0 +1,24 @@
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
"jquery.follow": {
src: "public/js/raw/jquery.follow.js",
dest: "public/js/jquery.follow.min.js"
}
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-internal');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-uglify-es');
grunt.registerTask('js', ['uglify']);
grunt.registerTask('default', ['js']);
};

Просмотреть файл

@ -32,4 +32,5 @@ security:
# Note: Only the *first* access control that matches will be used
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
- { path: ^/follow_plugin, roles: ROLE_USER }
- { path: ^/gif_modify, roles: ROLE_USER }

22
package.json Обычный файл
Просмотреть файл

@ -0,0 +1,22 @@
{
"name": "inforesurs-test",
"version": "0.0.1",
"devDependencies": {
"grunt": ">= 0.4.1",
"grunt-contrib-imagemin": "~3.1.0",
"grunt-contrib-internal": "~3.1.0",
"grunt-contrib-jshint": "~2.0.0",
"grunt-contrib-uglify": "~4.0.0",
"grunt-sass": "^2.1.0",
"jimp": "^0.2.28",
"node-sprite-generator": "~0.10.2",
"grunt-postcss": "~0.9.0",
"pixrem": "~4.0.1",
"cssnano": "~3.10.0",
"autoprefixer": "~8.0.0",
"grunt-contrib-clean": "^2.0.0"
},
"dependencies": {
"grunt-contrib-uglify-es": "github:gruntjs/grunt-contrib-uglify#harmony"
}
}

Двоичные данные
public/img/PHP.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 12 KiB

Двоичные данные
public/img/circle_php.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.3 KiB

Двоичные данные
public/img/original.gif Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 193 KiB

1
public/js/jquery.follow.min.js поставляемый Обычный файл
Просмотреть файл

@ -0,0 +1 @@
!function(o){o.fn.follow=function(){o(this).mouseover(function(f,e){var n;n=this,o("body").mousemove(function(f,e){o(n).offset({top:f.pageY,left:f.pageX}),o(n).click(function(){o("body").off("mousemove")})})})}}(jQuery);

18
public/js/raw/jquery.follow.js Обычный файл
Просмотреть файл

@ -0,0 +1,18 @@
(function ($) {
$.fn.follow = function () {
var $this = $(this);
function follow_mouse(obj) {
$('body').mousemove(function (e, h) {
$(obj).offset({top: e.pageY, left: e.pageX});
$(obj).click(function () {
$('body').off('mousemove')
})
})
}
$this.mouseover(function (e, h) {
follow_mouse(this);
});
};
})(jQuery);

Просмотреть файл

@ -4,6 +4,7 @@ namespace App\Controller;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Utils\GifModifier;
class IndexController extends AbstractController
{
@ -14,4 +15,55 @@ class IndexController extends AbstractController
{
return $this->render('index.html.twig');
}
/**
* @Route("/follow", name="follow_page", methods={"GET"})
*/
public function follow()
{
return $this->render('follow.html.twig');
}
/**
* @Route("/gif_modify", name="gif_page", methods={"GET"})
*/
public function gifModify()
{
return $this->render('gif_modify.html.twig', [
'result' => false,
]);
}
/**
* @Route("/gif_modify/process", name="gif_process_page", methods={"GET"})
*/
public function gifModifyProcess()
{
$img_dir = dirname(dirname(__DIR__)).'/public/img/';
$gifModify = new GifModifier();
$gifModify->modify($img_dir.'original.gif', 180, 146, $img_dir.'PHP.png', 36, 52, $img_dir.'out_180_146.gif');
$gifModify->modify($img_dir.'original.gif', 300, 243, $img_dir.'circle_php.png', 88, 152, $img_dir.'out_300_243.gif');
return $this->redirectToRoute('gif_result_page');
}
/**
* @Route("/gif_modify/results", name="gif_result_page", methods={"GET"})
*/
public function gifModifyResults()
{
return $this->render('gif_modify.html.twig', [
'result' => true,
'images' => [
[
'x' => 180,
'y' => 146,
],
[
'x' => 300,
'y' => 243,
],
],
]);
}
}

Просмотреть файл

@ -41,6 +41,9 @@ class UserController extends AbstractController
$passwordEncoder->encodePassword($user, $user->getPassword())
);
$user->setActive((bool) $form->get('active')->getData())
->setRoles($form->get('roles')->getData());
$entityManager->persist($user);
$entityManager->flush();

54
src/Utils/GifModifier.php Обычный файл
Просмотреть файл

@ -0,0 +1,54 @@
<?php
/**
* Ресайз и наложение ватермарки на прозрачную анимированную гифку.
*/
namespace App\Utils;
use Imagick;
/**
* Class GifModifier.
*
* Ресайз и наложение ватермарки на прозрачную анимированную гифку
*/
class GifModifier
{
/**
* Ресайз и наложение ватермарки на прозрачную анимированную гифку.
*
* @param string $filename Путь к исходному gif-файлу
* @param int $width Новый размер по горизонтали
* @param int $height Новый размер по вертикале
* @param string $watermarkFilename Путь к водному знаку. gif или png
* @param int $watermarkX Позиция водного знака по горизонтали
* @param int $watermarkY Позиция водного знака по вертикали
* @param string $outFilename Путь для записи результата
*/
public function modify(string $filename, int $width, int $height, string $watermarkFilename, int $watermarkX, int $watermarkY, string $outFilename)
{
$watermark = new Imagick();
$watermark->readImage($watermarkFilename);
$gifFile = new Imagick($filename);
$fileFormat = $gifFile->getImageFormat();
if ('GIF' == $fileFormat) {
$frames = $gifFile->coalesceImages();
foreach ($frames as $frame) {
$frame->resizeImage($width, $height, Imagick::FILTER_LANCZOS, 1);
$frame->compositeImage($watermark, Imagick::COMPOSITE_OVER, $watermarkX, $watermarkY);
}
$out_file = $frames->deconstructImages();
$out_file->writeImages($outFilename, true);
$out_file->clear();
}
$gifFile->clear();
$watermark->clear();
}
}

51
templates/follow.html.twig Обычный файл
Просмотреть файл

@ -0,0 +1,51 @@
{% extends "base.html.twig" %}
{% block title %}
Плагин follow
{% endblock %}
{% block body %}
<div class="container">
<a href="{{ path('index_page') }}" class="btn btn-primary mb-5">← Главная</a>
<p>But I must explain to you how all this mistaken idea of denouncing
pleasure and <span class="text-info js-follow">praising</span> pain
was born and I will give you a complete account of the system, and
expound the actual teachings of the great explorer of the truth, the
master-builder of human happiness. No one rejects, dislikes, or
avoids pleasure itself, because it is pleasure, but because those
who do not know how to pursue pleasure rationally encounter
consequences that are extremely painful. Nor again is there anyone
who loves or pursues or desires to obtain pain of itself, because it
is pain, but because occasionally circumstances occur in which toil
and pain can procure him some great pleasure. To take a trivial
example, which of us ever undertakes laborious physical exercise,
except to obtain some advantage from it? But who has any right to
find fault with a man who chooses to enjoy a pleasure that has no
annoying consequences, or one who avoids a pain that produces no
resultant pleasure?</p>
<p><span class="text-success js-follow">follow</span></p>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui
blanditiis <span class="text-danger js-follow">praesentium</span>
voluptatum deleniti atque corrupti quos dolores et quas molestias
excepturi sint occaecati cupiditate non provident, similique sunt in
culpa qui officia deserunt mollitia animi, id est laborum et dolorum
fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam
libero tempore, cum soluta nobis est eligendi optio cumque nihil
impedit quo minus id quod maxime placeat facere possimus, omnis
voluptas assumenda est, omnis dolor repellendus. Temporibus autem
quibusdam et aut officiis debitis aut rerum necessitatibus saepe
eveniet ut et voluptates repudiandae sint et molestiae non
recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut
aut reiciendis voluptatibus maiores alias consequatur aut
perferendis doloribus asperiores repellat.</p>
</div>
{% endblock %}
{% block javascripts %}
<script src="/js/jquery.follow.min.js"></script>
<script>
(function ($) {
$(function () {
$(".js-follow").follow();
});
})(jQuery);
</script>
{% endblock %}

27
templates/gif_modify.html.twig Обычный файл
Просмотреть файл

@ -0,0 +1,27 @@
{% extends "base.html.twig" %}
{% block title %}
Ресайз и наложение ватермарки{% if result == true %} (Результат){% endif %}.
{% endblock %}
{% block body %}
<div class="container">
{% if result == false %}
<a href="{{ path('index_page') }}" class="btn btn-primary mb-5">← Главная</a>
<br>
<a href="{{ path("gif_process_page") }}" class="btn btn-success js-gif">Изменить gif</a>
{% else %}
<a href="{{ path('gif_page') }}" class="btn btn-primary mb-5">← Страница изменения gif</a>
<br>
<div class="h3 mb-5">original.gif</div>
<img src="/img/original.gif" alt="" width="350" height="284" class="img-thumbnail">
<div class="h3 mb-5">circle_php.png</div>
<img src="/img/circle_php.png" height="50" width="50" class="img-thumbnail">
<div class="h3 mb-5">PHP.png</div>
<img src="/img/PHP.png" width="80" height="42" class="img-thumbnail">
{% for image in images %}
<hr>
<div class="h3 mb-5">out_{{ image.x }}_{{ image.y }}.gif</div>
<img src="/img/out_{{ image.x }}_{{ image.y }}.gif" alt="" width="{{ image.x }}" height="{{ image.y }}" class="img-thumbnail mb-5">
{% endfor %}
{% endif %}
</div>
{% endblock %}

Просмотреть файл

@ -10,6 +10,14 @@
<a href="{{ path('app_logout') }}" class="btn btn-primary">Выйти</a>
{% endif %}
<br class="mb-5">
{% if is_granted('ROLE_USER') %}
<a href="{{ path('follow_page') }}" class="btn btn-primary mb-1">Плагин follow</a>
<br>
<a href="{{ path('gif_result_page') }}" class="btn btn-primary mb-1">Результат изменения gif</a>
<br>
<a href="{{ path('gif_page') }}" class="btn btn-primary mb-1">Страница изменения gif</a>
<br>
{% endif %}
{% if is_granted('ROLE_ADMIN') %}
<a href="{{ path('user_index') }}" class="btn btn-primary">Список пользователей</a>
{% endif %}