├── files
├── 01
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 02
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 03
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 04
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 05
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 06
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 07
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── 08
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
└── 09
│ ├── mainimage.jpg
│ ├── mainimage-min.jpg
│ └── mainimage-slide.jpg
├── images
├── noimage-min.jpg
├── socialimage.png
├── icons
│ ├── favicon.ico
│ ├── adminfavicon.png
│ └── favicon-32x32.png
├── noimage-slide.jpg
├── backgrounds
│ └── logo.png
├── general
│ └── ajax-loader.gif
└── mediadescription
│ ├── i-bold.png
│ ├── i-center.png
│ ├── i-italic.png
│ ├── i-link.png
│ ├── i-reset.png
│ └── i-strong.png
├── README.md
├── html-admin
├── login.html
├── articles.html
├── categories.html
├── editcategory.html
└── editarticle.html
├── scripts
├── client
│ └── main.js
└── admin
│ ├── login.js
│ ├── error.js
│ ├── aliasmaker.js
│ ├── click-actions.js
│ ├── images-actions.js
│ ├── tags.js
│ ├── categories.js
│ ├── articles.js
│ ├── mediadescription.js
│ └── texthighlighter
│ ├── jquery.texthighlighter.js
│ └── rangy-core.js
├── html-client
├── 404.html
├── article.html
└── index.html
└── styles
├── main.css
└── admin.css
/files/01/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/01/mainimage.jpg
--------------------------------------------------------------------------------
/files/02/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/02/mainimage.jpg
--------------------------------------------------------------------------------
/files/03/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/03/mainimage.jpg
--------------------------------------------------------------------------------
/files/04/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/04/mainimage.jpg
--------------------------------------------------------------------------------
/files/05/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/05/mainimage.jpg
--------------------------------------------------------------------------------
/files/06/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/06/mainimage.jpg
--------------------------------------------------------------------------------
/files/07/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/07/mainimage.jpg
--------------------------------------------------------------------------------
/files/08/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/08/mainimage.jpg
--------------------------------------------------------------------------------
/files/09/mainimage.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/09/mainimage.jpg
--------------------------------------------------------------------------------
/images/noimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/noimage-min.jpg
--------------------------------------------------------------------------------
/images/socialimage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/socialimage.png
--------------------------------------------------------------------------------
/files/01/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/01/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/02/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/02/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/03/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/03/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/04/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/04/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/05/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/05/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/06/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/06/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/07/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/07/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/08/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/08/mainimage-min.jpg
--------------------------------------------------------------------------------
/files/09/mainimage-min.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/09/mainimage-min.jpg
--------------------------------------------------------------------------------
/images/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/icons/favicon.ico
--------------------------------------------------------------------------------
/images/noimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/noimage-slide.jpg
--------------------------------------------------------------------------------
/files/01/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/01/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/02/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/02/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/03/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/03/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/04/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/04/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/05/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/05/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/06/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/06/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/07/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/07/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/08/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/08/mainimage-slide.jpg
--------------------------------------------------------------------------------
/files/09/mainimage-slide.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/files/09/mainimage-slide.jpg
--------------------------------------------------------------------------------
/images/backgrounds/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/backgrounds/logo.png
--------------------------------------------------------------------------------
/images/general/ajax-loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/general/ajax-loader.gif
--------------------------------------------------------------------------------
/images/icons/adminfavicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/icons/adminfavicon.png
--------------------------------------------------------------------------------
/images/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/images/mediadescription/i-bold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/mediadescription/i-bold.png
--------------------------------------------------------------------------------
/images/mediadescription/i-center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/mediadescription/i-center.png
--------------------------------------------------------------------------------
/images/mediadescription/i-italic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/mediadescription/i-italic.png
--------------------------------------------------------------------------------
/images/mediadescription/i-link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/mediadescription/i-link.png
--------------------------------------------------------------------------------
/images/mediadescription/i-reset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/mediadescription/i-reset.png
--------------------------------------------------------------------------------
/images/mediadescription/i-strong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/droganaida/javascript-frontend/HEAD/images/mediadescription/i-strong.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Клиентская часть проекта для учебного курса «JavaScript. Практическое занятие.» https://www.youtube.com/playlist?list=PLOzk9ZaOL1u1U07cey-7GYBVE72wu8EAH
2 |
--------------------------------------------------------------------------------
/html-admin/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | )
6 | //*********** Присутствует на всех страницах админ-панели
7 | //=========== ВЫЗОВ
8 | //*********** showError(text, top) - сообщеие об ошибке
9 | //*********** showSuccess(text, top) - сообщеие об успешном завершении
10 | //=========== ПАРАМЕТРЫ
11 | //*********** text - сообщение в окне
12 | //*********** top - отступ от верха страницы (px)
13 | //================================================================//
14 |
15 | //==============================================================//
16 | //*********** hideError - скрыть сообщение об ошибке ***********//
17 | //==============================================================//
18 |
19 | var timer = null;
20 |
21 | function hideError(){
22 |
23 | //------------ очищаем таймер
24 | if (timer != null){
25 | window.clearTimeout(timer);
26 | }
27 |
28 | //------------ таймаут на 5 секунд
29 | timer = window.setTimeout(function(){
30 | $('.error-holder').fadeOut();
31 | }, 5000);
32 | }
33 |
34 | //==============================================================//
35 | //********** showError - показать сообщение об ошибке **********//
36 | //==============================================================//
37 | function showError(text, top){
38 |
39 | $('.error-holder').removeClass('error-holder-success');
40 | $('.error-holder').css({"top":"" + top + "px", "z-index":"999999"});
41 | $('.error-holder span').text(text);
42 |
43 | $('.error-holder').fadeIn(function(){
44 | hideError();
45 | });
46 | }
47 |
48 | //==============================================================//
49 | //******* showSuccess - сообщение об успешном завершении *******//
50 | //==============================================================//
51 | function showSuccess(text, top){
52 |
53 | $('.error-holder').addClass('error-holder-success');
54 | $('.error-holder').css({"top":"" + top + "px", "z-index":"999999"});
55 | $('.error-holder span').text(text);
56 |
57 | $('.error-holder').fadeIn(function(){
58 | hideError();
59 | });
60 | }
61 |
62 | $(document).ready(function(){
63 |
64 | //=============== Скрыть сообщение по клику =================//
65 | $('.error-holder').on("click", function(){
66 | $(this).fadeOut();
67 | });
68 |
69 | });
--------------------------------------------------------------------------------
/scripts/admin/aliasmaker.js:
--------------------------------------------------------------------------------
1 |
2 | //================================================================//
3 | //*********** aliasmaker.js ***********//
4 | //*********** © Aida Drogan - #BlondieCode
5 | //*********** Функция для транслитерации русских заголовков в ссылки
6 | //=========== ВЫЗОВ
7 | //*********** Наличие у элемента-инпута id="alias"
8 | //================================================================//
9 |
10 | $(document).ready(function(){
11 |
12 | //================================================================//
13 | //*********** Input Focus ***********//
14 | //================================================================//
15 | $('body').on('focus', '#alias', function(){
16 |
17 | if ($(this).val() == ""){
18 |
19 | var text = $('#title').val();
20 |
21 | text = text.replace(/ /g, "-").toLowerCase();
22 | text = text.replace(/\./g, "-");
23 | text = text.replace(/:/g, "");
24 | text = text.replace(/,/g, "");
25 | text = text.replace(/;/g, "");
26 |
27 | text = text.replace(/а/g, "a");
28 | text = text.replace(/б/g, "b");
29 | text = text.replace(/в/g, "v");
30 | text = text.replace(/г/g, "g");
31 | text = text.replace(/д/g, "d");
32 | text = text.replace(/е/g, "e");
33 | text = text.replace(/ё/g, "yo");
34 | text = text.replace(/ж/g, "j");
35 | text = text.replace(/з/g, "z");
36 | text = text.replace(/и/g, "i");
37 | text = text.replace(/й/g, "i");
38 | text = text.replace(/к/g, "k");
39 | text = text.replace(/л/g, "l");
40 | text = text.replace(/м/g, "m");
41 | text = text.replace(/н/g, "n");
42 | text = text.replace(/о/g, "o");
43 | text = text.replace(/п/g, "p");
44 | text = text.replace(/р/g, "r");
45 | text = text.replace(/с/g, "s");
46 | text = text.replace(/т/g, "t");
47 | text = text.replace(/у/g, "u");
48 | text = text.replace(/ф/g, "f");
49 | text = text.replace(/х/g, "h");
50 | text = text.replace(/ц/g, "c");
51 | text = text.replace(/ч/g, "ch");
52 | text = text.replace(/ш/g, "sh");
53 | text = text.replace(/щ/g, "sch");
54 | text = text.replace(/ъ/g, "");
55 | text = text.replace(/ы/g, "y");
56 | text = text.replace(/ь/g, "");
57 | text = text.replace(/э/g, "e");
58 | text = text.replace(/ю/g, "yu");
59 | text = text.replace(/я/g, "ya");
60 |
61 | $(this).val(text);
62 | }
63 | });
64 | });
--------------------------------------------------------------------------------
/scripts/admin/click-actions.js:
--------------------------------------------------------------------------------
1 |
2 | //================================================================//
3 | //*********** click-action.js ***********//
4 | //*********** © Aida Drogan - #BlondieCode
5 | //*********** Описывает клики по общим элементам админ-панели
6 | //*********** Кнопка ОТМЕНА на pop-up окнах (class="p-cancel")
7 | //*********** Элементы-чекеры с кастомным интерфейсом (checkbox, radio button)
8 | //*********** Раздвижной элемент "баян"
9 | //================================================================//
10 |
11 | $(document).ready(function(){
12 |
13 | //================================================================//
14 | //*********** ОТМЕНА на pop-up окнах ***********//
15 | //================================================================//
16 |
17 | $('body').on('click', '.p-cancel', function(){
18 | $('.popup-holder.dynamic').fadeOut('fast', function(){
19 | $(this).remove();
20 | });
21 | });
22 |
23 | //================================================================//
24 | //*********** CHECKERS ***********//
25 | // --- атрибут data-relna с именем класса элемента,
26 | // --- который нужно переключить в неактивное состоянии (стилевой класс .na)
27 | // --- при выборе элемента-чекера
28 |
29 | // --- класс .single назначается родительскому элементу,
30 | // --- в котором может быть только один активный чекер (поведение радио-кнопок)
31 | //================================================================//
32 |
33 | $('body').on('click', '.checker', function(){
34 | $(this).toggleClass('active');
35 | var relative = $(this).attr('data-relna');
36 | if (relative){
37 | $('.' + relative).toggleClass('na');
38 | }
39 | });
40 |
41 | $('.check-holder').on('click', '.check', function(){
42 | if (!$(this).parent('.check-holder').hasClass('na')){
43 | if ($(this).parents('.check-holder').hasClass('single')){
44 | $(this).parents('.check-holder').find('.check').removeClass('active');
45 | $(this).addClass('active');
46 | } else {
47 | $(this).toggleClass('active');
48 | }
49 | }
50 | });
51 |
52 | //================================================================//
53 | //*********** БАЯН ***********//
54 | // --- класс элемента open-bayan
55 | // --- тело баяна следующий за .open-bayan элемент
56 | // --- класс up - стилевое оформление открытого баяна
57 | //================================================================//
58 |
59 | $('body').on('click', '.open-bayan', function(){
60 |
61 | if ($(this).hasClass('up')){
62 | $(this).next().slideUp('fast');
63 | $(this).removeClass('up');
64 | } else {
65 | $(this).addClass('up');
66 | $(this).next().slideDown('fast');
67 | }
68 | });
69 | });
--------------------------------------------------------------------------------
/scripts/admin/images-actions.js:
--------------------------------------------------------------------------------
1 |
2 | //================================================================//
3 | //*********** images-actions.js ***********//
4 | //*********** © Aida Drogan - #BlondieCode
5 | //*********** Работа с изображениями
6 | //*********** Запись файла в глобальную переменную globalArticleMainImageFileNameToUpload
7 | //*********** Предпросмотр изображения
8 | //*********** Удаление изображения
9 | //================================================================//
10 |
11 | //====================== Переменные ===========================//
12 |
13 | var globalArticleMainImageFileNameToUpload = null;
14 |
15 |
16 | //====================== Предпросмотр изображения ===========================//
17 |
18 | function uploadMainArticleImg(file){
19 |
20 | //------- передаем файл в глобальную переменную
21 | globalArticleMainImageFileNameToUpload = file;
22 |
23 | //------- если файл есть, передаем его в FileReader
24 | if (file != undefined){
25 | if (!file.type.match('image.*')) {
26 | showError('File type should be an image', 'popup');
27 | return;
28 | }
29 |
30 | var reader = new FileReader();
31 | reader.onload = (function(file){
32 |
33 | return function(e){
34 |
35 | //------- после того, как FileReader распознал файл отображаем его в элементе .imgarticle
36 | if ($('.logo-holder.imgarticle img').length){
37 |
38 | $('.logo-holder.imgarticle img').fadeOut('fast', function(){
39 | $('.logo-holder.imgarticle').append('
');
40 | $(this).remove();
41 | });
42 | } else {
43 | $('.logo-holder.imgarticle').append('
');
44 | }
45 | };
46 | })(file);
47 | reader.readAsDataURL(file);
48 | }
49 | }
50 |
51 |
52 | $(document).ready(function(){
53 |
54 | //------- клик по кнопке выбора изображения (инициируем клик по скрытому инпуту)
55 | $('body').on('click', '#main-article-img', function(){
56 | $('#imgarticle').click();
57 | });
58 |
59 | //------- выбор изображение при помощи инпута с типом "файл"
60 | $('body').on('change', '#imgarticle', function(f){
61 |
62 | var files = f.target.files;
63 | var file = files[0];
64 |
65 | uploadMainArticleImg(file);
66 |
67 | });
68 |
69 | //====================== Удаление изображения ===========================//
70 |
71 | $('#del-main-img').on('click', function(){
72 |
73 | //------- проверяем, есть ли что удалять (изображение в виджете и это не noimage)
74 | if ($('.logo-holder img').length && ($('.logo-holder img').attr('src').indexOf('noimage') == -1)){
75 |
76 | $('.logo-holder img').fadeOut('fast', function(){
77 |
78 | globalArticleMainImageFileNameToUpload = null;
79 | //------- добавляем класс на кнопку edit-article, отмечаем, что старое изображение нужно удалить
80 | $('#edit-article').addClass('todelete');
81 | $(this).remove();
82 | });
83 |
84 | $('.logo-holder').append('
');
85 | }
86 | });
87 | });
--------------------------------------------------------------------------------
/html-client/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
BlondieBlog 404. Жаль, что ничего здесь нет
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
47 |
48 |
49 |
50 |
51 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
Ничего не найдено по вашему запросу
70 |
Попробуйте сформулировать иначе
71 |
72 |
73 |
74 |
75 |
76 |
77 |
85 | #BlondieCode © 2017
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/scripts/admin/tags.js:
--------------------------------------------------------------------------------
1 |
2 | //================================================================//
3 | //*********** tags.js ***********//
4 | //*********** © Aida Drogan - #BlondieCode
5 | //*********** Виджет с автоподстановкой и заполнением тегов
6 | //================================================================//
7 |
8 | //======================= ПАРАМЕТРЫ =====================//
9 | // iInput - элемент для ввода тега
10 | // iContainer - панель для вывода результатов подстановки
11 | // iContainerClass - класс панели для вывода результатов подстановки (String)
12 | // iTagHolder - контейнер для выгрузки выбранных тегов
13 | // iItemClass - класс элемента с тегом в контейнере
14 | // iRoute - роут для ajax-запроса к серверу (совпадение тегов для постановки)
15 |
16 | function tagMeBabe(iInput, iContainer, iContainerClass, iTagHolder, iItemClass, iRoute){
17 |
18 | //------------ функция добавления тега в контейнер
19 | function appendTag(tag){
20 |
21 | var toAppend = true;
22 | iInput.val('');
23 |
24 | iTagHolder.find('.' + iItemClass).each(function(){
25 |
26 | //------------ проверяем теги на дубли
27 | if ($(this).text() == tag){
28 | $(this).addClass('double');
29 | toAppend = false;
30 | } else {
31 | $(this).removeClass('double');
32 | }
33 | });
34 |
35 | if (toAppend) {
36 | iTagHolder.prepend('' + result[i] + '')
58 | }
59 | if (iContainer.children().length > 0){
60 | iContainer.slideDown(200);
61 | } else {
62 | iContainer.slideUp(10);
63 | }
64 | }
65 | }
66 |
67 | iInput.on('focus', function(){
68 | checkTag($(this));
69 | });
70 |
71 | iInput.on('keyup', function(e){
72 |
73 | var tag = $(this).val();
74 | var input = $(this);
75 |
76 | //------------ навигация по панели подстановки
77 | if (e.keyCode == 40) {
78 |
79 | if (iContainer.find('.active').length > 0){
80 | iContainer.find('.active').removeClass('active').next().addClass('active');
81 | } else {
82 | iContainer.find('span:first').addClass('active');
83 | }
84 |
85 | input.val(iContainer.find('.active').text());
86 |
87 | } else if (e.keyCode == 38) {
88 |
89 | if (iContainer.find('.active').length > 0){
90 | iContainer.find('.active').removeClass('active').prev().addClass('active');
91 | } else {
92 | iContainer.find('span:last').addClass('active');
93 | }
94 |
95 | input.val(iContainer.find('.active').text());
96 |
97 | } else if (e.keyCode == 13){
98 |
99 | appendTag(tag);
100 | iContainer.slideUp(10);
101 |
102 | } else {
103 |
104 | checkTag(input);
105 | }
106 | });
107 |
108 | //------------ удаляем тег из контейнера по клику
109 | iTagHolder.on('click', '.' + iItemClass, function(){
110 | $(this).fadeOut(100, function(){
111 | $(this).remove();
112 | });
113 | });
114 |
115 | //------------ переносим тег в контейнер из панели подстановки
116 | iContainer.on('click', 'span', function(){
117 | appendTag($(this).text());
118 | iContainer.slideUp(10);
119 | });
120 |
121 | //------------ закрываем панель подстановки по клику в любое место документа
122 | $(document).mousedown(function(e){
123 |
124 | if (!$(e.target).is('span') && (!$(e.target).parent().hasClass(iContainerClass))){
125 | iContainer.slideUp(10, function(){
126 | iContainer.children().remove();
127 | });
128 | }
129 | });
130 | }
--------------------------------------------------------------------------------
/html-admin/articles.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Админ-панель
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Вы вошли как superadmin
16 |
20 |
21 |
22 |
23 |
24 |
25 | Error
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
Любовь к няшным котикам
42 |
43 | Создана: Вт, 31. Янв 2017, в 19:9
44 | Обновлена: Пт, 10. Фев 2017, в 16:56
45 |
46 |
47 | Не опубликована
48 |
49 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
Что можно сделать из пластиковой бутылки
59 |
60 | Создана: Пт, 27. Янв 2017, в 21:59
61 | Обновлена: Пн, 30. Янв 2017, в 18:40
62 |
63 |
64 | Опубликована
65 |
66 |
69 |
70 |
71 |
72 |
73 |
74 |
Тима и Няша в детстве
75 |
76 | Создана: Пт, 27. Янв 2017, в 21:59
77 | Обновлена: Пт, 27. Янв 2017, в 22:3
78 |
79 |
80 | Опубликована
81 |
82 |
85 |
86 |
87 |
88 |
89 |
90 |
Как Боня читал сценарий к этому видео
91 |
92 | Создана: Пт, 27. Янв 2017, в 18:43
93 | Обновлена: Пт, 27. Янв 2017, в 21:46
94 |
95 |
96 | Опубликована
97 |
98 |
101 |
102 |
103 |
104 |
105 |
106 | #BlondieCode © 2017
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/html-admin/categories.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Админ-панель
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
Вы вошли как superadmin
21 |
25 |
26 |
27 |
28 |
29 |
30 | Error
31 |
32 |
33 |
34 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | Добро пожаловать на BlondieBlog
44 | Главная страница (0 статей)
45 |
46 |
49 |
50 |
51 |
52 |
53 |
54 | Няшные котики
55 | 4 статьи
56 |
57 |
61 |
62 |
63 |
64 |
65 | Боня - король вечеринок
66 | 4 статьи
67 |
68 |
72 |
73 |
74 |
75 | Настоящие леди
76 | 3 статьи
77 |
78 |
82 |
83 |
84 |
85 | Коты - спасение человечества
86 | 6 статей
87 |
88 |
92 |
93 |
94 |
95 | Кошачий вопрос
96 | 4 статьи
97 |
98 |
102 |
103 |
104 |
105 | Без кота жизнь не та
106 | 8 статей
107 |
108 |
112 |
113 |
114 |
115 | Кот - это на всю жизнь
116 | 5 статей
117 |
118 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | #BlondieCode © 2017
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/html-admin/editcategory.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Админ-панель
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Вы вошли как superadmin
24 |
28 |
29 |
30 |
31 |
32 |
33 | Error
34 |
35 |
36 |
37 |
38 |
43 |
44 |
45 |
46 |
47 |
48 | Заголовок категории
49 |
50 |
51 |
52 | URL категории (без домена и /)
53 |
54 |
55 |
56 | Заголовок категории в меню
57 |
58 |
59 |
60 |
74 |
75 |
76 |
77 |
78 | Главная страница
79 |
80 |
81 |
82 | Краткое описание
83 |
84 |
85 |
86 |
87 |
Текст на странице категории
88 |
89 |
90 |
91 |
92 |
93 |
94 |
История модерации:
95 |
96 |
97 |
superadmin
98 |
99 | Создана: Чт, 26. Янв 2017, в 20:24
100 |
101 |
102 |
103 |
superadmin
104 |
105 | Отмодерирована: Пт, 27. Янв 2017, в 22:22
106 |
107 |
108 |
109 |
superadmin
110 |
111 | Отмодерирована: Пн, 30. Янв 2017, в 18:39
112 |
113 |
114 |
115 |
superadmin
116 |
117 | Отмодерирована: Вт, 31. Янв 2017, в 20:22
118 |
119 |
120 |
121 |
superadmin
122 |
123 | Отмодерирована: Вт, 07. Фев 2017, в 11:0
124 |
125 |
126 |
127 |
128 |
129 |
130 |
138 |
139 |
140 |
141 |
142 | #BlondieCode © 2017
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/html-admin/editarticle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Админ-панель
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Вы вошли как superadmin
25 |
29 |
30 |
31 |
32 |
33 |
34 | Error
35 |
36 |
37 |
38 |
39 |
44 |
45 |
46 |
47 |
Главное изображение
48 |
49 |
50 |
51 |
52 |
+ Добавить
53 |
Удалить
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | Название статьи
63 |
64 |
65 |
66 | URL страницы (без домена и /)
67 |
68 |
69 |
81 |
82 |
108 |
109 |
110 | Краткое описание
111 |
112 |
113 |
114 |
115 |
Текст на странице статьи
116 |
117 |
118 |
119 |
120 |
121 |
122 |
История модерации:
123 |
124 |
125 |
superadmin
126 |
127 | Создана: Пт, 27. Янв 2017, в 18:43
128 |
129 |
130 |
131 |
132 |
superadmin
133 |
134 | Отмодерирована: Пт, 27. Янв 2017, в 21:46
135 |
136 |
137 |
138 |
139 |
140 |
141 |
149 |
150 |
151 |
152 |
153 | #BlondieCode © 2017
154 |
155 |
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/html-client/article.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Боня читал сценарий
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
47 |
48 |
49 |
50 |
51 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Добавлена: Пт, 27. Янв 2017
74 | Просмотров: 222
75 |
76 |
Как Боня читал сценарий к этому видео
77 | Я подошла к дивану. и мое сердце замерло.
78 |
Он лежал и не двигался .
79 | Его белое мохнатое тельце с серыми пятнышками застыло, и только редкие вздохи выдавали в нем живое существо.
80 | Я наклонилась и спросила:
81 |
82 | - Боня! Боня! Что с тобой?..
83 |
84 | Но Боня не отвечал. Я потрясла его, и он устало поднял на меня глаза.
85 |
86 |
- Что за фигню ты написала , двуногая? - спросил он и потянулся.
87 |
88 | - Я... Я просто хотела донести до людей, что программирование это прекрасно...
89 |
90 | - Программирование - это туфта! - перебил меня Боня, - Прекрасно - это колбаса!
91 |
92 | Он отвернулся от меня и устроился поудобнее на распечатках сценария к
очередной серии .
93 | Я присела рядом, и чувство пустоты наполнило мою грудь. Колбаса... Как много в этом слове.
94 |
И что же они добавляют в эту колбасу, если я начала понимать кошек...
95 | Только ветер в трубах продолжал монотонно завывать, да тиканье часов на стене отражалось в моей голове.
96 | Боня так и не повернул ко мне совей прекрасной мордашки, и не сдвинул свою задницу с моих распечаток...
97 |
98 |
99 |
100 |
101 |
134 |
135 |
136 |
137 |
138 |
139 |
147 | #BlondieCode © 2017
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/scripts/admin/categories.js:
--------------------------------------------------------------------------------
1 |
2 | //================================================================//
3 | //*********** categories.js ***********//
4 | //*********** © Aida Drogan - #BlondieCode
5 | //*********** Логика работы с категориями
6 | //*********** Создание новой категории
7 | //*********** Сортировка категорий drag-n-drop (ui-sortable)
8 | //*********** Удаление категории
9 | //*********** Редактирование категории
10 | //================================================================//
11 |
12 | $(document).ready(function(){
13 |
14 | //================================================================//
15 | //*********** Создание новой категории ***********//
16 | //================================================================//
17 |
18 | $('#b-new-category').on('click', function(){
19 |
20 | //------------ pop-up форма для ввода данных
21 |
22 | $('body').append(''
37 | );
38 |
39 | $('.popup-holder.dynamic').fadeIn();
40 |
41 | });
42 |
43 | //------------ клик по кнопке Сохранить на pop-up форме
44 |
45 | $('body').on('click', '#save-category', function(){
46 |
47 | var button = $(this);
48 |
49 | if (!button.hasClass('working')){
50 |
51 | button.addClass('working');
52 |
53 | //------------ данные для ajax-запроса
54 | var data = {};
55 | data.title = $('#title').val(); // заголовок категории
56 | data.alias = $('#alias').val(); // алиас (url страницы)
57 | data.pos = $('#sortable li').length; // позиция в слайдере
58 |
59 | if (data.title.length == 0){
60 | showError('Пожалуйста введите заголовок категории!', 'popup');
61 | button.removeClass('working');
62 | } else if (data.alias.length == 0){
63 | showError('Пожалуйста введите роут!', 'popup');
64 | button.removeClass('working');
65 | } else {
66 |
67 | //------------ ajax-запрос на сохранение категории
68 |
69 | //------------ по завершении ajax-запроса
70 | //------------ result - ответ от сервера (сохраненная категория)
71 |
72 | var result = '' +
73 | '' +
74 | '' + data.title + ' ' +
75 | '0 статьи ' +
76 | '
' +
77 | '' +
81 | ' ';
82 |
83 | button.removeClass('working');
84 | $('.popup-holder.dynamic').fadeOut('fast', function(){
85 | $(this).remove();
86 | });
87 | $('#sortable').append(result);
88 | }
89 | }
90 | });
91 |
92 | //================================================================//
93 | //*********** Сортировка категорий ***********//
94 | //================================================================//
95 |
96 | function sortItems(){
97 | $('.ui-sortable-handle').each( function(){
98 |
99 | //------------ данные для ajax-запроса
100 | var data = {};
101 | data.pos = $(this).prevAll().length; // позиция в слайдере
102 |
103 | //------------ ajax-запрос на смену позиции категории (сортировка)
104 | })
105 | }
106 |
107 | if ($('#sortable').length){
108 |
109 | //------------ объявляем ui-sortable
110 |
111 | $('#sortable').sortable({
112 | deactivate: function(event, ui){
113 | sortItems();
114 | },
115 | placeholder: "ui-state-highlight"
116 | });
117 |
118 | //------------ отключаем выделение текста
119 | $('#sortable').disableSelection();
120 | }
121 |
122 |
123 | //================================================================//
124 | //*********** Удаление категории ***********//
125 | //================================================================//
126 |
127 | $('#delete-category').on('click', function(){
128 |
129 | $('body').append(''
140 | );
141 |
142 | $('.popup-holder.dynamic').fadeIn();
143 |
144 | });
145 |
146 | $('body').on('click', '#yes-delete-category', function(){
147 |
148 | var button = $(this);
149 |
150 | if (!button.hasClass('working')){
151 |
152 | button.addClass('working');
153 |
154 | //------------ ajax-запрос на удаление категории
155 |
156 | }
157 | });
158 |
159 |
160 | //================================================================//
161 | //*********** Редактирование категории ***********//
162 | //================================================================//
163 |
164 | //------------------ подключение плагина mediadescription
165 |
166 | var mediaElement = null;
167 |
168 | if ($('.mediaelement').length){
169 |
170 | var insidedescription = $('.mediaelement').find('.mediacontent').html();
171 |
172 | mediaElement = $('.mediaelement').makemediadescription({
173 | insidedescription:insidedescription
174 | });
175 |
176 | //-------------- подтвердить перезагрузку окна\ уход со страницы
177 |
178 | window.onbeforeunload = function() {
179 |
180 | if (!$('#deleted').length){
181 | return 'Ты сохранил все изменения?';
182 | }
183 | };
184 | }
185 |
186 | $('#edit-category').on('click', function(){
187 |
188 | var button = $(this);
189 |
190 | if (!button.hasClass('working')){
191 |
192 | button.addClass('working');
193 |
194 | //------------ данные для ajax-запроса
195 | var data = {};
196 | data.title = $('#title').val();
197 | data.shortdescription = $('#shortdescription').val();
198 | data.htmltitle = $('#htmltitle').val();
199 | data.htmldescription = $('#htmldescription').val();
200 | data.htmlkeywords = $('#htmlkeywords').val();
201 | data.alias = $('#alias').val();
202 | data.menutitle = $('#menutitle').val();
203 | data.moderator = $('#moderator').text();
204 |
205 | var ismain = 'false';
206 | if ($('.ismain').hasClass('active')){
207 | ismain = 'true';
208 | }
209 |
210 | data.ismain = ismain;
211 | data.mediadescription = mediaElement.saveDescription();
212 |
213 | $('.loader').fadeIn('fast');
214 |
215 | //------------ ajax-запрос на сохраение категории
216 |
217 | console.log('Данные для сохранения: ' + JSON.stringify(data));
218 |
219 | //------------ по завершении ajax-запроса
220 | // $('.loader').fadeOut('fast')
221 | // button.removeClass('working')
222 | }
223 | });
224 | });
225 |
--------------------------------------------------------------------------------
/html-client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Блог блондинки-программиста о кошечках
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
47 |
48 |
49 |
50 |
51 |
62 |
63 |
64 |
65 |
66 |
67 | Добро пожаловать на BlondieBlog
68 | Я очень рада видеть вас на своем блоге!
69 | Больше фишек на моем канале !
70 |
71 |
72 |
73 |
74 |
75 |
76 |
Тимоти - кошка с мужским именем и мужским характером
77 |
Настоящий боец. Сильная духом и лапами. Беспощадная и благородная.
78 |
79 |
80 | 8
81 | Пт, 17. Фев 2017
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
Бонин брат дал эксклюзивное интервью
91 |
Как живется простому уличному коту, и почему попасть в хорошие руки так важно в наше время.
92 |
93 |
94 | 3
95 | Вт, 14. Фев 2017
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
Марианна - знойная женщина
104 |
Красивая и независимая кошка ни с кем не намерена делить свой подоконник.
105 |
106 |
107 | 32
108 | Пн, 30. Янв 2017
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
Как Боня был маленьким
117 |
Ути-пути маленький! Уже в возрасте двух месяцев Боня показывал зубы и умел постоять за себя
118 |
119 |
120 | 29
121 | Пн, 30. Янв 2017
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
Что можно сделать из пластиковой бутылки
130 |
Вам некуда девать мусор? Няшные котики - то что нужно дизайнеру!
131 |
132 |
133 | 18
134 | Пн, 30. Янв 2017
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
Лолита - кошка сама по себе
143 |
Если у тебя нет хозяина, всегда можно приручить дикого двуногого и заставить его кормить тебя!
144 |
145 |
146 | 100
147 | Пт, 27. Янв 2017
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
Я собрал свой чемодан!
156 |
Боня собрал чемодан и едет на отдых
157 |
158 |
159 | 49
160 | Пт, 27. Янв 2017
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
Тима и Няша в детстве
169 |
Маленькие котики - это всегда повышенная няшность! Читайте историю, о том, как они появились в моем доме.
170 |
171 |
172 | 210
173 | Пт, 27. Янв 2017
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
Как Боня читал сценарий к этому видео
182 |
История о том, как кот уснул от унылости сценариев блогера.
183 |
184 |
185 | 222
186 | Пт, 27. Янв 2017
187 |
188 |
189 |
190 |
191 | Больше
192 |
193 |
194 |
195 |
203 | #BlondieCode © 2017
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
--------------------------------------------------------------------------------
/scripts/admin/articles.js:
--------------------------------------------------------------------------------
1 |
2 | //================================================================//
3 | //*********** articles.js ***********//
4 | //*********** © Aida Drogan - #BlondieCode
5 | //*********** Логика работы со статьями
6 | //*********** Поиск по статьям
7 | //*********** Создание новой стаьи
8 | //*********** Удаление статьи
9 | //*********** Редактирование статьи
10 | //*********** Публикация статьи и снятие с публикации
11 | //================================================================//
12 |
13 | $(document).ready(function(){
14 |
15 | //================================================================//
16 | //*********** Создание статьи по запросу ***********//
17 | //================================================================//
18 |
19 | $('#search-article').on('keyup', function(e){
20 |
21 | if ($(this).val().length > 1){
22 |
23 | //------------ данные для ajax-запроса
24 | var data = {};
25 | data.key = $(this).val();
26 |
27 | //------------ ajax-запрос на поиск статьи
28 |
29 | //------------ по завершении ajax-запроса
30 | //------------ result - ответ от сервера (найденная статья)
31 |
32 | var result = '' +
33 | '
' +
34 | '
' +
35 | '
' +
36 | '
Как Боня был маленьким
' +
37 | '
' +
38 | 'Создана: Пт, 27. Янв 2017, в 21:59 ' +
39 | 'Обновлена: Пн, 30. Янв 2017, в 18:40 ' +
40 | '
' +
41 | '
' +
42 | 'Опубликована ' +
43 | '
' +
44 | '
' +
47 | '
'
48 |
49 | //------------ если ничего не найдено по запросу
50 |
51 | var notFound = 'Ой... Похоже ничего не найдено!
';
52 |
53 | $('.articles').children().remove();
54 | $('.articles').append(notFound);
55 | $('.articles').append(result);
56 | }
57 | });
58 |
59 | //------------------ функция для подстановки тегов tagMeBabe
60 |
61 | if ($('#tags').length){
62 |
63 | var tagInput = $('#tags'); // элемент для ввода тега
64 | var tagAutoFillBar = $('.autofill-bar'); // панель для вывода результатов подстановки
65 | var tagAutoFillClass = 'autofill-bar'; // класс панели для вывода результатов подстановки (String)
66 | var tagContainer = $('#article-tags'); // контейнер для выгрузки выбранных тегов
67 | var tagItemClass = 't-item'; // класс элемента с тегом в контейнере
68 | var routeToTagSearch = '/route/to/tags'; // роут для ajax-запроса к серверу (совпадение тегов для постановки)
69 |
70 | tagMeBabe(tagInput, tagAutoFillBar, tagAutoFillClass, tagContainer, tagItemClass, routeToTagSearch);
71 | }
72 |
73 | //------------------ подключение плагина mediadescription
74 |
75 | var mediaElement = null;
76 |
77 | if ($('.mediaelement').length){
78 |
79 | var insidedescription = $('.mediaelement').find('.mediacontent').html();
80 |
81 | mediaElement = $('.mediaelement').makemediadescription({
82 | insidedescription:insidedescription
83 | });
84 |
85 | //-------------- подтвердить перезагрузку окна\ уход со страницы
86 |
87 | window.onbeforeunload = function() {
88 |
89 | if (!$('#deleted').length){
90 | return 'Ты сохранил все изменения?';
91 | }
92 | };
93 | }
94 |
95 |
96 | //================================================================//
97 | //*********** Сохранение статьи ***********//
98 | //================================================================//
99 |
100 | function saveArticle(type, button){
101 |
102 | //--------------- button - кнопка, с которой был переход
103 | //--------------- type - новая статья или редактирование существующей
104 |
105 | if (!button.hasClass('working')){
106 |
107 | //--------------- проверка выбрана ли хоть одна категория
108 | if (($('#article-categories .active').length > 0)){
109 |
110 | //--------------- проверка на обязательные поля
111 | if ($('#title').val().length == 0){
112 | showError('Введите название статьи!', 'login');
113 | } else if ($('#alias').val().length == 0) {
114 | showError('Введите URL статьи!', 'login');
115 | } else {
116 |
117 | button.addClass('working');
118 |
119 | //------------ данные для ajax-запроса
120 | var data = {};
121 |
122 | //--------------- передать тип на сервер!
123 | data.action = type;
124 |
125 | //--------------- разобраться с загрузкой изображения!
126 | console.log('Главное изображение - ' + globalArticleMainImageFileNameToUpload);
127 |
128 | data.title = $('#title').val();
129 | data.alias = $('#alias').val();
130 | data.shortdescription = $('#shortdescription').val();
131 | data.htmltitle = $('#htmltitle').val();
132 | data.htmldescription = $('#htmldescription').val();
133 | data.htmlkeywords = $('#htmlkeywords').val();
134 | data.moderator = $('#moderator').text();
135 |
136 | var catArray = [];
137 | $('#article-categories .active').each(function(){
138 | catArray.push($(this).text());
139 | });
140 | data.categories = catArray;
141 |
142 | var tagArray = [];
143 | $('#article-tags .t-item').each(function(){
144 | tagArray.push($(this).text());
145 | });
146 | data.tags = tagArray;
147 |
148 | data.mediadescription = mediaElement.saveDescription();
149 |
150 | $('.loader').fadeIn('fast');
151 |
152 | //------------ ajax-запрос на сохранение статьи
153 |
154 | console.log('Данные для сохранения: ' + JSON.stringify(data));
155 |
156 | //------------ по завершении ajax-запроса
157 | // $('.loader').fadeOut('fast')
158 | // button.removeClass('working')
159 | }
160 |
161 | } else {
162 | showError('Выберите хотя бы одну категорию!', 'login');
163 | }
164 | }
165 | }
166 |
167 | //================================================================//
168 | //*********** Редактирование статьи ***********//
169 | //================================================================//
170 |
171 | $('#edit-article').on('click', function(){
172 |
173 | var button = $(this);
174 |
175 | //----------- проверяем нужно ли удалить старое изображение
176 | if (button.hasClass('todelete')){
177 |
178 | //------------ данные для ajax-запроса на удаление файла с сервера
179 | var data = {};
180 | data.file = 'path/to/file';
181 | }
182 |
183 | saveArticle('editarticle', button);
184 |
185 | });
186 |
187 | //================================================================//
188 | //*********** Новая статья ***********//
189 | //================================================================//
190 |
191 | $('#new-article').on('click', function(){
192 |
193 | var button = $(this);
194 | saveArticle('newarticle', button);
195 |
196 | });
197 |
198 | //================================================================//
199 | //*********** Удаление статьи ***********//
200 | //================================================================//
201 |
202 | $('#delete-article').on('click', function(){
203 |
204 | $('body').append(''
215 | );
216 |
217 | $('.popup-holder.dynamic').fadeIn();
218 |
219 | });
220 |
221 | $('body').on('click', '#yes-delete-article', function(){
222 |
223 | var button = $(this);
224 |
225 | if (!button.hasClass('working')){
226 |
227 | button.addClass('working');
228 | //------------ ajax-запрос на удаление категории
229 | }
230 | });
231 |
232 | //================================================================//
233 | //*********** Публикация статьи ***********//
234 | //================================================================//
235 |
236 | $('.articles').on('click', '.published span', function(){
237 |
238 | var button = $(this);
239 |
240 | //------------ данные для ajax-запроса
241 | var data = {};
242 | var flag = 'yes';
243 | if (button.hasClass('yes')){
244 | flag = 'no';
245 | }
246 | data.flag = flag;
247 |
248 | //------------ ajax-запрос на публикацию статьи
249 |
250 | //------------ по завершении ajax-запроса
251 |
252 | if (flag == 'yes'){
253 | button.removeClass('no').addClass('yes').text('Опубликована');
254 | showSuccess('Статья опубликована', 'login');
255 | } else {
256 | button.removeClass('yes').addClass('no').text('Не опубликована');
257 | showSuccess('Статья снята с публикации', 'login');
258 | }
259 | });
260 |
261 | });
--------------------------------------------------------------------------------
/styles/main.css:
--------------------------------------------------------------------------------
1 | /*************************** Сброс стилей *****************************/
2 |
3 | html, body, div, span, object, iframe,
4 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
5 | abbr, address, cite, code,
6 | del, dfn, em, img, ins, kbd, q, samp,
7 | small, strong, sub, sup, var,
8 | b, i,
9 | dl, dt, dd, ol, ul, li,
10 | fieldset, form, label, legend,
11 | table, caption, tbody, tfoot, thead, tr, th, td,
12 | article, aside, canvas, details, figcaption, figure,
13 | footer, header, menu, nav, section, summary,
14 | time, mark, audio, video {
15 | margin:0;
16 | padding:0;
17 | border:0;
18 | outline:0;
19 | font-size:100%;
20 | background:transparent;
21 | }
22 |
23 | body {
24 | line-height:1;
25 | }
26 |
27 | article,aside,details,figcaption,figure,
28 | footer,header,menu,nav,section {
29 | display:block;
30 | }
31 |
32 | nav ul {
33 | list-style:none;
34 | }
35 |
36 | blockquote, q {
37 | quotes:none;
38 | }
39 |
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {content:'';}
42 |
43 | a {
44 | margin:0;
45 | padding:0;
46 | font-size:100%;
47 | vertical-align:baseline;
48 | background:transparent;
49 | }
50 |
51 | /************************* Общие стили ***************************/
52 |
53 | body, html {padding: 0;margin: 0; height: 100%}
54 | body {
55 | background: #f6f6f6;
56 | color: #2d2d2d;
57 | font-family: 'Arial', 'Helvetica';
58 | font-size: 16px;
59 | line-height: 1.5;
60 | }
61 |
62 | h1 {font-size: 24px;}
63 | h2 {font-size: 22px;}
64 | h3 {font-size: 20px;}
65 | h4, h5, h6 {font-size: 18px;}
66 |
67 | a {color: #ca6a96}
68 | a:hover {color: #e889b4}
69 |
70 | header, footer, main {
71 | width: 100%;
72 | }
73 |
74 | header {
75 | padding: 50px 0 30px;
76 | display: flex;
77 | flex-grow: 0;
78 | flex-direction: row;
79 | justify-content: space-between;
80 | align-items: center;
81 | }
82 | header ul li, footer ul li {
83 | display: inline-block;
84 | margin: 0 20px 0 0;
85 | text-transform: uppercase;
86 | font-weight: 600;
87 | font-size: 11px;
88 | letter-spacing: 1px;
89 | }
90 | header ul a, footer ul a {
91 | color: #2d2d2d;
92 | text-decoration: none;
93 | display: inline-block;
94 | border-bottom: 2px solid transparent;
95 | transition: .2s;
96 | }
97 | header ul a:hover, header ul a.active, footer ul a:hover, footer ul a.active {
98 | color: #2d2d2d;
99 | border-bottom: 2px solid #2d2d2d;
100 | transition: .2s;
101 | }
102 | header nav#language {
103 | margin: 0 0 10px 0;
104 | display: flex;
105 | flex-direction: row-reverse;
106 | }
107 | header nav#language ul li {
108 | background: #2d2d2d;
109 | color: #f6f6f6;
110 | padding: 4px 6px;
111 | border-radius: 50%;
112 | transition: .2s;
113 | font-size: 10px;
114 | }
115 | header nav#language ul li:hover, header nav#language ul li.active {background: #ca6a96; transition: .2s;}
116 | header nav#language ul li a {color: #f6f6f6; border-bottom: none;}
117 |
118 | main {
119 | flex-grow: 1;
120 | line-height: 1.8;
121 | }
122 | footer {
123 | flex-grow: 0;
124 | display: flex;
125 | align-items: center;
126 | justify-content: space-between;
127 | padding: 40px 0;
128 | border-top: 1px solid #d4d4d4;
129 | }
130 | footer small {
131 | font-size: 11px;
132 | text-align: center;
133 | text-transform: uppercase;
134 | }
135 | main h1, main h2, main h3, main h4 {
136 | text-transform: uppercase;
137 | letter-spacing: 1px;
138 | color: #2d2d2d;
139 | margin: 0 0 20px 0;
140 | }
141 | main h1 {
142 | text-align: center;
143 | margin: 30px 0 50px;
144 | }
145 | .page-wrapper {
146 | width: 100%;
147 | height: 100%;
148 | margin: 0 auto;
149 | max-width: 1200px;
150 | padding: 0 10px;
151 | box-sizing: border-box;
152 | display: flex;
153 | flex-direction: column;
154 | }
155 | .scrolltop {
156 | position: fixed;
157 | bottom: 40px;
158 | right: 40px;
159 | width: 40px;
160 | height: 40px;
161 | border-radius: 50%;
162 | background: rgba(0,0,0,.75);
163 | opacity: .75;
164 | cursor: pointer;
165 | transition: .3s;
166 | }
167 | .scrolltop:hover {
168 | opacity: 1;
169 | transition: .3s;
170 | }
171 | .scrolltop:after {
172 | content: "⇪";
173 | width: 100%;
174 | text-align: center;
175 | line-height: 40px;
176 | position: absolute;
177 | top: 0;
178 | left: 0;
179 | color: #ffffff;
180 | }
181 |
182 | /************************* Страница категории ***************************/
183 |
184 | .article-holder {
185 | display: flex;
186 | flex-flow: row wrap;
187 | justify-content: space-between;
188 | padding: 10px 0;
189 | margin: 30px 0 0 0;
190 | }
191 | .article-holder article {
192 | background: #ffffff;
193 | margin: 10px 0 0 0;
194 | flex-basis: calc(33% - 4px);
195 | }
196 | .article-holder article a {
197 | text-decoration: none;
198 | display: flex;
199 | flex-direction: column;
200 | height: 100%;
201 | }
202 | .article-holder article .details {
203 | padding: 30px;
204 | box-sizing: border-box;
205 | font-size: 14px;
206 | color: #7d7d7d;
207 | flex-grow: 1;
208 | }
209 | .article-holder article h2 {
210 | font-weight: 400;
211 | font-size: 18px;
212 | color: #2d2d2d;
213 | }
214 | .article-holder article img {
215 | width: 100%;
216 | height: auto;
217 | opacity: 1;
218 | transition: .3s
219 | }
220 | .article-holder article:hover img {
221 | opacity: .75;
222 | transition: .3s
223 | }
224 | .article-holder article .secondary {
225 | display: flex;
226 | flex-direction: row;
227 | align-items: center;
228 | justify-content: space-between;
229 | padding: 0 20px 30px;
230 | box-sizing: border-box;
231 | font-size: 12px;
232 | }
233 | .article-holder article .secondary .views {
234 | font-size: 16px;
235 | font-weight: 600;
236 | display: block;
237 | position: relative;
238 | padding: 0 0 0 16px;
239 | }
240 | .article-holder article .secondary .views:after {
241 | display: block;
242 | position: absolute;
243 | content: '☋';
244 | top: 0;
245 | left: 0;
246 | }
247 | .more {
248 | margin: 20px auto 10px;
249 | background: #ca6a96;
250 | color: #ffffff;
251 | border-radius: 5px;
252 | padding: 4px 10px;
253 | transition: .2s;
254 | cursor: pointer;
255 | display: table;
256 | }
257 | .more:hover {
258 | background: #e889b4;
259 | transition: .2s;
260 | }
261 |
262 | /************************* Страница статей ***************************/
263 |
264 | .article-wrapper {
265 | display: flex;
266 | flex-flow: row wrap;
267 | height: 100%;
268 | width: 100%;
269 | margin: 40px 0 0 0;
270 | }
271 | .article-wrapper .details {
272 | padding: 10px;
273 | }
274 | .article-wrapper article .details {
275 | padding: 20px;
276 | }
277 | .article-wrapper article {
278 | display: flex;
279 | flex-direction: column;
280 | flex-wrap: wrap;
281 | background: #ffffff;
282 | margin: 0 20px 20px 0;
283 | width: 70%;
284 | max-width: calc(100% - 320px);
285 | flex-grow: 1;
286 | }
287 | .article-wrapper article h1 {
288 | margin: 30px 0;
289 | }
290 | .article-wrapper article .secondary {
291 | display: flex;
292 | flex-direction: row;
293 | justify-content: space-between;
294 | font-size: 14px;
295 | color: #999999;
296 | }
297 | .article-wrapper article img {
298 | margin: 0 0 20px 0;
299 | width: 100%;
300 | height: auto;
301 | }
302 | .article-wrapper aside {
303 | display: flex;
304 | flex-direction: column;
305 | width: 30%;
306 | max-width: 300px;
307 | }
308 | .article-wrapper aside a {
309 | text-decoration: none;
310 | display: block;
311 | background: #ffffff;
312 | margin: 0 0 20px 0;
313 | }
314 | .article-wrapper aside .tags {
315 | display: flex;
316 | flex-flow: row wrap;
317 | background: #ffffff;
318 | padding: 20px;
319 | margin: 0 0 20px 0;
320 | }
321 | .article-wrapper aside .tags a {
322 | background: #ca6a96;
323 | color: #ffffff;
324 | border-radius: 5px;
325 | padding: 4px 10px;
326 | margin: 0 10px 10px 0;
327 | transition: .2s;
328 | }
329 | .article-wrapper aside .tags a:hover {
330 | background: #e889b4;
331 | transition: .2s;
332 | }
333 | .article-wrapper aside p {
334 | font-size: 14px;
335 | line-height: 1.4;
336 | color: #666666;
337 | }
338 | .article-wrapper aside h2 {
339 | text-transform: none;
340 | font-size: 18px;
341 | line-height: 1.3;
342 | margin: 0 0 12px 0;
343 | }
344 | .article-wrapper aside img {
345 | width: 100%;
346 | height: auto;
347 | }
348 |
349 | /************************* Страница 404 ***************************/
350 |
351 | .notfoundpage {
352 | text-align: center;
353 | font-size: 32px;
354 | margin: 30px 0;
355 | }
356 | .notfoundpage p {
357 | margin: 0 0 20px 0;
358 | }
359 | .notfoundpage .small {
360 | font-size: 22px;
361 | }
362 | .notfoundpage h1 {
363 | font-size: 66px;
364 | }
365 | .notfoundpage .sad {
366 | position: relative;
367 | min-height: 120px;
368 | }
369 | .notfoundpage .sad:after {
370 | position: absolute;
371 | content: "☹";
372 | color: #999999;
373 | font-size: 120px;
374 | line-height: 1;
375 | width: 100%;
376 | top: 0;
377 | left: 0;
378 | }
379 |
380 | /************************* Мобильные стили ***************************/
381 |
382 | @media (max-width: 800px) {
383 |
384 | header {
385 | display: block;
386 | padding: 10px 0 0 0;
387 | }
388 | header nav#language {
389 | margin: 20px 0 10px;
390 | flex-direction: row;
391 | }
392 | header ul li {
393 | margin: 0 20px 20px 0;
394 | }
395 | main h1 {
396 | margin: 20px 0 30px;
397 | }
398 | .article-holder {
399 | margin: 20px 0 0 0;
400 | }
401 | .article-holder article {
402 | flex-basis: calc(50% - 5px);
403 | }
404 | .scrolltop {
405 | bottom: 20px;
406 | right: 20px;
407 | }
408 | .article-wrapper article {
409 | display: block;
410 | margin: 0 0 20px 0;
411 | }
412 | .article-wrapper {
413 | flex-direction: column;
414 | }
415 | .article-wrapper aside, .article-wrapper article {
416 | max-width: 100%;
417 | width: 100%;
418 | }
419 | .article-wrapper aside img {
420 | width: 50px;
421 | border-radius: 50%;
422 | margin-left: 10px;
423 | }
424 | .article-wrapper aside a {
425 | display: flex;
426 | flex-direction: row;
427 | align-items: center;
428 | margin: 0 0 10px 0;
429 | }
430 | }
431 |
432 | @media (max-width: 600px) {
433 |
434 | .article-holder article {
435 | flex-basis: 100%;
436 | }
437 | .scrolltop {
438 | bottom: 10px;
439 | right: 10px;
440 | }
441 | }
--------------------------------------------------------------------------------
/scripts/admin/mediadescription.js:
--------------------------------------------------------------------------------
1 | //*********************************************************************************************//
2 | //======================== MEDIADESCRIPTION PLUGIN V 1.0 /02-2017/ ============================//
3 | //================================== © #BLONDIECODE © =========================================//
4 | //================================== © Aida Drogan © ==========================================//
5 | //*********************************************************************************************//
6 |
7 | //======================= ОПЦИИ =====================//
8 | // insidedescription - type:STRING - текущее описание статьи из БД (HTML)
9 |
10 | //======================= Функции =====================//
11 | // destroyPluginEvent - очистить плагин (при повторном вызове без перезагрузки страницы)
12 | // saveDescription - экспорт контекста в формате HTML (String)
13 |
14 | (function($){
15 |
16 | $.fn.makemediadescription = function(options){
17 |
18 | var container = $(this);
19 |
20 | var insidedescription = options.insidedescription;
21 |
22 | container.append(
23 | '' +
24 | insidedescription +
25 | '
');
26 |
27 | var id = new Date();
28 | id = id.getTime();
29 |
30 | $('body').append('');
42 |
43 | var popupmenu = $('#' + id);
44 |
45 | var contentHolder = container.find('#article-descr');
46 |
47 |
48 | //============================ TEXT HIGHLIGHTER ===============================//
49 |
50 | $.textHighlighter.createWrapper = function() {
51 | return $(' ');
52 | };
53 | contentHolder.textHighlighter();
54 |
55 | // ---- а еще можно определить так =)
56 | // contentHolder.textHighlighter({highlightedClass: 'temp', color: 'none'});
57 |
58 | //============================ ФУНКЦИОНАЛЬНОЕ МЕНЮ ===============================//
59 |
60 | function parseMenu(show){
61 |
62 | if (popupmenu.find('.link-holder:visible').length){
63 | popupmenu.find('.link-holder').hide();
64 | popupmenu.find('.mitem').show();
65 | }
66 |
67 | if (container.find('.temp').length && (show == 'first')){
68 |
69 | var top = (container.find('.temp').offset().top) - 46;
70 | var left =container.find('.temp').offset().left;
71 |
72 | popupmenu.css({top: top, left: left}).fadeIn('fast');
73 |
74 | } else if ($('.md-menu-panel:visible').length && (show == 'change')) {
75 |
76 | if (container.find('.temp').length ){
77 |
78 | var top = container.find('.temp').offset().top - 46;
79 | var left =container.find('.temp').offset().left;
80 |
81 | popupmenu.css({top: top, left: left});
82 |
83 | } else {
84 | popupmenu.fadeOut('fast');
85 | }
86 |
87 | } else {
88 | popupmenu.fadeOut('fast');
89 | }
90 | }
91 |
92 | $(document).on( 'scroll', function(){
93 | parseMenu('change');
94 | });
95 |
96 | contentHolder.on( 'scroll', function(){
97 | parseMenu('change');
98 | });
99 |
100 | container.on('mouseup', function(){
101 | parseMenu('first');
102 | });
103 |
104 | popupmenu.on('click', '.mitem', function(){
105 | if (!$(this).hasClass('adescr-addlink')){
106 | parseMenu('hide');
107 | }
108 | });
109 |
110 | //============================ KEYPRESS ===============================//
111 |
112 | container.on('keydown', function(e){
113 | handleDeleteActions(e, $(this));
114 | });
115 |
116 | container.on('keypress', function(e){
117 | handleDeleteActions(e, $(this));
118 | });
119 |
120 | function handleDeleteActions(e, obj){
121 |
122 | //=================== Обработка кнопок backspace и delete ==================//
123 |
124 | if ((e.keyCode == 8) || (e.keyCode == 46)){
125 |
126 | if (obj.find('.temp').length > 0){
127 |
128 | e.preventDefault();
129 |
130 | obj.find('.temp').first().before(' ');
131 |
132 | var node = document.getElementById('cursorpos');
133 | var range = document.createRange();
134 | range.setStartAfter(node);
135 | range.collapse(true);
136 | var selection = window.getSelection();
137 | selection.removeAllRanges();
138 | selection.addRange(range);
139 |
140 | obj.find('.temp').remove();
141 | obj.find('#cursorpos').remove();
142 |
143 | $('p:empty').remove();
144 | $('span:empty').remove();
145 | $('h2:empty').remove();
146 | $('h3:empty').remove();
147 | $('h4:empty').remove();
148 | $('a:empty').remove();
149 | }
150 | }
151 | }
152 |
153 | //====================== КНОПКИ МЕНЮ ===========================//
154 |
155 | //-------- по клику на контейнер сбрасываем выделение
156 |
157 | container.on('mousedown', '#article-descr', function(){
158 |
159 | container.find('.temp').each(function(){
160 | $(this).contents().unwrap();
161 | })
162 |
163 | });
164 |
165 | //-------- функция вставки элемента на место выделения
166 |
167 | function wrapSelection(type, cclass){
168 |
169 | var str = '';
170 | var counter = 0;
171 | var length = container.find('.temp').length;
172 |
173 | container.find('.temp').each(function(){
174 |
175 | counter++;
176 | str = str + $(this).text();
177 |
178 | if ((type == 'a') && ($(this).parent().is('a'))){
179 | $(this).unwrap();
180 | }
181 |
182 | if (counter == length){
183 |
184 | if (cclass != ''){
185 |
186 | if (type == 'span'){
187 |
188 | var span = $(this).after('<' + type + ' class="' + cclass + '">' + str + '' + type + '>');
189 | span.parent().addClass(cclass).text(span.text());
190 | span.remove();
191 |
192 | } else if (type == 'a'){
193 |
194 | var href;
195 |
196 | if (popupmenu.find('.open-link').hasClass('active')){
197 | href = $(this).after('<' + type + ' href="' + cclass + '" target="_blank">' + str + '' + type + '>');
198 | } else {
199 | href = $(this).after('<' + type + ' href="' + cclass + '" rel="nofollow" target="_blank">' + str + '' + type + '>');
200 | }
201 |
202 | if (href.parent().is('a')){
203 | href.unwrap();
204 | }
205 | }
206 |
207 | } else {
208 |
209 | var h = $(this).after('<' + type + '>' + str + '' + type + '>');
210 | if (h.parent().attr('id') != contentHolder.attr('id')){
211 | h.unwrap();
212 | }
213 | }
214 | }
215 | $(this).remove();
216 | })
217 | }
218 |
219 | popupmenu.on('click', '.adescr-bold', function(){
220 | wrapSelection('b', '');
221 | });
222 |
223 | popupmenu.on('click', '.adescr-italic', function(){
224 | wrapSelection('i', '');
225 | });
226 |
227 | popupmenu.on('click', '.adescr-h2', function(){
228 | wrapSelection('h2', '');
229 | });
230 |
231 | popupmenu.on('click', '.adescr-h3', function(){
232 | wrapSelection('h3', '');
233 | });
234 |
235 | popupmenu.on('click', '.adescr-h4', function(){
236 | wrapSelection('h4', '');
237 | });
238 |
239 | popupmenu.on('click', '.adescr-strong', function(){
240 | wrapSelection('strong', '');
241 | });
242 |
243 | popupmenu.on('click', '.adescr-centered', function(){
244 | wrapSelection('span', 'a-centered');
245 | });
246 |
247 | popupmenu.on('click', '.adescr-reset', function(){
248 |
249 | container.find('.temp').each(function () {
250 | if ($(this).parent().attr('id') != contentHolder.attr('id')){
251 | $(this).unwrap();
252 | }
253 | });
254 |
255 | });
256 |
257 | //========================= Добавить ссылку ========================//
258 |
259 | popupmenu.on('click', '.adescr-addlink', function(){
260 | $(this).siblings().fadeOut('fast');
261 | $(this).fadeOut('fast', function(){
262 | $(this).next().fadeIn('fast');
263 | $('.href-val').focus();
264 | });
265 | });
266 |
267 | popupmenu.on('keyup', '.href-val', function(e){
268 |
269 | if (e.keyCode == 13){
270 |
271 | if ($(this).val() != ''){
272 | var link = $(this).val();
273 | wrapSelection('a', link);
274 | }
275 |
276 | $(this).val('');
277 | $(this).parent().fadeOut('fast', function(){
278 | popupmenu.find('.mitem').fadeIn('fast');
279 | popupmenu.find('.open-link').removeClass('active');
280 | });
281 | }
282 | });
283 |
284 | popupmenu.on('click', '.open-link', function(){
285 | $(this).toggleClass('active');
286 | popupmenu.find('.href-val').focus();
287 | });
288 |
289 |
290 | //====================== Сохранить описание внутри плагина ===========================//
291 | function saveDescription(){
292 |
293 | contentHolder.find('br').each(function(){
294 | if (($(this).parent().is('div'))&& ($(this).parent().attr('id')) != contentHolder.attr('id')){
295 | $(this).unwrap();
296 | }
297 | });
298 |
299 | contentHolder.find('.temp').each(function(){
300 | $(this).contents().unwrap();
301 | });
302 |
303 | contentHolder.find('div').each(function(){
304 | if ($(this).text().length == 0){
305 | $(this).remove();
306 | } else {
307 | $(this).before(' ');
308 | $(this).contents().unwrap();
309 | }
310 | });
311 |
312 | contentHolder.find('h2:empty').remove();
313 | contentHolder.find('h3:empty').remove();
314 | contentHolder.find('h4:empty').remove();
315 | contentHolder.find('a:empty').remove();
316 |
317 | var html = contentHolder.html().replace(/ /g, '');
318 | return html;
319 | }
320 |
321 | //====================== Экспортные функции ===========================//
322 |
323 | return {
324 | destroyPluginEvent: function(){
325 | container.children().die();
326 | popupmenu.children.die();
327 | },
328 | saveDescription: function(){
329 | return saveDescription();
330 | }
331 | };
332 |
333 | return container;
334 | };
335 |
336 | })(jQuery);
--------------------------------------------------------------------------------
/styles/admin.css:
--------------------------------------------------------------------------------
1 | /*************************** Сброс стилей *****************************/
2 |
3 | html, body, div, span, object, iframe,
4 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
5 | abbr, address, cite, code,
6 | del, dfn, em, img, ins, kbd, q, samp,
7 | small, strong, sub, sup, var,
8 | b, i,
9 | dl, dt, dd, ol, ul, li,
10 | fieldset, form, label, legend,
11 | table, caption, tbody, tfoot, thead, tr, th, td,
12 | article, aside, canvas, details, figcaption, figure,
13 | footer, header, menu, nav, section, summary,
14 | time, mark, audio, video {
15 | margin:0;
16 | padding:0;
17 | border:0;
18 | outline:0;
19 | font-size:100%;
20 | background:transparent;
21 | }
22 |
23 | body {
24 | line-height:1;
25 | }
26 |
27 | article,aside,details,figcaption,figure,
28 | footer,header,menu,nav,section {
29 | display:block;
30 | }
31 |
32 | nav ul {
33 | list-style:none;
34 | }
35 |
36 | blockquote, q {
37 | quotes:none;
38 | }
39 |
40 | blockquote:before, blockquote:after,
41 | q:before, q:after {content:'';}
42 |
43 | a {
44 | margin:0;
45 | padding:0;
46 | font-size:100%;
47 | vertical-align:baseline;
48 | background:transparent;
49 | }
50 |
51 | input, select {
52 | vertical-align:middle;
53 | }
54 |
55 | /************************* Системные стили ***************************/
56 |
57 | .clear {display:block; clear:both;}
58 | .clear:after {content:"."; display:block; height:0; clear:both; visibility:hidden; line-height:0;}
59 |
60 | .centered {display: table; margin: 0 auto;}
61 |
62 | .fl_left {float: left;}
63 | .fl_right {float: right;}
64 |
65 | .hidden {overflow: hidden;}
66 | .half {width: 50%;}
67 | .full {width: 100%;}
68 |
69 | .flex-container {
70 | display: flex;
71 | flex: auto;
72 | }
73 | .flex-col {
74 | flex-direction: column;
75 | display: flex;
76 | }
77 | .flex-row {
78 | lex-direction: row;
79 | display: flex;
80 | }
81 | .flex-row-wrap {flex-flow: row wrap}
82 | .flex-centered {
83 | display: flex;
84 | align-content: center;
85 | align-items: center;
86 | justify-content: center;
87 | margin: 0 auto;
88 | }
89 | .flex-start {
90 | flex-wrap: wrap;
91 | align-content: flex-start;
92 | align-items: flex-start;
93 | justify-content: flex-start;
94 | }
95 | .flex-full {flex-grow: 1; flex-basis: 100%;}
96 | .flex-full.mini {max-width: 500px;}
97 | .flex-dominant {flex-grow: 1;}
98 | .flex-half {flex-basis: calc(50% - 10px); margin: 0 5px;}
99 | .flex-tht {flex-basis: calc(33% - 10px); margin: 0 5px;}
100 | .flex-goo {justify-content: space-between;}
101 |
102 | .padding20 {box-sizing: border-box; padding: 20px;}
103 | .padding10-h {padding: 0 10px;}
104 | .padding20-h {padding: 0 20px;}
105 |
106 | /************************* Базовые стили ***************************/
107 | html {
108 | min-height: 100%;
109 | display: flex;
110 | flex-direction: column;
111 | }
112 |
113 | body {
114 | display: flex;
115 | flex-direction: column;
116 | flex: auto;
117 | background: #efefef;
118 | font-family: Helvetica Neue, Helvetica, Arial;
119 | color: #222222;
120 | font-size: 16px;
121 | line-height: 1.6;
122 | }
123 |
124 | header, footer {
125 | flex-grow: 0;
126 | display: flex;
127 | flex-direction: row;
128 | width: 100%;
129 | padding: 10px 20px;
130 | box-sizing: border-box;
131 | background: #222222;
132 | color: #ffffff;
133 | }
134 |
135 | header {flex-direction: column; padding: 0;}
136 | header .flex-row {padding: 10px 20px;}
137 | header .subheader {background: #777777;}
138 |
139 | footer {justify-content: center;}
140 | footer small {font-size: 12px;}
141 |
142 | header a {
143 | color: #ffffff;
144 | border-radius: 5px;
145 | border: 1px solid #ffffff;
146 | padding: 4px 10px;
147 | margin: 0 6px 0 0;
148 | transition: .2s;
149 | text-decoration: none;
150 | }
151 | header a:first-child {
152 | margin: 0 0 0 26px;
153 | }
154 | header a:hover, header a.active {
155 | color: #222222;
156 | background: #ffffff;
157 | transition: .2s;
158 | }
159 |
160 | header .buttons {
161 | flex-grow: 1;
162 | display: flex;
163 | flex-direction: row-reverse;
164 | flex: auto;
165 | }
166 |
167 | header .title {padding: 4px; margin: 4px 0 0 0;}
168 |
169 | label, .label {color: #999999; font-size: 14px; margin: 0 0 4px 0;}
170 |
171 | .content {
172 | flex-grow: 1;
173 | display: flex;
174 | flex-direction: column;
175 | flex: auto;
176 | width: 100%;
177 | }
178 |
179 | .button {
180 | border-radius: 5px;
181 | padding: 10px 20px;
182 | margin: 10px 10px 0 0;
183 | background: #999999;
184 | color: #ffffff;
185 | cursor: pointer;
186 | line-height: 1;
187 | height: auto;
188 | transition: .2s;
189 | }
190 | .button:hover, .button.active {transition: .2s; background: #666666;}
191 |
192 | .button.green {background: #3b9739;}
193 | .button.green:hover {background: #358039;}
194 |
195 | .button.red {background: #973323;}
196 | .button.red:hover {background: #802725;}
197 |
198 | a.button {text-decoration: none;}
199 |
200 | .link {padding: 0 0 4px 0; border-bottom: 1px dashed #999999; color: #999999; cursor: pointer; transition: .2s;}
201 | .open-bayan {position: relative;}
202 | .open-bayan:after {content: "⥥"; position: absolute; color: #999999; top: 6px; right: 20px;}
203 | .open-bayan.up:after {content: "⥣";}
204 | .open-bayan:hover:after {color: #666666;}
205 | .link:hover {color: #666666; border-bottom: 1px dashed #666666; transition: .2s;}
206 |
207 | .bayan {display: none;}
208 |
209 | .holder {
210 | flex-grow: 1;
211 | display: flex;
212 | flex-direction: column;
213 | justify-content: center;
214 | flex-flow: row wrap;
215 | width: 100%;
216 | min-width: 1000px;
217 | max-width: 1300px;
218 | margin: 0 auto;
219 | background: #ffffff;
220 | box-sizing: border-box;
221 | }
222 |
223 | .holder.type {
224 | align-items: flex-start;
225 | justify-content: flex-start;
226 | align-content: flex-start;
227 | }
228 |
229 | .holder .holder {padding: 20px; align-items: flex-start;}
230 |
231 | .options-header {
232 | background: #dadada;
233 | width: 100%;
234 | height: 40px;
235 | padding: 10px 20px;
236 | flex-grow: 0;
237 | display: flex;
238 | flex-direction: row-reverse;
239 | align-items: center;
240 | }
241 | .options-header .button {margin: 0 10px 0 0; padding: 10px 20px;}
242 |
243 | .blog-content, .blog-content ul.ui-sortable {
244 | width: 100%;
245 | display: flex;
246 | flex-wrap: wrap;
247 | flex-direction: row;
248 | align-content: flex-start;
249 | list-style-type: none;
250 | align-items: flex-start;
251 | }
252 | .blog-content ul.ui-sortable li {
253 | flex-basis: calc(25% - 10px);
254 | border: 1px solid #a8a8a8;
255 | margin: 10px 10px 0 0;
256 | padding: 10px;
257 | box-sizing: border-box;
258 | border-radius: 5px;
259 | }
260 | .blog-content ul.ui-sortable li.ismain {
261 | background: #f6f6f6;
262 | }
263 | .blog-content ul.ui-sortable li.root {background: #e4fdce;}
264 | .blog-content ul.ui-sortable li.ui-state-highlight {
265 | border: 1px dashed #a7a7a7;
266 | }
267 | .blog-content ul.ui-sortable li .image, .blog-content ul.ui-sortable li .image img {width: 100%;}
268 | .blog-content ul.ui-sortable li .title {width: 100%; display: block;}
269 | .blog-content ul.ui-sortable li .small {font-size: 12px; color: #999999;}
270 | .blog-content ul.ui-sortable li .buttons {
271 | display: flex;
272 | flex-direction: row;
273 | align-content: flex-start;
274 | align-items: flex-start;
275 | }
276 | .blog-content ul.ui-sortable li .buttons a {
277 | background: #999999;
278 | color: #ffffff;
279 | padding: 4px 10px;
280 | border-radius: 5px;
281 | margin: 10px 10px 0 0;
282 | text-decoration: none;
283 | transition: .2s;
284 | }
285 | .blog-content ul.ui-sortable li .buttons a:hover {background: #666666; transition: .2s;}
286 | .blog-content ul.ui-sortable li .buttons a.article {background: #3b9739;}
287 | .blog-content ul.ui-sortable li .buttons a.article:hover {background: #358039;}
288 |
289 | .v-list {align-items: flex-start;}
290 | .v-list .v-item {
291 | justify-content: space-between;
292 | align-items: center;
293 | padding: 10px;
294 | margin: 0 0 6px 0;
295 | border: 1px dashed #efefef;
296 | }
297 | .v-list .v-item .title {
298 | max-width: 600px;
299 | min-width: 600px;
300 | }
301 | .v-list .v-item .title.full {max-width: 100%;}
302 | .v-list .v-item .image {
303 | background: #efefef;
304 | border-radius: 6px;
305 | width: 50px;
306 | height: 50px;
307 | overflow: hidden;
308 | }
309 | .v-list .v-item .image img {
310 | width: 100%;
311 | height: 100%;
312 | }
313 | .v-list .v-item .created {
314 | color: #a7a7a7;
315 | font-size: 14px;
316 | }
317 | .v-list .v-item .published {
318 | width: 120px;
319 | cursor: pointer;
320 | font-size: 14px;
321 | }
322 | .v-list .v-item .published .yes {color: #3b9739;}
323 | .v-list .v-item .published .no {color: #973323;}
324 | .work-holder .v-list .v-item a {color: #222222;}
325 | .search {
326 | max-width: 400px;
327 | margin: 0 0 10px 0;
328 | width: 100%;
329 | }
330 |
331 | /************************* Формы ***************************/
332 |
333 | input, textarea, select {
334 | border-radius: 5px;
335 | display: block;
336 | background: #ffffff;
337 | outline: 0;
338 | border: 1px solid #d5d5d5;
339 | padding: 6px 12px;
340 | font-size: 16px;
341 | box-sizing: border-box;
342 | width: 100%;
343 | }
344 | input:focus, textarea:focus {border: 1px solid #98e25d;}
345 | textarea {resize: none;}
346 | .input-row {
347 | margin: 10px auto;
348 | display: flex;
349 | flex-direction: column;
350 | flex-wrap: wrap;
351 | width: 100%;
352 | }
353 | .input-row.flex-row {flex-direction: row;}
354 | .cat-holder{
355 | border: 1px dashed #d5d5d5;
356 | border-radius: 6px;
357 | min-height: 40px;
358 | box-sizing: border-box;
359 | padding: 20px;
360 | }
361 | .cat-holder.na {opacity: .5;}
362 | .cat-holder .cat, .cat-holder.na .cat:hover {
363 | padding: 4px 10px;
364 | background: #999999;
365 | color: #ffffff;
366 | margin: 0 6px 6px 0;
367 | border-radius: 5px;
368 | cursor: pointer;
369 | transition: .2s;
370 | }
371 | .cat-holder .cat:hover, .cat-holder .cat.active {
372 | background: #49a37c;
373 | transition: .2s;
374 | }
375 | .cat-holder.na .cat, .cat-holder.na .cat:hover {cursor: default;}
376 |
377 | .checker {
378 | display: block;
379 | width: 16px;
380 | height: 16px;
381 | float: left;
382 | margin: 1px 6px 0 0;
383 | background: #efefef;
384 | border-radius: 50%;
385 | border: 2px solid #999999;
386 | transition: .3s;
387 | cursor: pointer;
388 | }
389 | .checker:hover, .checker.active {
390 | background: #c0f720;
391 | transition: .3s;
392 | }
393 | .logo-holder {
394 | max-width: 250px;
395 | overflow: hidden;
396 | margin: 10px 0;
397 | min-height: 50px;
398 | border-radius: 6px;
399 | background: #efefef;
400 | }
401 | .logo-holder img {
402 | width: 100%;
403 | height: auto;
404 | border-radius: 6px;
405 | }
406 |
407 | /************************* Теги ***************************/
408 |
409 | .tags-holder {
410 | border: 1px dashed #d5d5d5;
411 | border-radius: 5px;
412 | box-sizing: border-box;
413 | padding: 10px;
414 | min-height: 140px;
415 | }
416 | .tags-holder .t-item {
417 | display: inline-block;
418 | background: #a5a5a5;
419 | transition: .3s;
420 | cursor: pointer;
421 | color: #ffffff;
422 | padding: 4px 10px;
423 | margin: 4px 4px 0 0;
424 | font-size: 16px;
425 | border-radius: 5px;
426 | }
427 | .tags-holder .t-item {
428 | background: #39a090;
429 | padding: 4px 24px 4px 10px;
430 | position: relative;
431 | }
432 | .tags-holder .t-item.double {background: #a03213;}
433 | .tags-holder .t-item:after {
434 | content: '✕';
435 | transition: .2s;
436 | position: absolute;
437 | right: 4px; top: 7px;
438 | font-size: 10px;
439 | width: 14px;
440 | text-align: center;
441 | display: inline-block;
442 | padding: 1px;
443 | border-radius: 50%;
444 | }
445 | .tags-holder .t-item:hover:after {
446 | background: #ffffff;
447 | color: #39a090;
448 | transition: .2s;
449 | }
450 | .tags-holder .t-item.double:hover:after {color: #a03213;}
451 | .tag-holder {position: relative;}
452 | .autofill-bar {
453 | position: absolute;
454 | top: 60px;
455 | background: #ffffff;
456 | display: none;
457 | width: 100%;
458 | border-radius: 5px;
459 | overflow: hidden;
460 | }
461 | .autofill-bar span {
462 | display: block;
463 | box-sizing: border-box;
464 | padding: 6px 10px;
465 | border-bottom: 1px solid #d5d5d5;
466 | cursor: pointer;
467 | }
468 | .autofill-bar span:hover, .autofill-bar span.active {background: #ff9;}
469 | .autofill-bar span:last-child {border-bottom: none;}
470 | .tag-holder input, .tag-holder .autofill-bar {max-width: 540px;}
471 | .tag-holder .autofill-bar {border: 1px solid #d5d5d5;}
472 |
473 | /************************* Прелодеры ***************************/
474 | .loader {
475 | display: none;
476 | height: 15px;
477 | width: 128px;
478 | margin: 20px 50px 0 0;
479 | background: url("../images/general/ajax-loader.gif") no-repeat;
480 | }
481 | .button.working {opacity: .5;}
482 |
483 | /************************* Pop-up формы ***************************/
484 |
485 | .popup-holder {
486 | display: none;
487 | position: fixed;
488 | top: 0;
489 | left: 0;
490 | z-index: 99999;
491 | background: rgba(96,96,96,0.8);
492 | overflow: hidden;
493 | width: 100%;
494 | height: 100%;
495 | }
496 | .popup-content {
497 | position:fixed;
498 | z-index: 99999;
499 | width: 1100px;
500 | height: 600px;
501 | background-color: #f9f9f9;
502 | left: 50%;
503 | margin-left: -550px;
504 | top: 50%;
505 | margin-top: -300px;
506 | border-radius: 6px;
507 | box-sizing: border-box;
508 | }
509 | .popup-header {
510 | background: #5d5d5d;
511 | width: 100%;
512 | color: #ffffff;
513 | box-sizing: border-box;
514 | padding: 6px 12px;
515 | overflow: hidden;
516 | }
517 | .popup-content .button {margin: 0 10px 0 0;}
518 | .popup-content .full {
519 | box-sizing: border-box;
520 | padding: 20px;
521 | }
522 | .popup-content .full.centered {text-align: center;}
523 | .popup-content .full input {margin-bottom: 20px;}
524 | .popup-content .button {
525 | float: left;
526 | padding: 10px 20px;
527 | }
528 |
529 | /************************* Окно ошибок ***************************/
530 |
531 | .error-holder {
532 | position: fixed;
533 | top: 0;
534 | left: 35%;
535 | min-height: 14px;
536 | width: 28%;
537 | padding: 16px 1%;
538 | display: table;
539 | text-align: center;
540 | cursor: pointer;
541 | background-color: #e96161;
542 | border-radius: 10px;
543 | color: #ffffff; z-index: 999999; display: none;}
544 |
545 | .error-holder.error-holder-success {background-color: #35a63b;}
546 |
547 | /************************* Форма логина ***************************/
548 |
549 | .login {
550 | border: 2px solid #dadada;
551 | box-sizing: border-box;
552 | padding: 20px;
553 | border-radius: 5px;
554 | margin: auto;
555 | display: flex;
556 | flex-direction: column;
557 | justify-content: center;
558 | flex-wrap: wrap;
559 | }
560 | .login .button {
561 | padding: 10px 20px;
562 | text-align: center;
563 | max-width: 100px;
564 | margin: 20px auto 0;
565 | }
566 | .login input {min-width: 400px;}
567 |
568 | /************************* Плагин mediadescription ***************************/
569 |
570 | .temp {background: #b1d7fc;}
571 |
572 | .article-description {
573 | border: 1px dashed #d5d5d5;
574 | position: relative;
575 | border-radius: 6px; width: calc(100% - 42px);
576 | padding: 20px;
577 | margin: 4px 0 0 0;
578 | }
579 | .article-description .a-centered {text-align: center; display: block;}
580 | .article-description h2 {font-weight: bold; font-size: 22px; margin: 14px 0;}
581 | .article-description h3 {font-weight: bold; font-size: 18px; margin: 14px 0;}
582 | .article-description h4 {font-weight: bold; font-size: 16px; margin: 14px 0;}
583 | .article-description a {color: #b38cc9;}
584 |
585 | .md-menu-panel {
586 | position: absolute;
587 | overflow: hidden;
588 | display: none;
589 | }
590 | .md-menu-panel .mitem {
591 | background-repeat: no-repeat;
592 | background-position: center;
593 | background-repeat: no-repeat;
594 | background-position: center;
595 | font-weight: 700;
596 | background-color: rgba(0, 0, 0, .9);
597 | display: inline-block;
598 | float: left;
599 | color: #ffffff;
600 | font-size: 18px;
601 | padding: 5px;
602 | min-width: 30px;
603 | height: 30px;
604 | margin: 0 2px 0 0;
605 | cursor: pointer;
606 | text-align: center;
607 | line-height: 30px;
608 | border-radius: 50%;
609 | font-size: 16px;
610 | transition: .3s;
611 | position: relative;
612 | }
613 | .md-menu-panel .mitem:hover {
614 | background-color: #4BA7AF;
615 | transition: .3s;
616 | }
617 | .md-menu-panel .link-holder {
618 | overflow: hidden;
619 | display: none;
620 | }
621 | .md-menu-panel .link-holder .open-link {
622 | display: block;
623 | width: 16px;
624 | height: 16px;
625 | float: left;
626 | margin: 2px 2px 0 0;
627 | background: rgba(0,0,0,.75);
628 | border-radius: 50%;
629 | border: 5px solid rgba(0,0,0,.75);
630 | transition: .3s; cursor: pointer;
631 | }
632 | .md-menu-panel .link-holder .open-link:hover,
633 | .md-menu-panel .link-holder .open-link.active {
634 | background: #4BA7AF;
635 | transition: .3s;
636 | }
637 | .md-menu-panel .link-holder input {
638 | width: 200px;
639 | background: rgba(0,0,0,.75);
640 | color: #ffffff; font-size: 18px;
641 | float: left;
642 | border: none;
643 | padding: 4px 8px;
644 | border-radius: 20px;
645 | margin: 0;
646 | }
647 | .md-menu-panel .mitem.adescr-reset {
648 | background-image: url('../images/mediadescription/i-reset.png');
649 | background-size: 25px;
650 | }
651 | .md-menu-panel .mitem.adescr-bold {
652 | background-image: url('../images/mediadescription/i-bold.png');
653 | background-size: 25px;
654 | }
655 | .md-menu-panel .mitem.adescr-italic {
656 | background-image: url('../images/mediadescription/i-italic.png');
657 | background-size: 25px;}
658 |
659 | .md-menu-panel .mitem.adescr-strong {
660 | background-image: url('../images/mediadescription/i-strong.png');
661 | background-size: 25px;
662 | }
663 | .md-menu-panel .mitem.adescr-addlink {
664 | background-image: url('../images/mediadescription/i-link.png');
665 | background-size: 25px;
666 | }
667 | .md-menu-panel .mitem.adescr-centered {
668 | background-image: url('../images/mediadescription/i-center.png');
669 | background-size: 25px;
670 | }
671 |
--------------------------------------------------------------------------------
/scripts/admin/texthighlighter/jquery.texthighlighter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license jQuery Text Highlighter
3 | * Copyright (C) 2011 - 2013 by mirz
4 | *
5 | * Permission is hereby granted, free of charge, to any person obtaining a copy
6 | * of this software and associated documentation files (the "Software"), to deal
7 | * in the Software without restriction, including without limitation the rights
8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | * copies of the Software, and to permit persons to whom the Software is
10 | * furnished to do so, subject to the following conditions:
11 | *
12 | * The above copyright notice and this permission notice shall be included in
13 | * all copies or substantial portions of the Software.
14 | *
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | * THE SOFTWARE.
22 | */
23 |
24 | (function($, window, document, undefined) {
25 | var nodeTypes = {
26 | ELEMENT_NODE: 1,
27 | TEXT_NODE: 3
28 | };
29 |
30 | var plugin = {
31 | name: 'textHighlighter'
32 | };
33 |
34 | function TextHighlighter(element, options) {
35 | this.context = element;
36 | this.$context = $(element);
37 | this.options = $.extend({}, $[plugin.name].defaults, options);
38 |
39 | this.init();
40 | }
41 |
42 | TextHighlighter.prototype = {
43 | init: function() {
44 | this.$context.addClass(this.options.contextClass);
45 | this.bindEvents();
46 | },
47 |
48 | destroy: function() {
49 | this.unbindEvents();
50 | this.$context.removeClass(this.options.contextClass);
51 | this.$context.removeData(plugin.name);
52 | },
53 |
54 | bindEvents: function() {
55 | this.$context.bind('mouseup', {self: this}, this.highlightHandler);
56 | },
57 |
58 | unbindEvents: function() {
59 | this.$context.unbind('mouseup', this.highlightHandler);
60 | },
61 |
62 | highlightHandler: function(event) {
63 | var self = event.data.self;
64 | self.doHighlight();
65 | },
66 |
67 | /**
68 | * Highlights currently selected text.
69 | */
70 | doHighlight: function() {
71 | var range = this.getCurrentRange();
72 | if (!range || range.collapsed) return;
73 | var rangeText = range.toString();
74 |
75 | if (this.options.onBeforeHighlight(range) == true) {
76 | var $wrapper = $.textHighlighter.createWrapper(this.options);
77 |
78 | var createdHighlights = this.highlightRange(range, $wrapper);
79 | var normalizedHighlights = this.normalizeHighlights(createdHighlights);
80 |
81 | this.options.onAfterHighlight(normalizedHighlights, rangeText);
82 | }
83 |
84 | this.removeAllRanges();
85 | },
86 |
87 | /**
88 | * Returns first range of current selection object.
89 | */
90 | getCurrentRange: function() {
91 | var selection = this.getCurrentSelection();
92 |
93 | var range;
94 | if (selection.rangeCount > 0) {
95 | range = selection.getRangeAt(0);
96 | }
97 | return range;
98 | },
99 |
100 | removeAllRanges: function() {
101 | var selection = this.getCurrentSelection();
102 | selection.removeAllRanges();
103 | },
104 |
105 | /**
106 | * Returns current selection object.
107 | */
108 | getCurrentSelection: function() {
109 | var currentWindow = this.getCurrentWindow();
110 | var selection;
111 |
112 | if (currentWindow.getSelection) {
113 | selection = currentWindow.getSelection();
114 | } else if ($('iframe').length) {
115 | $('iframe', top.document).each(function() {
116 | if (this.contentWindow === currentWindow) {
117 | selection = rangy.getIframeSelection(this);
118 | return false;
119 | }
120 | });
121 | } else {
122 | selection = rangy.getSelection();
123 | }
124 |
125 | return selection;
126 | },
127 |
128 | /**
129 | * Returns owner window of this.context.
130 | */
131 | getCurrentWindow: function() {
132 | var currentDoc = this.getCurrentDocument();
133 | if (currentDoc.defaultView) {
134 | return currentDoc.defaultView; // Non-IE
135 | } else {
136 | return currentDoc.parentWindow; // IE
137 | }
138 | },
139 |
140 | /**
141 | * Returns owner document of this.context.
142 | */
143 | getCurrentDocument: function() {
144 | // if ownerDocument is null then context is document
145 | return this.context.ownerDocument ? this.context.ownerDocument : this.context;
146 | },
147 |
148 | /**
149 | * Wraps given range (highlights it) object in the given wrapper.
150 | */
151 | highlightRange: function(range, $wrapper) {
152 | if (range.collapsed) return;
153 |
154 | // Don't highlight content of these tags
155 | var ignoreTags = ['SCRIPT', 'STYLE', 'SELECT', 'BUTTON', 'OBJECT', 'APPLET'];
156 | var startContainer = range.startContainer;
157 | var endContainer = range.endContainer;
158 | var ancestor = range.commonAncestorContainer;
159 | var goDeeper = true;
160 |
161 | if (range.endOffset == 0) {
162 | while (!endContainer.previousSibling && endContainer.parentNode != ancestor) {
163 | endContainer = endContainer.parentNode;
164 | }
165 | endContainer = endContainer.previousSibling;
166 | } else if (endContainer.nodeType == nodeTypes.TEXT_NODE) {
167 | if (range.endOffset < endContainer.nodeValue.length) {
168 | endContainer.splitText(range.endOffset);
169 | }
170 | } else if (range.endOffset > 0) {
171 | endContainer = endContainer.childNodes.item(range.endOffset - 1);
172 | }
173 |
174 | if (startContainer.nodeType == nodeTypes.TEXT_NODE) {
175 | if (range.startOffset == startContainer.nodeValue.length) {
176 | goDeeper = false;
177 | } else if (range.startOffset > 0) {
178 | startContainer = startContainer.splitText(range.startOffset);
179 | if (endContainer == startContainer.previousSibling) endContainer = startContainer;
180 | }
181 | } else if (range.startOffset < startContainer.childNodes.length) {
182 | startContainer = startContainer.childNodes.item(range.startOffset);
183 | } else {
184 | startContainer = startContainer.nextSibling;
185 | }
186 |
187 | var done = false;
188 | var node = startContainer;
189 | var highlights = [];
190 |
191 | do {
192 | if (goDeeper && node.nodeType == nodeTypes.TEXT_NODE) {
193 | if (/\S/.test(node.nodeValue)) {
194 | var wrapper = $wrapper.clone(true).get(0);
195 | var nodeParent = node.parentNode;
196 |
197 | // highlight if node is inside the context
198 | if ($.contains(this.context, nodeParent) || nodeParent === this.context) {
199 | var highlight = $(node).wrap(wrapper).parent().get(0);
200 | highlights.push(highlight);
201 | }
202 | }
203 |
204 | goDeeper = false;
205 | }
206 | if (node == endContainer && (!endContainer.hasChildNodes() || !goDeeper)) {
207 | done = true;
208 | }
209 |
210 | if ($.inArray(node.tagName, ignoreTags) != -1) {
211 | goDeeper = false;
212 | }
213 | if (goDeeper && node.hasChildNodes()) {
214 | node = node.firstChild;
215 | } else if (node.nextSibling != null) {
216 | node = node.nextSibling;
217 | goDeeper = true;
218 | } else {
219 | node = node.parentNode;
220 | goDeeper = false;
221 | }
222 | } while (!done);
223 |
224 | return highlights;
225 | },
226 |
227 | /**
228 | * Normalizes highlights - nested highlights are flattened and sibling higlights are merged.
229 | */
230 | normalizeHighlights: function(highlights) {
231 | this.flattenNestedHighlights(highlights);
232 | this.mergeSiblingHighlights(highlights);
233 |
234 | // omit removed nodes
235 | var normalizedHighlights = $.map(highlights, function(hl) {
236 | if (typeof hl.parentElement != 'undefined') { // IE
237 | return hl.parentElement != null ? hl : null;
238 | } else {
239 | return hl.parentNode != null ? hl : null;
240 | }
241 | });
242 |
243 | return normalizedHighlights;
244 | },
245 |
246 | flattenNestedHighlights: function(highlights) {
247 | var self = this;
248 |
249 | $.each(highlights, function(i) {
250 | var $highlight = $(this);
251 | var $parent = $highlight.parent();
252 | var $parentPrev = $parent.prev();
253 | var $parentNext = $parent.next();
254 |
255 | if (self.isHighlight($parent)) {
256 | if ($parent.css('background-color') != $highlight.css('background-color')) {
257 | if (self.isHighlight($parentPrev) && !$highlight.get(0).previousSibling
258 | && $parentPrev.css('background-color') != $parent.css('background-color')
259 | && $parentPrev.css('background-color') == $highlight.css('background-color')) {
260 |
261 | $highlight.insertAfter($parentPrev);
262 | }
263 |
264 | if (self.isHighlight($parentNext) && !$highlight.get(0).nextSibling
265 | && $parentNext.css('background-color') != $parent.css('background-color')
266 | && $parentNext.css('background-color') == $highlight.css('background-color')) {
267 |
268 | $highlight.insertBefore($parentNext);
269 | }
270 |
271 | if ($parent.is(':empty')) {
272 | $parent.remove();
273 | }
274 | } else {
275 | var newNode = document.createTextNode($parent.text());
276 |
277 | $parent.empty();
278 | $parent.append(newNode);
279 | $(highlights[i]).remove();
280 | }
281 | }
282 | });
283 | },
284 |
285 | mergeSiblingHighlights: function(highlights) {
286 | var self = this;
287 |
288 | function shouldMerge(current, node) {
289 | return node && node.nodeType == nodeTypes.ELEMENT_NODE
290 | && $(current).css('background-color') == $(node).css('background-color')
291 | && $(node).hasClass(self.options.highlightedClass)
292 | ? true : false;
293 | }
294 |
295 | $.each(highlights, function() {
296 | var highlight = this;
297 |
298 | var prev = highlight.previousSibling;
299 | var next = highlight.nextSibling;
300 |
301 | if (shouldMerge(highlight, prev)) {
302 | var mergedTxt = $(prev).text() + $(highlight).text();
303 | $(highlight).text(mergedTxt);
304 | $(prev).remove();
305 | }
306 | if (shouldMerge(highlight, next)) {
307 | var mergedTxt = $(highlight).text() + $(next).text();
308 | $(highlight).text(mergedTxt);
309 | $(next).remove();
310 | }
311 | });
312 | },
313 |
314 | /**
315 | * Sets color of future highlights.
316 | */
317 | setColor: function(color) {
318 | this.options.color = color;
319 | },
320 |
321 | /**
322 | * Returns current highlights color.
323 | */
324 | getColor: function() {
325 | return this.options.color;
326 | },
327 |
328 | /**
329 | * Removes all highlights in given element or in context if no element given.
330 | */
331 | removeHighlights: function(element) {
332 | var container = (element !== undefined ? element : this.context);
333 |
334 | var unwrapHighlight = function(highlight) {
335 | return $(highlight).contents().unwrap().get(0);
336 | };
337 |
338 | var mergeSiblingTextNodes = function(textNode) {
339 | var prev = textNode.previousSibling;
340 | var next = textNode.nextSibling;
341 |
342 | if (prev && prev.nodeType == nodeTypes.TEXT_NODE) {
343 | textNode.nodeValue = prev.nodeValue + textNode.nodeValue;
344 | prev.parentNode.removeChild(prev);
345 | }
346 | if (next && next.nodeType == nodeTypes.TEXT_NODE) {
347 | textNode.nodeValue = textNode.nodeValue + next.nodeValue;
348 | next.parentNode.removeChild(next);
349 | }
350 | };
351 |
352 | var self = this;
353 | var $highlights = this.getAllHighlights(container, true);
354 | $highlights.each(function() {
355 | if (self.options.onRemoveHighlight(this) == true) {
356 | var textNode = unwrapHighlight(this);
357 | mergeSiblingTextNodes(textNode);
358 | }
359 | });
360 | },
361 |
362 | /**
363 | * Returns all highlights in given container. If container is a highlight itself and
364 | * andSelf is true, container will be also returned
365 | */
366 | getAllHighlights: function(container, andSelf) {
367 | var classSelectorStr = '.' + this.options.highlightedClass;
368 | var $highlights = $(container).find(classSelectorStr);
369 | if (andSelf == true && $(container).hasClass(this.options.highlightedClass)) {
370 | $highlights = $highlights.add(container);
371 | }
372 | return $highlights;
373 | },
374 |
375 | /**
376 | * Returns true if element is highlight, ie. has proper class.
377 | */
378 | isHighlight: function($el) {
379 | return $el.hasClass(this.options.highlightedClass);
380 | },
381 |
382 | /**
383 | * Serializes all highlights to stringified JSON object.
384 | */
385 | serializeHighlights: function() {
386 | var $highlights = this.getAllHighlights(this.context);
387 | var refEl = this.context;
388 | var hlDescriptors = [];
389 | var self = this;
390 |
391 | var getElementPath = function (el, refElement) {
392 | var path = [];
393 |
394 | do {
395 | var elIndex = $.inArray(el, el.parentNode.childNodes);
396 | path.unshift(elIndex);
397 | el = el.parentNode;
398 | } while (el !== refElement);
399 |
400 | return path;
401 | };
402 |
403 | $highlights.each(function(i, highlight) {
404 | var offset = 0; // Hl offset from previous sibling within parent node.
405 | var length = highlight.firstChild.length;
406 | var hlPath = getElementPath(highlight, refEl);
407 | var wrapper = $(highlight).clone().empty().get(0).outerHTML;
408 |
409 | if (highlight.previousSibling && highlight.previousSibling.nodeType === nodeTypes.TEXT_NODE) {
410 | offset = highlight.previousSibling.length;
411 | }
412 |
413 | hlDescriptors.push([
414 | wrapper,
415 | $(highlight).text(),
416 | hlPath.join(':'),
417 | offset,
418 | length
419 | ]);
420 | });
421 |
422 | return JSON.stringify(hlDescriptors);
423 | },
424 |
425 | /**
426 | * Deserializes highlights from stringified JSON given as parameter.
427 | */
428 | deserializeHighlights: function(json) {
429 | try {
430 | var hlDescriptors = JSON.parse(json);
431 | } catch (e) {
432 | throw "Can't parse serialized highlights: " + e;
433 | }
434 | var highlights = [];
435 | var self = this;
436 |
437 | var deserializationFn = function (hlDescriptor) {
438 | var wrapper = hlDescriptor[0];
439 | var hlText = hlDescriptor[1];
440 | var hlPath = hlDescriptor[2].split(':');
441 | var elOffset = hlDescriptor[3];
442 | var hlLength = hlDescriptor[4];
443 | var elIndex = hlPath.pop();
444 | var idx = null;
445 | var node = self.context;
446 |
447 | while ((idx = hlPath.shift()) !== undefined) {
448 | node = node.childNodes[idx];
449 | }
450 |
451 | if (node.childNodes[elIndex-1] && node.childNodes[elIndex-1].nodeType === nodeTypes.TEXT_NODE) {
452 | elIndex -= 1;
453 | }
454 |
455 | var textNode = node.childNodes[elIndex];
456 | var hlNode = textNode.splitText(elOffset);
457 | hlNode.splitText(hlLength);
458 |
459 | if (hlNode.nextSibling && hlNode.nextSibling.nodeValue == '') {
460 | hlNode.parentNode.removeChild(hlNode.nextSibling);
461 | }
462 |
463 | if (hlNode.previousSibling && hlNode.previousSibling.nodeValue == '') {
464 | hlNode.parentNode.removeChild(hlNode.previousSibling);
465 | }
466 |
467 | var highlight = $(hlNode).wrap(wrapper).parent().get(0);
468 | highlights.push(highlight);
469 | };
470 |
471 | $.each(hlDescriptors, function(i, hlDescriptor) {
472 | try {
473 | deserializationFn(hlDescriptor);
474 | } catch (e) {
475 | console && console.warn
476 | && console.warn("Can't deserialize " + i + "-th descriptor. Cause: " + e);
477 | return true;
478 | }
479 | });
480 |
481 | return highlights;
482 | }
483 |
484 | };
485 |
486 | /**
487 | * Returns TextHighlighter instance.
488 | */
489 | $.fn.getHighlighter = function() {
490 | return this.data(plugin.name);
491 | };
492 |
493 | $.fn[plugin.name] = function(options) {
494 | return this.each(function() {
495 | if (!$.data(this, plugin.name)) {
496 | $.data(this, plugin.name, new TextHighlighter(this, options));
497 | }
498 | });
499 | };
500 |
501 | $.textHighlighter = {
502 | /**
503 | * Returns HTML element to wrap selected text in.
504 | */
505 | createWrapper: function(options) {
506 | return $(' ')
507 | .css('backgroundColor', options.color)
508 | .addClass(options.highlightedClass);
509 | },
510 | defaults: {
511 | color: '#ffff7b',
512 | highlightedClass: 'highlighted',
513 | contextClass: 'highlighter-context',
514 | onRemoveHighlight: function() { return true; },
515 | onBeforeHighlight: function() { return true; },
516 | onAfterHighlight: function() { }
517 | }
518 | };
519 |
520 | })(jQuery, window, document);
521 |
--------------------------------------------------------------------------------
/scripts/admin/texthighlighter/rangy-core.js:
--------------------------------------------------------------------------------
1 | /*
2 | Rangy, a cross-browser JavaScript range and selection library
3 | http://code.google.com/p/rangy/
4 |
5 | Copyright 2012, Tim Down
6 | Licensed under the MIT license.
7 | Version: 1.2.3
8 | Build date: 26 February 2012
9 | */
10 | window.rangy=function(){function l(p,u){var w=typeof p[u];return w=="function"||!!(w=="object"&&p[u])||w=="unknown"}function K(p,u){return!!(typeof p[u]=="object"&&p[u])}function H(p,u){return typeof p[u]!="undefined"}function I(p){return function(u,w){for(var B=w.length;B--;)if(!p(u,w[B]))return false;return true}}function z(p){return p&&A(p,x)&&v(p,t)}function C(p){window.alert("Rangy not supported in your browser. Reason: "+p);c.initialized=true;c.supported=false}function N(){if(!c.initialized){var p,
11 | u=false,w=false;if(l(document,"createRange")){p=document.createRange();if(A(p,n)&&v(p,i))u=true;p.detach()}if((p=K(document,"body")?document.body:document.getElementsByTagName("body")[0])&&l(p,"createTextRange")){p=p.createTextRange();if(z(p))w=true}!u&&!w&&C("Neither Range nor TextRange are implemented");c.initialized=true;c.features={implementsDomRange:u,implementsTextRange:w};u=k.concat(f);w=0;for(p=u.length;w["+c.childNodes.length+"]":c.nodeName}function n(c){this._next=this.root=c}function t(c,f){this.node=c;this.offset=f}function x(c){this.code=this[c];
20 | this.codeName=c;this.message="DOMException: "+this.codeName}var A=l.util;A.areHostMethods(document,["createDocumentFragment","createElement","createTextNode"])||K.fail("document missing a Node creation method");A.isHostMethod(document,"getElementsByTagName")||K.fail("document missing getElementsByTagName method");var q=document.createElement("div");A.areHostMethods(q,["insertBefore","appendChild","cloneNode"])||K.fail("Incomplete Element implementation");A.isHostProperty(q,"innerHTML")||K.fail("Element is missing innerHTML property");
21 | q=document.createTextNode("test");A.areHostMethods(q,["splitText","deleteData","insertData","appendData","cloneNode"])||K.fail("Incomplete Text Node implementation");var v=function(c,f){for(var k=c.length;k--;)if(c[k]===f)return true;return false};n.prototype={_current:null,hasNext:function(){return!!this._next},next:function(){var c=this._current=this._next,f;if(this._current)if(f=c.firstChild)this._next=f;else{for(f=null;c!==this.root&&!(f=c.nextSibling);)c=c.parentNode;this._next=f}return this._current},
22 | detach:function(){this._current=this._next=this.root=null}};t.prototype={equals:function(c){return this.node===c.node&this.offset==c.offset},inspect:function(){return"[DomPosition("+i(this.node)+":"+this.offset+")]"}};x.prototype={INDEX_SIZE_ERR:1,HIERARCHY_REQUEST_ERR:3,WRONG_DOCUMENT_ERR:4,NO_MODIFICATION_ALLOWED_ERR:7,NOT_FOUND_ERR:8,NOT_SUPPORTED_ERR:9,INVALID_STATE_ERR:11};x.prototype.toString=function(){return this.message};l.dom={arrayContains:v,isHtmlNamespace:function(c){var f;return typeof c.namespaceURI==
23 | "undefined"||(f=c.namespaceURI)===null||f=="http://www.w3.org/1999/xhtml"},parentElement:function(c){c=c.parentNode;return c.nodeType==1?c:null},getNodeIndex:H,getNodeLength:function(c){var f;return C(c)?c.length:(f=c.childNodes)?f.length:0},getCommonAncestor:I,isAncestorOf:function(c,f,k){for(f=k?f:f.parentNode;f;)if(f===c)return true;else f=f.parentNode;return false},getClosestAncestorIn:z,isCharacterDataNode:C,insertAfter:N,splitDataNode:function(c,f){var k=c.cloneNode(false);k.deleteData(0,f);
24 | c.deleteData(f,c.length-f);N(k,c);return k},getDocument:O,getWindow:function(c){c=O(c);if(typeof c.defaultView!="undefined")return c.defaultView;else if(typeof c.parentWindow!="undefined")return c.parentWindow;else throw Error("Cannot get a window object for node");},getIframeWindow:function(c){if(typeof c.contentWindow!="undefined")return c.contentWindow;else if(typeof c.contentDocument!="undefined")return c.contentDocument.defaultView;else throw Error("getIframeWindow: No Window object found for iframe element");
25 | },getIframeDocument:function(c){if(typeof c.contentDocument!="undefined")return c.contentDocument;else if(typeof c.contentWindow!="undefined")return c.contentWindow.document;else throw Error("getIframeWindow: No Document object found for iframe element");},getBody:function(c){return A.isHostObject(c,"body")?c.body:c.getElementsByTagName("body")[0]},getRootContainer:function(c){for(var f;f=c.parentNode;)c=f;return c},comparePoints:function(c,f,k,r){var L;if(c==k)return f===r?0:f=e.childNodes.length?e.appendChild(a):e.insertBefore(a,e.childNodes[j]);return o}function O(a){for(var e,j,o=H(a.range).createDocumentFragment();j=a.next();){e=a.isPartiallySelectedSubtree();j=j.cloneNode(!e);if(e){e=a.getSubtreeIterator();j.appendChild(O(e));e.detach(true)}if(j.nodeType==10)throw new S("HIERARCHY_REQUEST_ERR");o.appendChild(j)}return o}function i(a,e,j){var o,E;for(j=j||{stop:false};o=a.next();)if(a.isPartiallySelectedSubtree())if(e(o)===
30 | false){j.stop=true;return}else{o=a.getSubtreeIterator();i(o,e,j);o.detach(true);if(j.stop)return}else for(o=g.createIterator(o);E=o.next();)if(e(E)===false){j.stop=true;return}}function n(a){for(var e;a.next();)if(a.isPartiallySelectedSubtree()){e=a.getSubtreeIterator();n(e);e.detach(true)}else a.remove()}function t(a){for(var e,j=H(a.range).createDocumentFragment(),o;e=a.next();){if(a.isPartiallySelectedSubtree()){e=e.cloneNode(false);o=a.getSubtreeIterator();e.appendChild(t(o));o.detach(true)}else a.remove();
31 | if(e.nodeType==10)throw new S("HIERARCHY_REQUEST_ERR");j.appendChild(e)}return j}function x(a,e,j){var o=!!(e&&e.length),E,T=!!j;if(o)E=RegExp("^("+e.join("|")+")$");var m=[];i(new q(a,false),function(s){if((!o||E.test(s.nodeType))&&(!T||j(s)))m.push(s)});return m}function A(a){return"["+(typeof a.getName=="undefined"?"Range":a.getName())+"("+g.inspectNode(a.startContainer)+":"+a.startOffset+", "+g.inspectNode(a.endContainer)+":"+a.endOffset+")]"}function q(a,e){this.range=a;this.clonePartiallySelectedTextNodes=
32 | e;if(!a.collapsed){this.sc=a.startContainer;this.so=a.startOffset;this.ec=a.endContainer;this.eo=a.endOffset;var j=a.commonAncestorContainer;if(this.sc===this.ec&&g.isCharacterDataNode(this.sc)){this.isSingleCharacterDataNode=true;this._first=this._last=this._next=this.sc}else{this._first=this._next=this.sc===j&&!g.isCharacterDataNode(this.sc)?this.sc.childNodes[this.so]:g.getClosestAncestorIn(this.sc,j,true);this._last=this.ec===j&&!g.isCharacterDataNode(this.ec)?this.ec.childNodes[this.eo-1]:g.getClosestAncestorIn(this.ec,
33 | j,true)}}}function v(a){this.code=this[a];this.codeName=a;this.message="RangeException: "+this.codeName}function c(a,e,j){this.nodes=x(a,e,j);this._next=this.nodes[0];this._position=0}function f(a){return function(e,j){for(var o,E=j?e:e.parentNode;E;){o=E.nodeType;if(g.arrayContains(a,o))return E;E=E.parentNode}return null}}function k(a,e){if(G(a,e))throw new v("INVALID_NODE_TYPE_ERR");}function r(a){if(!a.startContainer)throw new S("INVALID_STATE_ERR");}function L(a,e){if(!g.arrayContains(e,a.nodeType))throw new v("INVALID_NODE_TYPE_ERR");
34 | }function p(a,e){if(e<0||e>(g.isCharacterDataNode(a)?a.length:a.childNodes.length))throw new S("INDEX_SIZE_ERR");}function u(a,e){if(h(a,true)!==h(e,true))throw new S("WRONG_DOCUMENT_ERR");}function w(a){if(D(a,true))throw new S("NO_MODIFICATION_ALLOWED_ERR");}function B(a,e){if(!a)throw new S(e);}function V(a){return!!a.startContainer&&!!a.endContainer&&!(!g.arrayContains(ba,a.startContainer.nodeType)&&!h(a.startContainer,true))&&!(!g.arrayContains(ba,a.endContainer.nodeType)&&!h(a.endContainer,
35 | true))&&a.startOffset<=(g.isCharacterDataNode(a.startContainer)?a.startContainer.length:a.startContainer.childNodes.length)&&a.endOffset<=(g.isCharacterDataNode(a.endContainer)?a.endContainer.length:a.endContainer.childNodes.length)}function J(a){r(a);if(!V(a))throw Error("Range error: Range is no longer valid after DOM mutation ("+a.inspect()+")");}function ca(){}function Y(a){a.START_TO_START=ia;a.START_TO_END=la;a.END_TO_END=ra;a.END_TO_START=ma;a.NODE_BEFORE=na;a.NODE_AFTER=oa;a.NODE_BEFORE_AND_AFTER=
36 | pa;a.NODE_INSIDE=ja}function W(a){Y(a);Y(a.prototype)}function da(a,e){return function(){J(this);var j=this.startContainer,o=this.startOffset,E=this.commonAncestorContainer,T=new q(this,true);if(j!==E){j=g.getClosestAncestorIn(j,E,true);o=C(j);j=o.node;o=o.offset}i(T,w);T.reset();E=a(T);T.detach();e(this,j,o,j,o);return E}}function fa(a,e,j){function o(m,s){return function(y){r(this);L(y,$);L(d(y),ba);y=(m?z:C)(y);(s?E:T)(this,y.node,y.offset)}}function E(m,s,y){var F=m.endContainer,Q=m.endOffset;
37 | if(s!==m.startContainer||y!==m.startOffset){if(d(s)!=d(F)||g.comparePoints(s,y,F,Q)==1){F=s;Q=y}e(m,s,y,F,Q)}}function T(m,s,y){var F=m.startContainer,Q=m.startOffset;if(s!==m.endContainer||y!==m.endOffset){if(d(s)!=d(F)||g.comparePoints(s,y,F,Q)==-1){F=s;Q=y}e(m,F,Q,s,y)}}a.prototype=new ca;l.util.extend(a.prototype,{setStart:function(m,s){r(this);k(m,true);p(m,s);E(this,m,s)},setEnd:function(m,s){r(this);k(m,true);p(m,s);T(this,m,s)},setStartBefore:o(true,true),setStartAfter:o(false,true),setEndBefore:o(true,
38 | false),setEndAfter:o(false,false),collapse:function(m){J(this);m?e(this,this.startContainer,this.startOffset,this.startContainer,this.startOffset):e(this,this.endContainer,this.endOffset,this.endContainer,this.endOffset)},selectNodeContents:function(m){r(this);k(m,true);e(this,m,0,m,g.getNodeLength(m))},selectNode:function(m){r(this);k(m,false);L(m,$);var s=z(m);m=C(m);e(this,s.node,s.offset,m.node,m.offset)},extractContents:da(t,e),deleteContents:da(n,e),canSurroundContents:function(){J(this);w(this.startContainer);
39 | w(this.endContainer);var m=new q(this,true),s=m._first&&K(m._first,this)||m._last&&K(m._last,this);m.detach();return!s},detach:function(){j(this)},splitBoundaries:function(){J(this);var m=this.startContainer,s=this.startOffset,y=this.endContainer,F=this.endOffset,Q=m===y;g.isCharacterDataNode(y)&&F>0&&F0&&s=g.getNodeIndex(m)&&F++;s=0}e(this,m,s,y,F)},normalizeBoundaries:function(){J(this);
40 | var m=this.startContainer,s=this.startOffset,y=this.endContainer,F=this.endOffset,Q=function(U){var R=U.nextSibling;if(R&&R.nodeType==U.nodeType){y=U;F=U.length;U.appendData(R.data);R.parentNode.removeChild(R)}},qa=function(U){var R=U.previousSibling;if(R&&R.nodeType==U.nodeType){m=U;var sa=U.length;s=R.length;U.insertData(0,R.data);R.parentNode.removeChild(R);if(m==y){F+=s;y=m}else if(y==U.parentNode){R=g.getNodeIndex(U);if(F==R){y=U;F=sa}else F>R&&F--}}},ga=true;if(g.isCharacterDataNode(y))y.length==
41 | F&&Q(y);else{if(F>0)(ga=y.childNodes[F-1])&&g.isCharacterDataNode(ga)&&Q(ga);ga=!this.collapsed}if(ga)if(g.isCharacterDataNode(m))s==0&&qa(m);else{if(sx";X=P.firstChild.nodeType==3}catch(ta){}l.features.htmlParsingConforms=X;var ka=["startContainer","startOffset","endContainer","endOffset",
47 | "collapsed","commonAncestorContainer"],ia=0,la=1,ra=2,ma=3,na=0,oa=1,pa=2,ja=3;ca.prototype={attachListener:function(a,e){this._listeners[a].push(e)},compareBoundaryPoints:function(a,e){J(this);u(this.startContainer,e.startContainer);var j=a==ma||a==ia?"start":"end",o=a==la||a==ia?"start":"end";return g.comparePoints(this[j+"Container"],this[j+"Offset"],e[o+"Container"],e[o+"Offset"])},insertNode:function(a){J(this);L(a,aa);w(this.startContainer);if(g.isAncestorOf(a,this.startContainer,true))throw new S("HIERARCHY_REQUEST_ERR");
48 | this.setStartBefore(N(a,this.startContainer,this.startOffset))},cloneContents:function(){J(this);var a,e;if(this.collapsed)return H(this).createDocumentFragment();else{if(this.startContainer===this.endContainer&&g.isCharacterDataNode(this.startContainer)){a=this.startContainer.cloneNode(true);a.data=a.data.slice(this.startOffset,this.endOffset);e=H(this).createDocumentFragment();e.appendChild(a);return e}else{e=new q(this,true);a=O(e);e.detach()}return a}},canSurroundContents:function(){J(this);w(this.startContainer);
49 | w(this.endContainer);var a=new q(this,true),e=a._first&&K(a._first,this)||a._last&&K(a._last,this);a.detach();return!e},surroundContents:function(a){L(a,b);if(!this.canSurroundContents())throw new v("BAD_BOUNDARYPOINTS_ERR");var e=this.extractContents();if(a.hasChildNodes())for(;a.lastChild;)a.removeChild(a.lastChild);N(a,this.startContainer,this.startOffset);a.appendChild(e);this.selectNode(a)},cloneRange:function(){J(this);for(var a=new M(H(this)),e=ka.length,j;e--;){j=ka[e];a[j]=this[j]}return a},
50 | toString:function(){J(this);var a=this.startContainer;if(a===this.endContainer&&g.isCharacterDataNode(a))return a.nodeType==3||a.nodeType==4?a.data.slice(this.startOffset,this.endOffset):"";else{var e=[];a=new q(this,true);i(a,function(j){if(j.nodeType==3||j.nodeType==4)e.push(j.data)});a.detach();return e.join("")}},compareNode:function(a){J(this);var e=a.parentNode,j=g.getNodeIndex(a);if(!e)throw new S("NOT_FOUND_ERR");a=this.comparePoint(e,j);e=this.comparePoint(e,j+1);return a<0?e>0?pa:na:e>0?
51 | oa:ja},comparePoint:function(a,e){J(this);B(a,"HIERARCHY_REQUEST_ERR");u(a,this.startContainer);if(g.comparePoints(a,e,this.startContainer,this.startOffset)<0)return-1;else if(g.comparePoints(a,e,this.endContainer,this.endOffset)>0)return 1;return 0},createContextualFragment:X?function(a){var e=this.startContainer,j=g.getDocument(e);if(!e)throw new S("INVALID_STATE_ERR");var o=null;if(e.nodeType==1)o=e;else if(g.isCharacterDataNode(e))o=g.parentElement(e);o=o===null||o.nodeName=="HTML"&&g.isHtmlNamespace(g.getDocument(o).documentElement)&&
52 | g.isHtmlNamespace(o)?j.createElement("body"):o.cloneNode(false);o.innerHTML=a;return g.fragmentFromNodeChildren(o)}:function(a){r(this);var e=H(this).createElement("body");e.innerHTML=a;return g.fragmentFromNodeChildren(e)},toHtml:function(){J(this);var a=H(this).createElement("div");a.appendChild(this.cloneContents());return a.innerHTML},intersectsNode:function(a,e){J(this);B(a,"NOT_FOUND_ERR");if(g.getDocument(a)!==H(this))return false;var j=a.parentNode,o=g.getNodeIndex(a);B(j,"NOT_FOUND_ERR");
53 | var E=g.comparePoints(j,o,this.endContainer,this.endOffset);j=g.comparePoints(j,o+1,this.startContainer,this.startOffset);return e?E<=0&&j>=0:E<0&&j>0},isPointInRange:function(a,e){J(this);B(a,"HIERARCHY_REQUEST_ERR");u(a,this.startContainer);return g.comparePoints(a,e,this.startContainer,this.startOffset)>=0&&g.comparePoints(a,e,this.endContainer,this.endOffset)<=0},intersectsRange:function(a,e){J(this);if(H(a)!=H(this))throw new S("WRONG_DOCUMENT_ERR");var j=g.comparePoints(this.startContainer,
54 | this.startOffset,a.endContainer,a.endOffset),o=g.comparePoints(this.endContainer,this.endOffset,a.startContainer,a.startOffset);return e?j<=0&&o>=0:j<0&&o>0},intersection:function(a){if(this.intersectsRange(a)){var e=g.comparePoints(this.startContainer,this.startOffset,a.startContainer,a.startOffset),j=g.comparePoints(this.endContainer,this.endOffset,a.endContainer,a.endOffset),o=this.cloneRange();e==-1&&o.setStart(a.startContainer,a.startOffset);j==1&&o.setEnd(a.endContainer,a.endOffset);return o}return null},
55 | union:function(a){if(this.intersectsRange(a,true)){var e=this.cloneRange();g.comparePoints(a.startContainer,a.startOffset,this.startContainer,this.startOffset)==-1&&e.setStart(a.startContainer,a.startOffset);g.comparePoints(a.endContainer,a.endOffset,this.endContainer,this.endOffset)==1&&e.setEnd(a.endContainer,a.endOffset);return e}else throw new v("Ranges do not intersect");},containsNode:function(a,e){return e?this.intersectsNode(a,false):this.compareNode(a)==ja},containsNodeContents:function(a){return this.comparePoint(a,
56 | 0)>=0&&this.comparePoint(a,g.getNodeLength(a))<=0},containsRange:function(a){return this.intersection(a).equals(a)},containsNodeText:function(a){var e=this.cloneRange();e.selectNode(a);var j=e.getNodes([3]);if(j.length>0){e.setStart(j[0],0);a=j.pop();e.setEnd(a,a.length);a=this.containsRange(e);e.detach();return a}else return this.containsNodeContents(a)},createNodeIterator:function(a,e){J(this);return new c(this,a,e)},getNodes:function(a,e){J(this);return x(this,a,e)},getDocument:function(){return H(this)},
57 | collapseBefore:function(a){r(this);this.setEndBefore(a);this.collapse(false)},collapseAfter:function(a){r(this);this.setStartAfter(a);this.collapse(true)},getName:function(){return"DomRange"},equals:function(a){return M.rangesEqual(this,a)},isValid:function(){return V(this)},inspect:function(){return A(this)}};fa(M,ha,function(a){r(a);a.startContainer=a.startOffset=a.endContainer=a.endOffset=null;a.collapsed=a.commonAncestorContainer=null;I(a,"detach",null);a._listeners=null});l.rangePrototype=ca.prototype;
58 | M.rangeProperties=ka;M.RangeIterator=q;M.copyComparisonConstants=W;M.createPrototypeRange=fa;M.inspect=A;M.getRangeDocument=H;M.rangesEqual=function(a,e){return a.startContainer===e.startContainer&&a.startOffset===e.startOffset&&a.endContainer===e.endContainer&&a.endOffset===e.endOffset};l.DomRange=M;l.RangeException=v});
59 | rangy.createModule("WrappedRange",function(l){function K(i,n,t,x){var A=i.duplicate();A.collapse(t);var q=A.parentElement();z.isAncestorOf(n,q,true)||(q=n);if(!q.canHaveHTML)return new C(q.parentNode,z.getNodeIndex(q));n=z.getDocument(q).createElement("span");var v,c=t?"StartToStart":"StartToEnd";do{q.insertBefore(n,n.previousSibling);A.moveToElementText(n)}while((v=A.compareEndPoints(c,i))>0&&n.previousSibling);c=n.nextSibling;if(v==-1&&c&&z.isCharacterDataNode(c)){A.setEndPoint(t?"EndToStart":"EndToEnd",
60 | i);if(/[\r\n]/.test(c.data)){q=A.duplicate();t=q.text.replace(/\r\n/g,"\r").length;for(t=q.moveStart("character",t);q.compareEndPoints("StartToEnd",q)==-1;){t++;q.moveStart("character",1)}}else t=A.text.length;q=new C(c,t)}else{c=(x||!t)&&n.previousSibling;q=(t=(x||t)&&n.nextSibling)&&z.isCharacterDataNode(t)?new C(t,0):c&&z.isCharacterDataNode(c)?new C(c,c.length):new C(q,z.getNodeIndex(n))}n.parentNode.removeChild(n);return q}function H(i,n){var t,x,A=i.offset,q=z.getDocument(i.node),v=q.body.createTextRange(),
61 | c=z.isCharacterDataNode(i.node);if(c){t=i.node;x=t.parentNode}else{t=i.node.childNodes;t=A12");d.close();var h=c.getIframeWindow(b).getSelection(),D=d.documentElement.lastChild.firstChild;d=d.createRange();d.setStart(D,1);d.collapse(true);h.addRange(d);ha=h.rangeCount==1;h.removeAllRanges();var G=d.cloneRange();d.setStart(D,0);G.setEnd(D,2);h.addRange(d);h.addRange(G);ea=h.rangeCount==2;d.detach();G.detach();Y.removeChild(b)}();l.features.selectionSupportsMultipleRanges=ea;
81 | l.features.collapsedNonEditableSelectionsSupported=ha;var M=false,g;if(Y&&f.isHostMethod(Y,"createControlRange")){g=Y.createControlRange();if(f.areHostProperties(g,["item","add"]))M=true}l.features.implementsControlRange=M;w=W?function(b){return b.anchorNode===b.focusNode&&b.anchorOffset===b.focusOffset}:function(b){return b.rangeCount?b.getRangeAt(b.rangeCount-1).collapsed:false};var Z;if(f.isHostMethod(B,"getRangeAt"))Z=function(b,d){try{return b.getRangeAt(d)}catch(h){return null}};else if(W)Z=
82 | function(b){var d=c.getDocument(b.anchorNode);d=l.createRange(d);d.setStart(b.anchorNode,b.anchorOffset);d.setEnd(b.focusNode,b.focusOffset);if(d.collapsed!==this.isCollapsed){d.setStart(b.focusNode,b.focusOffset);d.setEnd(b.anchorNode,b.anchorOffset)}return d};l.getSelection=function(b){b=b||window;var d=b._rangySelection,h=u(b),D=V?I(b):null;if(d){d.nativeSelection=h;d.docSelection=D;d.refresh(b)}else{d=new x(h,D,b);b._rangySelection=d}return d};l.getIframeSelection=function(b){return l.getSelection(c.getIframeWindow(b))};
83 | g=x.prototype;if(!J&&W&&f.areHostMethods(B,["removeAllRanges","addRange"])){g.removeAllRanges=function(){this.nativeSelection.removeAllRanges();C(this)};var S=function(b,d){var h=k.getRangeDocument(d);h=l.createRange(h);h.collapseToPoint(d.endContainer,d.endOffset);b.nativeSelection.addRange(N(h));b.nativeSelection.extend(d.startContainer,d.startOffset);b.refresh()};g.addRange=fa?function(b,d){if(M&&V&&this.docSelection.type=="Control")t(this,b);else if(d&&da)S(this,b);else{var h;if(ea)h=this.rangeCount;
84 | else{this.removeAllRanges();h=0}this.nativeSelection.addRange(N(b));this.rangeCount=this.nativeSelection.rangeCount;if(this.rangeCount==h+1){if(l.config.checkSelectionRanges)if((h=Z(this.nativeSelection,this.rangeCount-1))&&!k.rangesEqual(h,b))b=new r(h);this._ranges[this.rangeCount-1]=b;z(this,b,aa(this.nativeSelection));this.isCollapsed=w(this)}else this.refresh()}}:function(b,d){if(d&&da)S(this,b);else{this.nativeSelection.addRange(N(b));this.refresh()}};g.setRanges=function(b){if(M&&b.length>
85 | 1)A(this,b);else{this.removeAllRanges();for(var d=0,h=b.length;d1)A(this,b);else d&&this.addRange(b[0])}}else{K.fail("No means of selecting a Range or TextRange was found");return false}g.getRangeAt=function(b){if(b<0||b>=this.rangeCount)throw new L("INDEX_SIZE_ERR");else return this._ranges[b]};
87 | var $;if(J)$=function(b){var d;if(l.isSelectionValid(b.win))d=b.docSelection.createRange();else{d=c.getBody(b.win.document).createTextRange();d.collapse(true)}if(b.docSelection.type=="Control")n(b);else d&&typeof d.text!="undefined"?i(b,d):C(b)};else if(f.isHostMethod(B,"getRangeAt")&&typeof B.rangeCount=="number")$=function(b){if(M&&V&&b.docSelection.type=="Control")n(b);else{b._ranges.length=b.rangeCount=b.nativeSelection.rangeCount;if(b.rangeCount){for(var d=0,h=b.rangeCount;d