diff --git a/ce_interface.js b/ce_interface.js index 3760bc71..aa098b53 100644 --- a/ce_interface.js +++ b/ce_interface.js @@ -45,7 +45,7 @@ var ce = function(settings) { }; // All posible tools -ce.prototype.allTools = ['header', 'picture', 'list', 'quote', 'code', 'twitter', 'instagram', 'smile']; +ce.prototype.allTools = ['header', 'picture', 'list', 'quote', 'code', 'link', 'twitter', 'instagram', 'smile']; // Default settings configuration ce.prototype.defaultSettings = { diff --git a/codex-editor.js b/codex-editor.js index 43e12a87..ac9b0cee 100644 --- a/codex-editor.js +++ b/codex-editor.js @@ -254,6 +254,7 @@ cEditor.renderer = { }, + /** * Asynchronously returns block data from blocksList by index * @return Promise to node @@ -926,18 +927,6 @@ cEditor.content = { newBlock.classList.add(cEditor.ui.BLOCK_CLASSNAME); newBlock.dataset.type = blockType; - - /** Content-editable blocks. We can set focus to such blocks and hang listeners */ - switch (blockType) { - case 'header' : - case 'paragraph': - case 'quote' : - case 'list' : - cEditor.ui.addBlockHandlers(newBlock); - break; - - } - if (workingNode) { cEditor.core.insertAfter(workingNode, newBlock); @@ -949,13 +938,12 @@ cEditor.content = { */ cEditor.nodes.redactor.appendChild(newBlock); - /** - * Set new node as current - */ - cEditor.content.workingNodeChanged(newBlock); } - + /** + * Set new node as current + */ + cEditor.content.workingNodeChanged(newBlock); }, /** @@ -1853,7 +1841,7 @@ var paragraphTool = { /** * Make initial header block - * @param {object} JSON to with block data + * @param {object} JSON with block data * @return {Element} element to append */ make : function (data) { @@ -1920,7 +1908,7 @@ var headerTool = { /** * Make initial header block - * @param {object} JSON to with block data + * @param {object} JSON with block data * @return {Element} element to append */ make : function (data) { @@ -2090,360 +2078,3 @@ cEditor.tools.header = { save : headerTool.save }; - - -/** QUOTE PLUGIN **/ - -var quoteTools = { - - captionPlaceholder : 'Введите имя автора', - jobPlacaholder : 'Введите должность', - /** - * Make Quote from JSON datasets - */ - makeBlockToAppend : function(data) { - - var tag; - - if (data && data.type) { - - switch (data.type) { - case 'simple': - tag = quoteTools.makeSimpleQuote(data); - break; - case 'withCaption': - tag = quoteTools.makeQuoteWithCaption(data); - break; - case 'withPhoto': - tag = quoteTools.makeQuoteWithPhoto(data); - break; - } - } else { - - tag = document.createElement('BLOCKQUOTE'); - - tag.contentEditable = 'true'; - tag.dataset.quoteStyle = 'simple'; - tag.class = 'ce_quote--text'; - - } - return tag; - }, - - render : function(data) { - return quoteTools.makeBlockToAppend(data); - }, - - save : function(block) { - - /** - * Extracts JSON quote data from HTML block - * @param {Text} text, {Text} author, {Object} photo - */ - parsedblock = quoteTools.parseBlockQuote(block); - - var data = { - type : 'quote', - style : parsedblock.style, - text : parsedblock.quote, - author : parsedblock.author, - photo : parsedblock.photo, - }; - - return data; - }, - - makeSettings : function(data) { - - var holder = document.createElement('DIV'), - caption = document.createElement('SPAN'), - types = { - simple : 'Простая цитата', - withCaption : 'Цитата с подписью', - withPhoto : 'Цитата с фото и ФИО' - }, - selectTypeButton; - - /** Add holder classname */ - holder.className = 'ce_plugin_quote--settings' - - /** Add settings helper caption */ - caption.textContent = 'Настройки цитат'; - caption.className = 'ce_plugin_quote--caption'; - - holder.appendChild(caption); - - /** Now add type selectors */ - for (var type in types){ - - selectTypeButton = document.createElement('SPAN'); - - selectTypeButton.textContent = types[type]; - - selectTypeButton.className = 'ce_plugin_quote--select_button'; - - var quoteStyle = quoteTools.selectTypeQuoteStyle(type); - quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle); - - holder.appendChild(selectTypeButton); - - } - - return holder; - - }, - - selectTypeQuoteStyle : function(type) { - - /** - * Choose Quote style to replace - */ - switch (type) { - case 'simple': - quoteStyleFunction = quoteTools.makeSimpleQuote; - break; - case 'withCaption': - quoteStyleFunction = quoteTools.makeQuoteWithCaption; - break; - case 'withPhoto': - quoteStyleFunction = quoteTools.makeQuoteWithPhoto; - break; - } - - return quoteStyleFunction; - - }, - - addSelectTypeClickListener : function(el, quoteStyle) { - - el.addEventListener('click', function () { - - /** - * Parsing currentNode to JSON. - */ - var parsedOldQuote = quoteTools.parseBlockQuote(), - newStyledQuote = quoteStyle(parsedOldQuote); - - cEditor.content.replaceBlock(cEditor.content.currentNode, newStyledQuote, 'quote'); - - /** Close settings after replacing */ - cEditor.toolbar.settings.close(); - - }, false); - - }, - - setBlockHandler : function(block) { - - }, - - makeSimpleQuote : function(data) { - - var wrapper = quoteTools.ui.blockquote(); - - wrapper.innerHTML = data.text || ''; - - wrapper.classList.add('ce_quote--text'); - - wrapper.dataset.quoteStyle = 'simple'; - - wrapper.contentEditable = 'true'; - - return wrapper; - }, - - makeQuoteWithCaption : function(data) { - - var wrapper = quoteTools.ui.blockquote(), - text = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withCaption--blockquote', 'ce_quote--text']), - author = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withCaption--author', 'ce_quote--author']); - - /* make text block ontentEditable */ - text.contentEditable = 'true'; - - text.innerHTML = data.text; - - /* make Author contentEditable */ - author.contentEditable = 'true'; - - author.textContent = data.author || quoteTools.captionPlaceholder; - - quoteTools.ui.mousedown(author, quoteTools.captionPlaceholder); - quoteTools.ui.keyPressed(author, quoteTools.captionPlaceholder); - - - /* Appending created components */ - wrapper.dataset.quoteStyle = 'withCaption'; - - wrapper.appendChild(text); - wrapper.appendChild(author); - - return wrapper; - - }, - - makeQuoteWithPhoto : function(data) { - - var wrapper = quoteTools.ui.blockquote(); - photo = quoteTools.ui.makeBlock('IMG', ['quoteStyle-withPhoto--photo']), - author = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withPhoto--author', 'ce_quote--author']), - job = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withPhoto--position', 'ce_quote--position']), - quote = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withPhoto--quote', 'ce_quote--text']) - - /* Default Image src */ - photo.src = data.photo || '../img/01.jpg'; - - /* make author block contentEditable */ - author.contentEditable = 'true'; - author.textContent = data.author || quoteTools.captionPlaceholder; - - quoteTools.ui.mousedown(author, quoteTools.captionPlaceholder); - quoteTools.ui.keyPressed(author, quoteTools.captionPlaceholder); - - /* Author's position and job */ - job.contentEditable = 'true'; - job.textContent = data.position || quoteTools.jobPlacaholder; - - quoteTools.ui.mousedown(job, quoteTools.jobPlacaholder); - quoteTools.ui.keyPressed(job, quoteTools.jobPlacaholder); - - var authorsWrapper = quoteTools.ui.makeBlock('DIV'); - authorsWrapper.appendChild(author); - authorsWrapper.appendChild(job); - - /* make quote text contentEditable */ - quote.contentEditable = 'true'; - quote.innerHTML = data.text; - - wrapper.dataset.quoteStyle = 'withPhoto'; - - wrapper.appendChild(photo); - wrapper.appendChild(authorsWrapper); - wrapper.appendChild(quote); - - return wrapper; - }, - - parseBlockQuote : function(block) { - - var currentNode = block || cEditor.content.currentNode, - photo = currentNode.getElementsByTagName('img')[0], - author = currentNode.querySelector('.ce_quote--author'), - position = currentNode.querySelector('.ce_quote--position'), - quote ; - - /** Simple quote text placed in Blockquote tag*/ - if ( currentNode.dataset.quoteStyle == 'simple' ) - quote = currentNode.textContent; - else - quote = currentNode.querySelector('.ce_quote--text').textContent; - - if (position) - position = position.textContent; - - if (author) - author = author.textContent; - - if (photo) - photo = photo.src; - - var data = { - text : quote, - author : author, - position : position, - photo : photo, - }; - - return data; - }, - -}; - -quoteTools.ui = { - - wrapper : function($classList) { - - var el = document.createElement('DIV'); - - el.classList.add($classList); - - return el; - - }, - - blockquote : function() { - - var el = document.createElement('BLOCKQUOTE'); - - return el; - - }, - - makeBlock : function(tag, classList) { - - var el = document.createElement(tag); - - - if ( classList ) { - - for( var i = 0; i < classList.length; i++) - el.className += ' ' + classList[i]; - - } - return el; - - }, - - mousedown : function(block, placeholder) { - - block.addEventListener('focus', function() { - - quoteTools.ui.clear(block, placeholder); - - }); - - }, - - keyPressed : function(block, placeholder) { - - block.addEventListener('keydown', function(){ - - quoteTools.ui.fillbyPlaceholder(block, placeholder); - - }); - - }, - - clear : function(block, placeholder) { - - if ( block.textContent == placeholder) { - block.innerHTML = ''; - } - }, - - fillbyPlaceholder : function(block, placeholder) { - - quoteTools.ui.clear(block, placeholder); - - setTimeout( function() { - - if (block.textContent == '') { - block.textContent = placeholder; - } - - }, 10); - - } -} - -cEditor.tools.quote = { - - type : 'quote', - iconClassname : 'ce-icon-quote', - make : quoteTools.makeBlockToAppend, - appendCallback : null, - settings : quoteTools.makeSettings(), - render : quoteTools.render, - save : quoteTools.save, - -}; diff --git a/editor.css b/editor.css index efa5edfc..72e0ce14 100644 --- a/editor.css +++ b/editor.css @@ -226,76 +226,6 @@ color: #cc7d74; } -/** Quote - settings */ - -.ce_plugin_quote--settings{ - white-space: nowrap; - /*padding-right: 10px; */ -} -.ce_plugin_quote--caption{ - color: #b9c2c2; -} -.ce_plugin_quote--select_button{ - display: inline-block; - margin-left: 40px; - border-bottom: 1px solid #c3d5ed; - padding-bottom: 2px; - color: #5399d4; - cursor: pointer; -} -.ce_plugin_quote--select_button:hover{ - border-bottom-color: #f6d8da; - color: #cc7d74; -} -.clearfix_quote:after { - visibility: hidden; - display: block; - font-size: 0; - content: " "; - clear: both; - height: 0; -} -.quoteStyle-withCaption--author { - margin-top: 25px; - text-align: right; - font-size: 17px; - font-weight: bold; - color: #000; - line-height: 1.5em; - -} - -.quoteStyle-withCaption--blockquote:focus, .quoteStyle-withCaption--author:focus { - outline: none; -} - -.quoteStyle-withPhoto--photo { - width: 90px; - height: 90px; - border: 1px solid #8E8E8E; - border-radius: 50%; - float: left; - margin-right: 30px; -} - -.quoteStyle-withPhoto--author, .quoteStyle-withPhoto--position { - overflow: hidden; - font-weight: bold; - font-size: 17px; - line-height: 1.5em; - /*border-bottom: 1px solid black;*/ - border: 0px; - outline: none; - - word-break: break-word; -} - -.quoteStyle-withPhoto--quote { - margin-top: 15px; - outline: none; - overflow: hidden; -} - /* @-webkit-keyframes bounceIn { 0% { opacity: 0; -webkit-transform: scale(.3);} diff --git a/example.html b/example.html index 7ba5319c..9be66d99 100644 --- a/example.html +++ b/example.html @@ -20,6 +20,8 @@ font-size: 2em; } + + @@ -99,8 +101,17 @@ }, { paragraph : { - text : 'На днях я получил очередной проект по разработке личного кабинета.
Как обычно, я открыл консоль, чтобы посмотреть историю проекта, ветки и все ли правки закомичены (от слова commit - фиксировать). Однако ничего из этого я не узнал — проект не содержал .git репозитория.
Эта ситуация в очередной раз заставила задуматься о том, как много разработчиков до сих пор не понимают необходимость контролировать изменения в файлах с исходным кодом. А многие и вовсе не знают что это такое, и как этим пользоваться.' + text : '

