├── 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 | Админ-панель 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
Введите свой логин и пароль
18 |
19 |
20 | 21 | 22 |
23 | Error 24 |
25 | 26 |
27 |
28 | 29 | 42 | 43 |
44 |
45 | 46 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /scripts/client/main.js: -------------------------------------------------------------------------------- 1 | 2 | $(document).ready(function () { 3 | 4 | $('body').on('click', '.more', function () { 5 | 6 | var button = $(this); 7 | 8 | //------------- контейнер для вставки статей 9 | var container = $('.article-holder'); 10 | 11 | //------------- ссылка на бэкэнд для запроса "Больше статей" 12 | var postLink = '/'; 13 | 14 | if (!button.hasClass('working')){ 15 | button.addClass('working'); 16 | 17 | //------------- атрибуты для передачи на бэкэнд 18 | var data = {}; 19 | data.action = 'more'; 20 | 21 | //------------- ajax-запрос 22 | $.ajax({ 23 | url: postLink, 24 | type: 'POST', 25 | dataType: 'json', 26 | data: data, 27 | success: function(data) { 28 | }, 29 | error: function(data){ 30 | button.removeClass('working'); 31 | } 32 | }).done(function(data){ 33 | //---------------- результаты с бэкэнда 34 | //---------------- data.html - массив статей для вставки 35 | //---------------- data.last - нужна ли кнопка Больше 36 | container.append(data.html); 37 | if (data.last){ 38 | button.removeClass('working'); 39 | } else { 40 | button.remove(); 41 | } 42 | }); 43 | } 44 | }); 45 | }); 46 | 47 | $(window).load(function(){ 48 | 49 | var winHeight = $(document).height(); 50 | var step = 4; 51 | var timeToScroll = winHeight/step; 52 | 53 | $('.scrolltop').on('click', function(){ 54 | 55 | $('html, body').animate({ 56 | scrollTop: 0 57 | }, timeToScroll); 58 | }); 59 | 60 | }); -------------------------------------------------------------------------------- /scripts/admin/login.js: -------------------------------------------------------------------------------- 1 | 2 | //================================================================// 3 | //*********** login.js 4 | //*********** © Aida Drogan - #BlondieCode 5 | //*********** Описание поведения формы логина (страница login.html) 6 | //*********** Проверка полей формы логина на валидность 7 | //*********** ajax-запрос на авторизацию 8 | //================================================================// 9 | 10 | $(document).ready(function(){ 11 | 12 | //---------------------------- фильтры для проверки полей на недопустимые символы 13 | //---------------------------- https://www.sitepoint.com/expressions-javascript/ 14 | var filterUsername = /^([a-zA-Z0-9_\-])+$/; 15 | var filterPassword = /^[a-zA-Z0-9!%&@#$\^*?_~+]+$/; 16 | 17 | $('#pass').on('keyup', function(e){ 18 | //---------------------------- если пользователь нажал enter 19 | if (e.keyCode == 13){ 20 | $('.b-login').click(); 21 | } 22 | }); 23 | 24 | //=========================== Кнопка войти ==========================// 25 | 26 | $('.b-login').on("click", function(){ 27 | 28 | //---------------------------- параметры для авторизации 29 | var data = {}; 30 | data.username = $('#username').val(); 31 | data.password = $('#pass').val(); 32 | 33 | if (data.username == ''){ 34 | //-------------------- showError(text, top) функция для отображения ошибки 35 | //-------------------- text - текст сообщения 36 | //-------------------- top - отступ от верха страницы 37 | showError('Пожалуйста введите свое имя!', 50); 38 | } else if (data.password == ''){ 39 | showError('Пожалуйста введите свой пароль!', 50); 40 | } else if (!filterUsername.test(data.username)){ 41 | showError('Недопустимые символы в имени', 50); 42 | } else if(!filterPassword.test(data.password)) { 43 | showError('Недопустимые символы в пароле', 50); 44 | } else { 45 | 46 | //----------------------- ajax-запрос на авторизацию 47 | showSuccess('Авторизация', 50); 48 | } 49 | }) 50 | }); -------------------------------------------------------------------------------- /scripts/admin/error.js: -------------------------------------------------------------------------------- 1 | 2 | //================================================================// 3 | //*********** error.js 4 | //*********** © Aida Drogan - #BlondieCode 5 | //*********** Функционал окна с сообщением об ошибке (
) 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('noimage'); 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 | #BlondieBlog 23 | 24 | 25 |
26 | 27 | 48 | 49 | 50 | 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('
' + tag + '
'); 37 | } 38 | 39 | } 40 | 41 | function checkTag(input){ 42 | 43 | if (input.val().length > 1){ 44 | 45 | //------------ данные для ajax-запроса 46 | var data = {}; 47 | data.key = input.val(); 48 | 49 | //------------ ajax-запрос для выборки из базы на подстановку 50 | //------------ result - массив тегов (ответ от сервера) 51 | 52 | var result = ['кот', 'любовь', 'няшка']; 53 | 54 | //------------ по завершении ajax-запроса парсим массив в контейнер подстановки 55 | iContainer.children().remove(); 56 | for (var i=0; i' + 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 |
17 | Выход 18 | Разделы 19 |
20 |
21 |
22 | 23 | 24 |
25 | Error 26 |
27 | 28 |
29 | 32 | 35 |
36 | 37 |
38 |
39 | Любовь к няшным котикам 40 |
41 |
Любовь к няшным котикам
42 |
43 | Создана: Вт, 31. Янв 2017, в 19:9 44 | Обновлена: Пт, 10. Фев 2017, в 16:56 45 |
46 |
47 | Не опубликована 48 |
49 |
50 | Редактор 51 |
52 |
53 | 54 |
55 |
56 | Что можно сделать из пластиковой бутылки 57 |
58 |
Что можно сделать из пластиковой бутылки
59 |
60 | Создана: Пт, 27. Янв 2017, в 21:59 61 | Обновлена: Пн, 30. Янв 2017, в 18:40 62 |
63 |
64 | Опубликована 65 |
66 |
67 | Редактор 68 |
69 |
70 |
71 |
72 | Тима и Няша в детстве 73 |
74 |
Тима и Няша в детстве
75 |
76 | Создана: Пт, 27. Янв 2017, в 21:59 77 | Обновлена: Пт, 27. Янв 2017, в 22:3 78 |
79 |
80 | Опубликована 81 |
82 |
83 | Редактор 84 |
85 |
86 |
87 |
88 | Как Боня читал сценарий к этому видео 89 |
90 |
Как Боня читал сценарий к этому видео
91 |
92 | Создана: Пт, 27. Янв 2017, в 18:43 93 | Обновлена: Пт, 27. Янв 2017, в 21:46 94 |
95 |
96 | Опубликована 97 |
98 |
99 | Редактор 100 |
101 |
102 |
103 |
104 | 105 | 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 |
22 | Выход 23 | Разделы 24 |
25 |
26 |
27 | 28 | 29 |
30 | Error 31 |
32 | 33 |
34 |
35 |
Добавить категорию +
36 |
37 |
38 |
39 |
    40 | 41 |
  • 42 |
    43 | Добро пожаловать на BlondieBlog 44 | Главная страница (0 статей) 45 |
    46 |
    47 | Редактор 48 |
    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 |
    99 | Статьи 100 | Редактор 101 |
    102 |
  • 103 |
  • 104 |
    105 | Без кота жизнь не та 106 | 8 статей 107 |
    108 |
    109 | Статьи 110 | Редактор 111 |
    112 |
  • 113 |
  • 114 |
    115 | Кот - это на всю жизнь 116 | 5 статей 117 |
    118 |
    119 | Статьи 120 | Редактор 121 |
    122 |
  • 123 |
124 |
125 |
126 |
127 | 128 | 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 |
25 | Выход 26 | Разделы 27 |
28 |
29 |
30 | 31 | 32 |
33 | Error 34 |
35 | 36 |
37 | 38 |
39 | de 40 | en 41 | ru 42 |
43 | 44 | 45 |
46 |
47 |
48 | 49 | 50 |
51 |
52 | 53 | 54 |
55 |
56 | 57 | 58 |
59 |
60 |
61 |
62 | 63 | 64 |
65 |
66 | 67 | 68 |
69 |
70 | 71 | 72 |
73 |
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 |
131 |
132 |
133 |
Сохранить
134 |
Удалить
135 | Отмена 136 |
137 |
138 | 139 |
140 | 141 | 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 |
26 | Выход 27 | Разделы 28 |
29 |
30 |
31 | 32 | 33 |
34 | Error 35 |
36 | 37 |
38 | 39 |
40 | de 41 | en 42 | ru 43 |
44 | 45 | 46 |
47 | 48 |
49 | 50 |
51 |
52 |
+ Добавить
53 |
Удалить
54 |
55 | 56 |
57 |
58 |
59 |
60 |
61 |
62 | 63 | 64 |
65 |
66 | 67 | 68 |
69 |
70 | Категории статьи 71 |
72 |
Няшные котики
73 |
Боня - король вечеринок
74 |
Настоящие леди
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 |
102 | 103 |
104 |
105 |
106 |
107 |
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 |
142 |
143 |
Сохранить
144 |
Удалить
145 | Отмена 146 |
147 |
148 |
149 | 150 |
151 | 152 | 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 | #BlondieBlog 23 | 24 | 25 |
26 | 27 | 48 | 49 | 50 | 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 | '
    ' + 78 | 'Статьи' + 79 | 'Редактор' + 80 | '
    ' + 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 | #BlondieBlog 23 | 24 | 25 |
    26 | 27 | 48 | 49 | 50 | 63 | 64 |
    65 |
    66 |
    67 |

    Добро пожаловать на BlondieBlog

    68 | Я очень рада видеть вас на своем блоге! 69 | Больше фишек на моем канале! 70 |
    71 | 72 | 85 | 86 | 99 | 112 | 125 | 138 | 151 | 164 | 177 | 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 | '
    ' + 45 | 'Редактор' + 46 | '
    ' + 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('
    ' + 31 | '
    ' + 32 | '
    ' + 33 | '
    ' + 34 | '
    H2
    ' + 35 | '
    H3
    ' + 36 | '
    H4
    ' + 37 | '
    ' + 38 | '
    ' + 39 | '' + 40 | '' + 41 | '
    '); 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 + ''); 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 + ''); 198 | } else { 199 | href = $(this).after('<' + type + ' href="' + cclass + '" rel="nofollow" target="_blank">' + str + ''); 200 | } 201 | 202 | if (href.parent().is('a')){ 203 | href.unwrap(); 204 | } 205 | } 206 | 207 | } else { 208 | 209 | var h = $(this).after('<' + type + '>' + str + ''); 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