На днях я получил очередной проект по разработке личного кабинета.

Как обычно, я открыл консоль, чтобы посмотреть историю проекта, ветки и все ли правки закомичены (от слова commit - фиксировать). Однако ничего из этого я не узнал — проект не содержал .git репозитория.

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

' } + }, + { + link : { + 'linkUrl' : 'http://yandex.ru', + 'linkText' : 'yandex.ru', + 'image' : 'https://yastatic.net/morda-logo/i/apple-touch-icon/ru-76x76.png', + 'title' : 'Яндекс', + 'description' : 'Сайт, поисковик, проч.' + } }, { header : { @@ -144,7 +155,7 @@ { header : { type : 'H2', - text : 'Что такое git', + text : 'Основные термины и понятия при работе с системой Git', } }, { @@ -152,24 +163,90 @@ text : 'Репозиторий — дерево изменений проекта.', } }, + { + link : { + 'linkUrl' : 'http://google.com', + 'linkText' : 'google.com', + 'image' : 'http://i1.kym-cdn.com/photos/images/facebook/000/002/110/longcat.jpg', + 'title' : 'Google', + 'description' : 'Поисковик, поисковик, проч.' + } + }, { paragraph : { - text : 'Репозиторий — дерево изменений проекта.', + text : 'Ветка — указатель на коммит.

На один коммит может указывать несколько веток. Как правило это случается при создании новой ветки из текущей. Например для реализации в ней новой задачи. По мере добавления коммитов — ветки будут расходится в разные стороны.

' } }, + { + paragraph : { + text : 'Коммит (от слова commit - фиксировать) — логическая единица изменений.

Каждый из них имеет историю уникальный ID и цепочку предшествующих коммитов. Можно «откатить» (отменить) изменения любого из коммитов. Для любого коммита из истории можно создать указатель, то есть ветку.

' + } + }, + { + paragraph : { + text : 'Индекс — изменения, которые будут зафиксированы при следующем коммите.

При этом, во время коммита, могут быть изменения, не добавленные в индекс — они не будут закоммичены. Их надо будет отдельно добавить в индекс и зафиксировать. Таким образом, можно вносить разом, все необходимые по мере работы, правки и фиксировать их логическими группами.

' + } + }, + { + paragraph : { + text : '

В первое время вам понадобятся только основные команды. Давайте рассмотрим их:

' + } + }, + { + list : { + type : 'unordered', + items : [ + 'init — создает новый репозиторий', + 'status — отображает список измененных, добавленных и удаленных файлов', + 'branch — отображает список веток и активную среди них', + 'add — добавляет указанные файлы в индекс', + 'reset — удаляет указанные файлы из индекса', + 'commit — фиксирует добавленнные в индекс изменения', + 'checkout — переключает активную ветку; отменяет не добавленные в индекс изменения', + 'merge — объединяет указанную ветку с активной', + 'log — выводит список последних коммитов (можно указать количество и формат)' + ] + } + }, + { + header : { + type : 'H2', + text : 'Примеры команд для работы с Git' + } + }, + { + paragraph : { + text : '

Создайте новую папку для тестового проекта.

Чтобы начать работу с гитом, надо его инициализировать — открыть консоль, перейти в корневую папку проекта и выполнить команду:' + } + }, + { + code : { + text : '$git init' + } + }, + { + paragraph : { + text : '

Эта команда создаст новый пустой репозиторий. Проще говоря, появится папка .git с какими-то непонятными файлами. Причем такой репозиторий, который находится в папке проекта, файлы которого вы можете менять — называется «рабочей копией». Существуют еще «внешние копии» или bare-репозитории.

Все остальные команды можно вызывать в корневой папке или в одной из вложенных.

Теперь можно вносить изменения.

Список изменений можно увидеть выполнив команду:

' + } + }, + { + code : { + text : '$git status' + } + }, { paragraph : { text : 'После создания нового репозитория дерево содержит только одну ветку — master. Ветка состоит из коммитов, расположенных в хронологическом порядке. Как правило, в ветке master находятся проверенные и протестированные изменения.' } - } + }, ]; /** * @todo uncomment and append all text to items * ..... - *

Ветка — указатель на коммит.  
На один коммит может указывать несколько веток. Как правило это случается при создании новой ветки из текущей. Например для реализации в ней новой задачи. По мере добавления коммитов — ветки будут расходится в разные стороны.

Коммит (от слова commit - фиксировать) — логическая единица изменений.
Каждый из них имеет историю уникальный ID и цепочку предшествующих коммитов. Можно «откатить» (отменить) изменения любого из коммитов. Для любого коммита из истории можно создать указатель, то есть ветку. 

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

В первое время вам понадобятся только основные команды. Давайте рассмотрим их:

Примеры команд для работы с Git

Создайте новую папку для тестового проекта.

Чтобы начать работу с гитом, надо его инициализировать — открыть консоль, перейти в корневую папку проекта и выполнить команду:

- * $ git init

Эта команда создаст новый пустой репозиторий. Проще говоря, появится папка .git с какими-то непонятными файлами. Причем такой репозиторий, который находится в папке проекта, файлы которого вы можете менять — называется «рабочей копией». Существуют еще «внешние копии» или bare-репозитории.

Все остальные команды можно вызывать в корневой папке или в одной из вложенных.

Теперь можно вносить изменения.

Список изменений можно увидеть выполнив команду:

$ git status

В консоли появится список измененных файлов.

Добавьте файлы, изменения в которых вы хотите зафиксировать:

$ git add file_name_a.php

Файлы можно указывать через пробел. Все файлы в данной папке и ее подпаках можно добавить командой:

$ git add .

Будьте внимательны, эта команда не добавит новые файлы в индекс. Добавятся только модифицированные старые файлы и удаленные. Новые файлы можно добавить явно указав имя. 

Добавить все новые и измененные файлы можно командой:

$ git add -A

Изменения стоит фиксировать логическими блоками, то есть в одном коммите должны быть файлы связанные с решением одной конкретной ошибки или одной конкретной новой задачи.

Если вы добавили файл из другого логического блока, удалите его из индекса командой:

$ git reset file_name_b.php

Зафиксируйте эти изменения в другом коммите. Так будет удобнее при просмотре истории изменений и отмене изменений.

Если вы случайно изменили не тот файл - верните его к последнему зафиксированному состоянию командой:

$ git checkout file_name_c.php

Отменить изменения всех, ранее существующих, файлах в данной и вложенных папках можно командой:

$ git checkout -- .

Ненужные новые файлы достаточно просто удалить. Или это можно сделать командой:

$ git reset --hard HEAD

Проект будет полностью приведен к последнему зафиксированному состоянию.

Теперь зафиксируйте изменения добавленные в индекс:

$ git commit

Откроется текстовый редактор по-умолчанию для того, чтобы добавить комментарий к коммиту. Распишите, что и зачем вы меняли. Но не перечисляйте список измененных файлов — гит сделает это за вас. Комментарий должен коротким и понятным, например:

fix| order price

now price includes vat

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

Первая строка самая важная и должна включать суть коммита в нескольких словах. Дальше можете не жалеть строк и расписать подробно что, зачем и почему было изменено (речь про логику, а не про файлы).

Теперь можно посмотреть историю изменений, ваш коммит должен в ней отобразиться:

$ git log

Заключение

Как видите, ничего сложного.

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

+ * + *

$ git status

В консоли появится список измененных файлов.

Добавьте файлы, изменения в которых вы хотите зафиксировать:

$ git add file_name_a.php

Файлы можно указывать через пробел. Все файлы в данной папке и ее подпаках можно добавить командой:

$ git add .

Будьте внимательны, эта команда не добавит новые файлы в индекс. Добавятся только модифицированные старые файлы и удаленные. Новые файлы можно добавить явно указав имя. 

Добавить все новые и измененные файлы можно командой:

$ git add -A

Изменения стоит фиксировать логическими блоками, то есть в одном коммите должны быть файлы связанные с решением одной конкретной ошибки или одной конкретной новой задачи.

Если вы добавили файл из другого логического блока, удалите его из индекса командой:

$ git reset file_name_b.php

Зафиксируйте эти изменения в другом коммите. Так будет удобнее при просмотре истории изменений и отмене изменений.

Если вы случайно изменили не тот файл - верните его к последнему зафиксированному состоянию командой:

$ git checkout file_name_c.php

Отменить изменения всех, ранее существующих, файлах в данной и вложенных папках можно командой:

$ git checkout -- .

Ненужные новые файлы достаточно просто удалить. Или это можно сделать командой:

$ git reset --hard HEAD

Проект будет полностью приведен к последнему зафиксированному состоянию.

Теперь зафиксируйте изменения добавленные в индекс:

$ git commit

Откроется текстовый редактор по-умолчанию для того, чтобы добавить комментарий к коммиту. Распишите, что и зачем вы меняли. Но не перечисляйте список измененных файлов — гит сделает это за вас. Комментарий должен коротким и понятным, например:

fix| order price

now price includes vat

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

Первая строка самая важная и должна включать суть коммита в нескольких словах. Дальше можете не жалеть строк и расписать подробно что, зачем и почему было изменено (речь про логику, а не про файлы).

Теперь можно посмотреть историю изменений, ваш коммит должен в ней отобразиться:

$ git log

Заключение

Как видите, ничего сложного.

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

*/ @@ -189,3 +266,6 @@ }) + + + diff --git a/plugins/ceditor-tool-link.css b/plugins/ceditor-tool-link.css new file mode 100644 index 00000000..330dc089 --- /dev/null +++ b/plugins/ceditor-tool-link.css @@ -0,0 +1,59 @@ +.clearfix:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; +} + +.ceditor-tool-link-input { + outline: none; + border: 0; + width: 100%; +} + +.tool-link-panel { + width: 50%; + position: relative; + margin: 25px auto; + background: #f8f7ef; + border: 1px solid transparent; + padding: 25px 30px; +} + +.ceditor-tool-link .tool-link-image { + float:right; + width: 75px; + border-radius: 50%; +} + +.ceditor-tool-link .tool-link-title { + display: block; + width: 340px; + margin-bottom: 4px; + line-height: 1.2em; + font-size: 20px; + font-weight: 700; + color: #000; +} + +.ceditor-tool-link .tool-link-description { + display: block; + width: 400px; + margin-top: 10px; + font-size: 14px; + color: #000; +} + +.ceditor-tool-link .tool-link-link { + display: block; + width: 360px; + font-size: 10px; + margin-bottom: 4px; + letter-spacing: 1px; + overflow: hidden; + text-transform: uppercase; + text-decoration: none; + color: rgba(165,156,86,.8); +} diff --git a/plugins/ceditor-tool-link.js b/plugins/ceditor-tool-link.js new file mode 100644 index 00000000..c4c26b12 --- /dev/null +++ b/plugins/ceditor-tool-link.js @@ -0,0 +1,277 @@ +/** + * Created by nostr on 29.06.16. + */ + +/** + * Link tool plugin + */ +var linkTool = { + + defaultText : 'Insert link here ...', + currentBlock : null, + currentInput : null, + elementClasses : { + link : "tool-link-link", + image : "tool-link-image", + title : "tool-link-title", + description : "tool-link-description" + }, + + /** + * Make initial header block + * @param {object} JSON with block data + * @return {Element} element to append + */ + makeNewBlock : function (data) { + + var wrapper = linkTool.ui.mainBlock(); + + var tag = linkTool.ui.input(); + + linkTool.currentInput = tag; + + wrapper.appendChild(tag); + + /* Bind callbacks **/ + + tag.addEventListener('paste', linkTool.blockPasteCallback, false); + + return wrapper; + + }, + + /** + * Method to render HTML block from JSON + */ + render : function (json) { + + var block = linkTool.ui.mainBlock(); + + var tag = linkTool.ui.make(json); + + block.appendChild(tag); + + return block; + + }, + + /** + * Method to extract JSON data from HTML block + */ + save : function (block){ + + var linkElement = linkTool.elementClasses.link; + + var data = { + fullLink : block.querySelector("." + linkElement).href, + shortLink : block.querySelector("." + linkElement).textContent, + image : block.querySelector("." + linkTool.elementClasses.image).src, + title : block.querySelector("." + linkTool.elementClasses.title).textContent, + description : block.querySelector("." + linkTool.elementClasses.description).textContent + }; + + return data; + + }, + + appendCallback : function () { + + console.log('link callback is appended...'); + + }, + + blockPasteCallback : function (event) { + + clipboardData = event.clipboardData || window.clipboardData; + + pastedData = clipboardData.getData('Text'); + + var block = event.target.parentNode; + + Promise.resolve() + + .then(function () { + return linkTool.urlify(pastedData) + }) + + .then(fetch('http://ajax.ru/link')) + + .then(function (response) { + + if (response.status == "200"){ + + return response.json(); + + } + else { + + return { + 'linkUrl' : 'http://yandex.ru', + 'linkText' : 'yandex.ru', + 'image' : 'https://yastatic.net/morda-logo/i/apple-touch-icon/ru-76x76.png', + 'title' : 'Яндекс', + 'description' : 'Сайт, поисковик, проч.' + }; + + } + + }) + + .then(function (json) { + linkTool.composeLinkPreview(json, block) + }) + + .catch(function(error) { + cEditor.core.log('Error while doing things with link paste: %o', 'error', error); + }); + + }, + + urlify : function (text) { + + var urlRegex = /(https?:\/\/\S+)/g; + + var links = text.match(urlRegex); + + if (links) { + return links[0]; + } + + return null; + + }, + + composeLinkPreview : function (json, currentBlock) { + + if (json == {}) { + + return; + + } + + var previewBlock = linkTool.ui.make(json); + + linkTool.currentInput.remove(); + + currentBlock.appendChild(previewBlock); + + } + +}; + +linkTool.ui = { + + make : function (json) { + + var wrapper = this.wrapper(), + siteImage = this.image(json.image), + siteTitle = this.title(json.title), + siteDescription = this.description(json.description), + siteLink = this.link(json.linkUrl, json.linkText); + + wrapper.appendChild(siteImage); + wrapper.appendChild(siteTitle); + wrapper.appendChild(siteLink); + wrapper.appendChild(siteDescription); + + return wrapper; + + }, + + mainBlock : function () { + + var wrapper = document.createElement('div'); + + wrapper.classList += "ceditor-tool-link"; + + return wrapper + + }, + + input : function () { + + var inpitTag = document.createElement('input'); + + inpitTag.classList += "ceditor-tool-link-input"; + + inpitTag.placeholder = linkTool.defaultText; + + inpitTag.contentEditable = false; + + return inpitTag; + + }, + + wrapper : function () { + + var wrapper = document.createElement('div'); + + wrapper.className += 'tool-link-panel clearfix'; + + return wrapper; + + }, + + image : function (imageSrc) { + + var imageTag = document.createElement('img'); + + imageTag.classList += linkTool.elementClasses.image; + + imageTag.setAttribute('src', imageSrc); + + return imageTag; + + }, + + link : function (linkUrl, linkText) { + + var linkTag = document.createElement('a'); + + linkTag.classList += linkTool.elementClasses.link; + + linkTag.href = linkUrl; + + linkTag.target = "_blank"; + + linkTag.innerText = linkText; + + return linkTag; + + }, + + title : function (titleText) { + + var titleTag = document.createElement('div'); + + titleTag.classList.add("tool-link-content", linkTool.elementClasses.title); + + titleTag.innerHTML = titleText; + + return titleTag; + }, + + description : function (descriptionText) { + + var descriptionTag = document.createElement('div'); + + descriptionTag.classList.add("tool-link-content", linkTool.elementClasses.description); + + descriptionTag.innerHTML = descriptionText; + + return descriptionTag; + } + +}; + +cEditor.tools.link = { + + type : 'link', + iconClassname : 'ce-icon-link', + make : linkTool.makeNewBlock, + appendCallback : linkTool.appendCallback, + render : linkTool.render + // settings : linkTool.makeSettings(), + // save : linkTool.save + +}; \ No newline at end of file diff --git a/plugins/ceditor-tool-quote.css b/plugins/ceditor-tool-quote.css new file mode 100644 index 00000000..d4f98228 --- /dev/null +++ b/plugins/ceditor-tool-quote.css @@ -0,0 +1,69 @@ +/** Quote - settings */ + +.ce_plugin_quote--settings{ + white-space: nowrap; + /*padding-right: 10px; */ +} +.ce_plugin_quote--caption{ + color: #b9c2c2; +} +.ce_plugin_quote--select_button{ + display: inline-block; + margin-left: 40px; + border-bottom: 1px solid #c3d5ed; + padding-bottom: 2px; + color: #5399d4; + cursor: pointer; +} +.ce_plugin_quote--select_button:hover{ + border-bottom-color: #f6d8da; + color: #cc7d74; +} +.clearfix_quote:after { + visibility: hidden; + display: block; + font-size: 0; + content: " "; + clear: both; + height: 0; +} +.quoteStyle-withCaption--author { + margin-top: 25px; + text-align: right; + font-size: 17px; + font-weight: bold; + color: #000; + line-height: 1.5em; + +} + +.quoteStyle-withCaption--blockquote:focus, .quoteStyle-withCaption--author:focus { + outline: none; +} + +.quoteStyle-withPhoto--photo { + width: 90px; + height: 90px; + border: 1px solid #8E8E8E; + border-radius: 50%; + float: left; + margin-right: 30px; +} + +.quoteStyle-withPhoto--author, .quoteStyle-withPhoto--position { + overflow: hidden; + font-weight: bold; + font-size: 17px; + line-height: 1.5em; + /*border-bottom: 1px solid black;*/ + border: 0px; + outline: none; + + word-break: break-word; +} + +.quoteStyle-withPhoto--quote { + margin-top: 15px; + outline: none; + overflow: hidden; +} diff --git a/plugins/ceditor-tool-quote.js b/plugins/ceditor-tool-quote.js new file mode 100644 index 00000000..f0853292 --- /dev/null +++ b/plugins/ceditor-tool-quote.js @@ -0,0 +1,358 @@ +/** +* Codex Team +* @author Khaydarov Murod +*/ + +var quoteTools = { + + captionPlaceholder : 'Введите имя автора', + jobPlacaholder : 'Введите должность', + /** + * Make Quote from JSON datasets + */ + makeBlockToAppend : function(data) { + + var tag; + + if (data && data.type) { + + switch (data.type) { + case 'simple': + tag = quoteTools.makeSimpleQuote(data); + break; + case 'withCaption': + tag = quoteTools.makeQuoteWithCaption(data); + break; + case 'withPhoto': + tag = quoteTools.makeQuoteWithPhoto(data); + break; + } + } else { + + tag = document.createElement('BLOCKQUOTE'); + + tag.contentEditable = 'true'; + tag.dataset.quoteStyle = 'simple'; + tag.class = 'ce_quote--text'; + + } + return tag; + }, + + render : function(data) { + return quoteTools.makeBlockToAppend(data); + }, + + save : function(block) { + + /** + * Extracts JSON quote data from HTML block + * @param {Text} text, {Text} author, {Object} photo + */ + parsedblock = quoteTools.parseBlockQuote(block); + + var data = { + type : 'quote', + style : parsedblock.style, + text : parsedblock.quote, + author : parsedblock.author, + photo : parsedblock.photo, + }; + + return data; + }, + + makeSettings : function(data) { + + var holder = document.createElement('DIV'), + caption = document.createElement('SPAN'), + types = { + simple : 'Простая цитата', + withCaption : 'Цитата с подписью', + withPhoto : 'Цитата с фото и ФИО' + }, + selectTypeButton; + + /** Add holder classname */ + holder.className = 'ce_plugin_quote--settings' + + /** Add settings helper caption */ + caption.textContent = 'Настройки цитат'; + caption.className = 'ce_plugin_quote--caption'; + + holder.appendChild(caption); + + /** Now add type selectors */ + for (var type in types){ + + selectTypeButton = document.createElement('SPAN'); + + selectTypeButton.textContent = types[type]; + + selectTypeButton.className = 'ce_plugin_quote--select_button'; + + var quoteStyle = quoteTools.selectTypeQuoteStyle(type); + quoteTools.addSelectTypeClickListener(selectTypeButton, quoteStyle); + + holder.appendChild(selectTypeButton); + + } + + return holder; + + }, + + selectTypeQuoteStyle : function(type) { + + /** + * Choose Quote style to replace + */ + switch (type) { + case 'simple': + quoteStyleFunction = quoteTools.makeSimpleQuote; + break; + case 'withCaption': + quoteStyleFunction = quoteTools.makeQuoteWithCaption; + break; + case 'withPhoto': + quoteStyleFunction = quoteTools.makeQuoteWithPhoto; + break; + } + + return quoteStyleFunction; + + }, + + addSelectTypeClickListener : function(el, quoteStyle) { + + el.addEventListener('click', function () { + + /** + * Parsing currentNode to JSON. + */ + var parsedOldQuote = quoteTools.parseBlockQuote(), + newStyledQuote = quoteStyle(parsedOldQuote); + + cEditor.content.replaceBlock(cEditor.content.currentNode, newStyledQuote, 'quote'); + + /** Close settings after replacing */ + cEditor.toolbar.settings.close(); + + }, false); + + }, + + setBlockHandler : function(block) { + + }, + + makeSimpleQuote : function(data) { + + var wrapper = quoteTools.ui.blockquote(); + + wrapper.innerHTML = data.text || ''; + + wrapper.classList.add('ce_quote--text'); + + wrapper.dataset.quoteStyle = 'simple'; + + wrapper.contentEditable = 'true'; + + return wrapper; + }, + + makeQuoteWithCaption : function(data) { + + var wrapper = quoteTools.ui.blockquote(), + text = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withCaption--blockquote', 'ce_quote--text']), + author = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withCaption--author', 'ce_quote--author']); + + /* make text block ontentEditable */ + text.contentEditable = 'true'; + + text.innerHTML = data.text; + + /* make Author contentEditable */ + author.contentEditable = 'true'; + + author.textContent = data.author || quoteTools.captionPlaceholder; + + quoteTools.ui.mousedown(author, quoteTools.captionPlaceholder); + quoteTools.ui.keyPressed(author, quoteTools.captionPlaceholder); + + + /* Appending created components */ + wrapper.dataset.quoteStyle = 'withCaption'; + + wrapper.appendChild(text); + wrapper.appendChild(author); + + return wrapper; + + }, + + makeQuoteWithPhoto : function(data) { + + var wrapper = quoteTools.ui.blockquote(); + photo = quoteTools.ui.makeBlock('IMG', ['quoteStyle-withPhoto--photo']), + author = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withPhoto--author', 'ce_quote--author']), + job = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withPhoto--position', 'ce_quote--position']), + quote = quoteTools.ui.makeBlock('DIV', ['quoteStyle-withPhoto--quote', 'ce_quote--text']) + + /* Default Image src */ + photo.src = data.photo || '../img/01.jpg'; + + /* make author block contentEditable */ + author.contentEditable = 'true'; + author.textContent = data.author || quoteTools.captionPlaceholder; + + quoteTools.ui.mousedown(author, quoteTools.captionPlaceholder); + quoteTools.ui.keyPressed(author, quoteTools.captionPlaceholder); + + /* Author's position and job */ + job.contentEditable = 'true'; + job.textContent = data.position || quoteTools.jobPlacaholder; + + quoteTools.ui.mousedown(job, quoteTools.jobPlacaholder); + quoteTools.ui.keyPressed(job, quoteTools.jobPlacaholder); + + var authorsWrapper = quoteTools.ui.makeBlock('DIV'); + authorsWrapper.appendChild(author); + authorsWrapper.appendChild(job); + + /* make quote text contentEditable */ + quote.contentEditable = 'true'; + quote.innerHTML = data.text; + + wrapper.dataset.quoteStyle = 'withPhoto'; + + wrapper.appendChild(photo); + wrapper.appendChild(authorsWrapper); + wrapper.appendChild(quote); + + return wrapper; + }, + + parseBlockQuote : function(block) { + + var currentNode = block || cEditor.content.currentNode, + photo = currentNode.getElementsByTagName('img')[0], + author = currentNode.querySelector('.ce_quote--author'), + position = currentNode.querySelector('.ce_quote--position'), + quote ; + + /** Simple quote text placed in Blockquote tag*/ + if ( currentNode.dataset.quoteStyle == 'simple' ) + quote = currentNode.textContent; + else + quote = currentNode.querySelector('.ce_quote--text').textContent; + + if (position) + position = position.textContent; + + if (author) + author = author.textContent; + + if (photo) + photo = photo.src; + + var data = { + text : quote, + author : author, + position : position, + photo : photo, + }; + + return data; + }, + +}; + +quoteTools.ui = { + + wrapper : function($classList) { + + var el = document.createElement('DIV'); + + el.classList.add($classList); + + return el; + + }, + + blockquote : function() { + + var el = document.createElement('BLOCKQUOTE'); + + return el; + + }, + + makeBlock : function(tag, classList) { + + var el = document.createElement(tag); + + + if ( classList ) { + + for( var i = 0; i < classList.length; i++) + el.className += ' ' + classList[i]; + + } + return el; + + }, + + mousedown : function(block, placeholder) { + + block.addEventListener('focus', function() { + + quoteTools.ui.clear(block, placeholder); + + }); + + }, + + keyPressed : function(block, placeholder) { + + block.addEventListener('keydown', function(){ + + quoteTools.ui.fillbyPlaceholder(block, placeholder); + + }); + + }, + + clear : function(block, placeholder) { + + if ( block.textContent == placeholder) { + block.innerHTML = ''; + } + }, + + fillbyPlaceholder : function(block, placeholder) { + + quoteTools.ui.clear(block, placeholder); + + setTimeout( function() { + + if (block.textContent == '') { + block.textContent = placeholder; + } + + }, 10); + + } +} + +cEditor.tools.quote = { + + type : 'quote', + iconClassname : 'ce-icon-quote', + make : quoteTools.makeBlockToAppend, + appendCallback : null, + settings : quoteTools.makeSettings(), + render : quoteTools.render, + save : quoteTools.save, + +};