Version Notes
https://github.com/SchumacherFM/Magento-Markdown
Download this release
Release Info
Developer | Cyrill Schumacher |
Extension | markdown |
Version | 1.4.0 |
Comparing to | |
See all releases |
Code changes from version 1.1.0 to 1.4.0
- app/code/community/SchumacherFM/Markdown/Helper/Data.php +58 -10
- app/code/community/SchumacherFM/Markdown/Model/Editor/Config.php +13 -15
- app/code/community/SchumacherFM/Markdown/Model/Markdown/Abstract.php +195 -0
- app/code/community/SchumacherFM/Markdown/Model/Markdown/Interface.php +21 -0
- app/code/community/SchumacherFM/Markdown/Model/Markdown/Observer.php +144 -0
- app/code/community/SchumacherFM/Markdown/Model/Markdown/Render.php +1 -213
- app/code/community/SchumacherFM/Markdown/Model/Michelf/Markdown.php +1 -1
- app/code/community/SchumacherFM/Markdown/Model/Observer/AdminhtmlBlock.php +91 -16
- app/code/community/SchumacherFM/Markdown/controllers/Adminhtml/MarkdownController.php +37 -0
- app/code/community/SchumacherFM/Markdown/etc/adminhtml.xml +1 -1
- app/code/community/SchumacherFM/Markdown/etc/config.xml +26 -4
- app/code/community/SchumacherFM/Markdown/etc/system.xml +23 -2
- app/design/adminhtml/default/default/layout/markdown.xml +7 -1
- js/mage/adminhtml/markdown.js +120 -53
- js/mage/adminhtml/marked.js +41 -27
- package.xml +10 -8
app/code/community/SchumacherFM/Markdown/Helper/Data.php
CHANGED
@@ -7,6 +7,8 @@
|
|
7 |
*/
|
8 |
class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
9 |
{
|
|
|
|
|
10 |
|
11 |
/**
|
12 |
* easy access method for rendering markdown in phtml files
|
@@ -14,25 +16,26 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
14 |
* echo Mage::helper('markdown')->render($_product->getDescription())
|
15 |
*
|
16 |
* @param string $text
|
17 |
-
* @param array
|
18 |
*
|
19 |
* @return string
|
20 |
*/
|
21 |
-
public function render($text,array $options = null)
|
22 |
{
|
23 |
return Mage::getSingleton('markdown/markdown_render')
|
24 |
->setOptions($options)
|
25 |
-
->renderMarkdown($text
|
26 |
}
|
27 |
|
28 |
/**
|
29 |
-
* @
|
30 |
*
|
31 |
-
* @return
|
32 |
*/
|
33 |
-
public function getDetectionTag()
|
34 |
{
|
35 |
-
|
|
|
36 |
}
|
37 |
|
38 |
/**
|
@@ -48,13 +51,58 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
48 |
}
|
49 |
|
50 |
/**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
* @todo if backend check for current selected store view / website
|
52 |
* check if md extra is enabled ... per store view
|
53 |
*
|
54 |
-
* @return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
*/
|
56 |
-
public function
|
57 |
{
|
58 |
-
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
}
|
7 |
*/
|
8 |
class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
9 |
{
|
10 |
+
const URL_MD_SYNTAX = 'http://daringfireball.net/projects/markdown/syntax';
|
11 |
+
const URL_MD_EXTRA_SYNTAX = 'http://michelf.ca/projects/php-markdown/extra/';
|
12 |
|
13 |
/**
|
14 |
* easy access method for rendering markdown in phtml files
|
16 |
* echo Mage::helper('markdown')->render($_product->getDescription())
|
17 |
*
|
18 |
* @param string $text
|
19 |
+
* @param array $options
|
20 |
*
|
21 |
* @return string
|
22 |
*/
|
23 |
+
public function render($text, array $options = null)
|
24 |
{
|
25 |
return Mage::getSingleton('markdown/markdown_render')
|
26 |
->setOptions($options)
|
27 |
+
->renderMarkdown($text);
|
28 |
}
|
29 |
|
30 |
/**
|
31 |
+
* @param bool $encoded
|
32 |
*
|
33 |
+
* @return mixed|string
|
34 |
*/
|
35 |
+
public function getDetectionTag($encoded = FALSE)
|
36 |
{
|
37 |
+
$tag = Mage::getStoreConfig('schumacherfm/markdown/detection_tag');
|
38 |
+
return $encoded ? rawurlencode($tag) : $tag;
|
39 |
}
|
40 |
|
41 |
/**
|
51 |
}
|
52 |
|
53 |
/**
|
54 |
+
* @param string $type enum email|page|block ... last two not supported, maybe later.
|
55 |
+
*
|
56 |
+
* @return bool
|
57 |
+
*/
|
58 |
+
public function isMarkdownExtra($type = null)
|
59 |
+
{
|
60 |
+
return (boolean)Mage::getStoreConfig('schumacherfm/markdown/md_extra' . (!empty($type) ? '_' . $type : ''));
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* loads CSS files and minifies it
|
65 |
+
*
|
66 |
* @todo if backend check for current selected store view / website
|
67 |
* check if md extra is enabled ... per store view
|
68 |
*
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function getTransactionalEmailCSS()
|
72 |
+
{
|
73 |
+
$file = Mage::getStoreConfig('schumacherfm/markdown/te_md_css');
|
74 |
+
if (empty($file)) {
|
75 |
+
return '';
|
76 |
+
}
|
77 |
+
$content = trim(implode('', @file(Mage::getBaseDir() . DS . $file)));
|
78 |
+
if (empty($content)) {
|
79 |
+
Mage::log('Markdown CSS file [' . $file . '] is empty!');
|
80 |
+
}
|
81 |
+
$content = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $content); // comments
|
82 |
+
$content = preg_replace('~\s+~', ' ', $content); // all whitespaces
|
83 |
+
$content = preg_replace('~\s*(:|\{|\}|,|;)\s*~', '\\1', $content); // all other whitespaces
|
84 |
+
return $content;
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @return string
|
89 |
+
*/
|
90 |
+
public function getAdminRenderUrl()
|
91 |
+
{
|
92 |
+
return Mage::helper("adminhtml")->getUrl('*/markdown/render');
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @param string $htmlId
|
97 |
+
*
|
98 |
+
* @return string
|
99 |
*/
|
100 |
+
public function getRenderMarkdownJs($htmlId)
|
101 |
{
|
102 |
+
$args = array('\'' . $htmlId . '\'', '\'' . Mage::helper('markdown')->getDetectionTag(TRUE) . '\'');
|
103 |
+
if ($this->isMarkdownExtra()) {
|
104 |
+
$args[] = '\'' . $this->getAdminRenderUrl() . '\'';
|
105 |
+
}
|
106 |
+
return 'renderMarkdown(' . implode(',', $args) . ');';
|
107 |
}
|
108 |
}
|
app/code/community/SchumacherFM/Markdown/Model/Editor/Config.php
CHANGED
@@ -17,26 +17,24 @@ class SchumacherFM_Markdown_Model_Editor_Config
|
|
17 |
public function getWysiwygPluginSettings($config)
|
18 |
{
|
19 |
$variableConfig = array();
|
20 |
-
$
|
21 |
'search' => array('html_id'),
|
22 |
-
'subject' => '
|
23 |
);
|
24 |
-
$
|
25 |
'search' => array('html_id'),
|
26 |
-
'subject' => '
|
27 |
);
|
28 |
$variableWysiwygPlugin = array(
|
29 |
array(
|
30 |
'name' => 'markdownToggle',
|
31 |
'src' => '',
|
32 |
'options' => array(
|
33 |
-
'title' => Mage::helper('markdown')->__('
|
34 |
'url' => '',
|
35 |
'onclick' => array(
|
36 |
'search' => array('html_id'),
|
37 |
-
'subject' => 'toggleMarkdown(\''.
|
38 |
-
rawurlencode(Mage::helper('markdown')->getDetectionTag())
|
39 |
-
.'\',\'{{html_id}}\');'
|
40 |
),
|
41 |
'class' => 'plugin'
|
42 |
)
|
@@ -45,19 +43,19 @@ class SchumacherFM_Markdown_Model_Editor_Config
|
|
45 |
'name' => 'markdown',
|
46 |
'src' => '',
|
47 |
'options' => array(
|
48 |
-
'title' => Mage::helper('markdown')->__('
|
49 |
'url' => '',
|
50 |
-
'onclick' => $
|
51 |
'class' => 'plugin'
|
52 |
)
|
53 |
),
|
54 |
array(
|
55 |
-
'name' => '
|
56 |
'src' => '',
|
57 |
'options' => array(
|
58 |
-
'title' => Mage::helper('markdown')->__('
|
59 |
'url' => '',
|
60 |
-
'onclick' => $
|
61 |
'class' => 'plugin'
|
62 |
)
|
63 |
),
|
@@ -68,11 +66,11 @@ class SchumacherFM_Markdown_Model_Editor_Config
|
|
68 |
'name' => 'markdownextrasyntax',
|
69 |
'src' => '',
|
70 |
'options' => array(
|
71 |
-
'title' => Mage::helper('markdown')->__('
|
72 |
'url' => '',
|
73 |
'onclick' => array(
|
74 |
'search' => array('html_id'),
|
75 |
-
'subject' => '
|
76 |
),
|
77 |
'class' => 'plugin'
|
78 |
)
|
17 |
public function getWysiwygPluginSettings($config)
|
18 |
{
|
19 |
$variableConfig = array();
|
20 |
+
$onclickPreview = array(
|
21 |
'search' => array('html_id'),
|
22 |
+
'subject' => Mage::helper('markdown')->getRenderMarkdownJs('{{html_id}}'),
|
23 |
);
|
24 |
+
$onclickSyntax = array(
|
25 |
'search' => array('html_id'),
|
26 |
+
'subject' => 'mdExternalUrl(\'' . SchumacherFM_Markdown_Helper_Data::URL_MD_SYNTAX . '\',\'{{html_id}}\');'
|
27 |
);
|
28 |
$variableWysiwygPlugin = array(
|
29 |
array(
|
30 |
'name' => 'markdownToggle',
|
31 |
'src' => '',
|
32 |
'options' => array(
|
33 |
+
'title' => Mage::helper('markdown')->__('[M↓] enable'),
|
34 |
'url' => '',
|
35 |
'onclick' => array(
|
36 |
'search' => array('html_id'),
|
37 |
+
'subject' => 'toggleMarkdown(\'' . Mage::helper('markdown')->getDetectionTag(TRUE) . '\',\'{{html_id}}\');'
|
|
|
|
|
38 |
),
|
39 |
'class' => 'plugin'
|
40 |
)
|
43 |
'name' => 'markdown',
|
44 |
'src' => '',
|
45 |
'options' => array(
|
46 |
+
'title' => Mage::helper('markdown')->__('[M↓] Preview'),
|
47 |
'url' => '',
|
48 |
+
'onclick' => $onclickPreview,
|
49 |
'class' => 'plugin'
|
50 |
)
|
51 |
),
|
52 |
array(
|
53 |
+
'name' => 'mdExternalUrl',
|
54 |
'src' => '',
|
55 |
'options' => array(
|
56 |
+
'title' => Mage::helper('markdown')->__('[M↓] Syntax'),
|
57 |
'url' => '',
|
58 |
+
'onclick' => $onclickSyntax,
|
59 |
'class' => 'plugin'
|
60 |
)
|
61 |
),
|
66 |
'name' => 'markdownextrasyntax',
|
67 |
'src' => '',
|
68 |
'options' => array(
|
69 |
+
'title' => Mage::helper('markdown')->__('[M↓] Extra Syntax'),
|
70 |
'url' => '',
|
71 |
'onclick' => array(
|
72 |
'search' => array('html_id'),
|
73 |
+
'subject' => 'mdExternalUrl(\'' . SchumacherFM_Markdown_Helper_Data::URL_MD_EXTRA_SYNTAX . '\',\'{{html_id}}\');'
|
74 |
),
|
75 |
'class' => 'plugin'
|
76 |
)
|
app/code/community/SchumacherFM/Markdown/Model/Markdown/Abstract.php
ADDED
@@ -0,0 +1,195 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category SchumacherFM_Markdown
|
4 |
+
* @package Model
|
5 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
+
* @copyright Copyright (c)
|
7 |
+
*/
|
8 |
+
abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
9 |
+
{
|
10 |
+
protected $_tag = '';
|
11 |
+
protected $_isDisabled = FALSE;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var string
|
15 |
+
*/
|
16 |
+
private $_currentRenderedText = '';
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @var array
|
20 |
+
*/
|
21 |
+
protected $_preserveContainer = array();
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var SchumacherFM_Markdown_Model_Michelf_Markdown
|
25 |
+
*/
|
26 |
+
protected $_renderer = null;
|
27 |
+
|
28 |
+
protected $_options = array(
|
29 |
+
'force' => FALSE,
|
30 |
+
'protectMagento' => TRUE,
|
31 |
+
);
|
32 |
+
|
33 |
+
public function __construct()
|
34 |
+
{
|
35 |
+
/**
|
36 |
+
* due to some weired parsings ... every text field which should contain MD must start with this tag
|
37 |
+
*/
|
38 |
+
$this->_tag = Mage::helper('markdown')->getDetectionTag();
|
39 |
+
$this->_isDisabled = Mage::helper('markdown')->isDisabled();
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* @return SchumacherFM_Markdown_Model_Michelf_Markdown
|
44 |
+
*/
|
45 |
+
public final function getRenderer()
|
46 |
+
{
|
47 |
+
if ($this->_renderer !== null) {
|
48 |
+
return $this->_renderer;
|
49 |
+
}
|
50 |
+
|
51 |
+
$_isExtra = $this->_getIsExtraRenderer();
|
52 |
+
$this->_renderer = Mage::getModel($this->_getRendererModelName($_isExtra));
|
53 |
+
return $this->_renderer;
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* for overloading please use this method to enable or disable the extra renderer
|
58 |
+
*
|
59 |
+
* @return boolean
|
60 |
+
*/
|
61 |
+
protected function _getIsExtraRenderer()
|
62 |
+
{
|
63 |
+
return Mage::helper('markdown')->isMarkdownExtra();
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* for overloading and using of your own markdown renderer use this method
|
68 |
+
*
|
69 |
+
* @param bool $_isExtra
|
70 |
+
*
|
71 |
+
* @return string
|
72 |
+
*/
|
73 |
+
protected function _getRendererModelName($_isExtra = FALSE)
|
74 |
+
{
|
75 |
+
return 'markdown/michelf_markdown' . ($_isExtra === TRUE ? '_extra' : '');
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* @param array $options
|
80 |
+
*
|
81 |
+
* @return $this
|
82 |
+
*/
|
83 |
+
public function setOptions(array $options = null)
|
84 |
+
{
|
85 |
+
$this->_options = $options;
|
86 |
+
return $this;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* @param string $text
|
91 |
+
*
|
92 |
+
* @return string
|
93 |
+
*/
|
94 |
+
public function renderMarkdown($text)
|
95 |
+
{
|
96 |
+
return $this->_isDisabled
|
97 |
+
? $text
|
98 |
+
: $this->_renderMarkdown($text);
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @param string $text
|
103 |
+
*
|
104 |
+
* @return string
|
105 |
+
*/
|
106 |
+
protected function _renderMarkdown($text)
|
107 |
+
{
|
108 |
+
$force = isset($this->_options['force']) && $this->_options['force'] === TRUE;
|
109 |
+
$protectMagento = isset($this->_options['protectMagento']) && $this->_options['protectMagento'] === TRUE;
|
110 |
+
$this->_currentRenderedText = $text; // @todo optimize
|
111 |
+
|
112 |
+
if (!$this->_isMarkdown() && $force === FALSE) {
|
113 |
+
return $this->_currentRenderedText;
|
114 |
+
}
|
115 |
+
|
116 |
+
$this->_removeMarkdownTag();
|
117 |
+
if ($protectMagento === TRUE) {
|
118 |
+
$this->_preserveMagentoVariablesEncode();
|
119 |
+
}
|
120 |
+
|
121 |
+
$this->_currentRenderedText = $this->getRenderer()->defaultTransform($this->_currentRenderedText);
|
122 |
+
|
123 |
+
if ($protectMagento === TRUE) {
|
124 |
+
$this->_preserveMagentoVariablesDecode();
|
125 |
+
}
|
126 |
+
return $this->_currentRenderedText;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* removes the markdown detection tag
|
131 |
+
*
|
132 |
+
* @return $this
|
133 |
+
*/
|
134 |
+
protected function _removeMarkdownTag()
|
135 |
+
{
|
136 |
+
$this->_currentRenderedText = str_replace($this->_tag, '', $this->_currentRenderedText);
|
137 |
+
return $this;
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* @return $this
|
142 |
+
*/
|
143 |
+
protected function _preserveMagentoVariablesEncode()
|
144 |
+
{
|
145 |
+
$matches = array();
|
146 |
+
preg_match_all('~(\{\{[a-z]+.+\}\})~ismU', $this->_currentRenderedText, $matches, PREG_SET_ORDER);
|
147 |
+
if (count($matches) > 0) {
|
148 |
+
foreach ($matches as $match) {
|
149 |
+
$key = md5($match[0]);
|
150 |
+
$this->_preserveContainer[$key] = $match[0];
|
151 |
+
}
|
152 |
+
$this->_currentRenderedText = str_replace(
|
153 |
+
$this->_preserveContainer, array_keys($this->_preserveContainer), $this->_currentRenderedText
|
154 |
+
);
|
155 |
+
}
|
156 |
+
return $this;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* @return $this
|
161 |
+
*/
|
162 |
+
protected function _preserveMagentoVariablesDecode()
|
163 |
+
{
|
164 |
+
if (count($this->_preserveContainer) === 0) {
|
165 |
+
return $this;
|
166 |
+
}
|
167 |
+
$this->_currentRenderedText = str_replace(
|
168 |
+
array_keys($this->_preserveContainer), $this->_preserveContainer, $this->_currentRenderedText
|
169 |
+
);
|
170 |
+
$this->_preserveContainer = array();
|
171 |
+
return $this;
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* checks if text contains no html ... if so considered as markdown ... not a nice way...
|
176 |
+
*
|
177 |
+
* @return bool
|
178 |
+
*/
|
179 |
+
private function _isMarkdown()
|
180 |
+
{
|
181 |
+
$flag = !empty($this->_currentRenderedText);
|
182 |
+
return $flag === TRUE && strpos($this->_currentRenderedText, $this->_tag) !== FALSE;
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* @param string reference $text
|
187 |
+
*
|
188 |
+
* @return bool
|
189 |
+
*/
|
190 |
+
public function isMarkdown(&$text)
|
191 |
+
{
|
192 |
+
return strpos($text, $this->_tag) !== FALSE;
|
193 |
+
}
|
194 |
+
|
195 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Markdown/Interface.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Markdown renderer Interface
|
5 |
+
*
|
6 |
+
* @category SchumacherFM_Markdown
|
7 |
+
* @package Model
|
8 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
9 |
+
* @copyright Copyright (c)
|
10 |
+
*/
|
11 |
+
interface SchumacherFM_Markdown_Model_Markdown_Interface
|
12 |
+
{
|
13 |
+
/**
|
14 |
+
* transform markdown into html
|
15 |
+
* @param string $text
|
16 |
+
*
|
17 |
+
* @return string
|
18 |
+
*/
|
19 |
+
public static function defaultTransform($text);
|
20 |
+
|
21 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Markdown/Observer.php
ADDED
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category SchumacherFM_Markdown
|
4 |
+
* @package Model
|
5 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
+
* @copyright Copyright (c)
|
7 |
+
*/
|
8 |
+
class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdown_Model_Markdown_Abstract
|
9 |
+
{
|
10 |
+
/**
|
11 |
+
* @var null
|
12 |
+
*/
|
13 |
+
protected $_currentObserverMethod = null;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var array
|
17 |
+
*/
|
18 |
+
protected $_mdExtraUsage = array(
|
19 |
+
// observer method => config value
|
20 |
+
'renderEmailTemplate' => 'email',
|
21 |
+
);
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @return null|bool null = use global
|
25 |
+
*/
|
26 |
+
protected function _isObserverMdExtraUsage()
|
27 |
+
{
|
28 |
+
$isset = isset($this->_mdExtraUsage[$this->_currentObserverMethod]);
|
29 |
+
if (!$isset) {
|
30 |
+
return null;
|
31 |
+
}
|
32 |
+
|
33 |
+
return Mage::helper('markdown')->isMarkdownExtra($this->_mdExtraUsage[$this->_currentObserverMethod]);
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @return bool
|
38 |
+
*/
|
39 |
+
protected function _getIsExtraRenderer()
|
40 |
+
{
|
41 |
+
$globalExtra = parent::_getIsExtraRenderer();
|
42 |
+
$_observerMdExtraUsage = $this->_isObserverMdExtraUsage();
|
43 |
+
if ($_observerMdExtraUsage === null) {
|
44 |
+
return $globalExtra;
|
45 |
+
}
|
46 |
+
return $_observerMdExtraUsage;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* @param Varien_Event_Observer $observer
|
51 |
+
*
|
52 |
+
* @return null
|
53 |
+
*/
|
54 |
+
public function renderEmailTemplate(Varien_Event_Observer $observer)
|
55 |
+
{
|
56 |
+
$this->_currentObserverMethod = __FUNCTION__;
|
57 |
+
if ($this->_isDisabled) {
|
58 |
+
return null;
|
59 |
+
}
|
60 |
+
|
61 |
+
$object = $observer->getEvent()->getObject();
|
62 |
+
if (!$object instanceof Mage_Core_Model_Email_Template) {
|
63 |
+
return null;
|
64 |
+
}
|
65 |
+
|
66 |
+
$template = $object->getData('template_text');
|
67 |
+
|
68 |
+
if ($this->isMarkdown($template)) {
|
69 |
+
$object->setData('template_text', $this->_renderMarkdown($template));
|
70 |
+
$css = Mage::helper('markdown')->getTransactionalEmailCSS();
|
71 |
+
$object->setData('template_styles', $css);
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @param Varien_Event_Observer $observer
|
77 |
+
*
|
78 |
+
* @return null
|
79 |
+
*/
|
80 |
+
public function renderPage(Varien_Event_Observer $observer)
|
81 |
+
{
|
82 |
+
$this->_currentObserverMethod = __FUNCTION__;
|
83 |
+
if ($this->_isDisabled) {
|
84 |
+
return null;
|
85 |
+
}
|
86 |
+
|
87 |
+
/** @var Mage_Cms_Model_Page $page */
|
88 |
+
$page = $observer->getEvent()->getPage();
|
89 |
+
if (!$page instanceof Mage_Cms_Model_Page) {
|
90 |
+
return null;
|
91 |
+
}
|
92 |
+
$content = $this->_renderMarkdown($page->getContent());
|
93 |
+
$page->setContent($content);
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* renders every block as markdown except those having the html tags of method _isMarkdown in it
|
98 |
+
*
|
99 |
+
* @param Varien_Event_Observer $observer
|
100 |
+
*
|
101 |
+
* @return null
|
102 |
+
*/
|
103 |
+
public function renderBlock(Varien_Event_Observer $observer)
|
104 |
+
{
|
105 |
+
$this->_currentObserverMethod = __FUNCTION__;
|
106 |
+
if ($this->_isDisabled) {
|
107 |
+
return null;
|
108 |
+
}
|
109 |
+
|
110 |
+
/** @var Mage_Cms_Block_Block $page */
|
111 |
+
$block = $observer->getEvent()->getBlock();
|
112 |
+
|
113 |
+
if (!$this->_isAllowedBlock($block)) {
|
114 |
+
return null;
|
115 |
+
}
|
116 |
+
|
117 |
+
/** @var Varien_Object $transport */
|
118 |
+
$transport = $observer->getEvent()->getTransport();
|
119 |
+
|
120 |
+
/**
|
121 |
+
* you can set on any block the property ->setData('is_markdown',true)
|
122 |
+
* then the block will get rendered as markdown even if it contains html
|
123 |
+
*/
|
124 |
+
$isMarkdown = (boolean)$block->getIsMarkdown();
|
125 |
+
$this->setOptions(array(
|
126 |
+
'force' => $isMarkdown,
|
127 |
+
'protectMagento' => TRUE,
|
128 |
+
));
|
129 |
+
$html = $transport->getHtml();
|
130 |
+
$transport->setHtml($this->_renderMarkdown($html));
|
131 |
+
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* @param Varien_Object $block
|
136 |
+
*
|
137 |
+
* @return bool
|
138 |
+
*/
|
139 |
+
protected function _isAllowedBlock(Varien_Object $block)
|
140 |
+
{
|
141 |
+
return $block instanceof Mage_Cms_Block_Block || $block instanceof Mage_Cms_Block_Widget_Block;
|
142 |
+
}
|
143 |
+
|
144 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Markdown/Render.php
CHANGED
@@ -5,219 +5,7 @@
|
|
5 |
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
* @copyright Copyright (c)
|
7 |
*/
|
8 |
-
class SchumacherFM_Markdown_Model_Markdown_Render
|
9 |
{
|
10 |
-
private $_tag = '';
|
11 |
-
private $_isDisabled = FALSE;
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var string
|
15 |
-
*/
|
16 |
-
private $_currentRenderedText = '';
|
17 |
-
|
18 |
-
private $_preserveContainer = array();
|
19 |
-
|
20 |
-
/**
|
21 |
-
* @var SchumacherFM_Markdown_Model_Michelf_Markdown
|
22 |
-
*/
|
23 |
-
private $_renderer = null;
|
24 |
-
|
25 |
-
protected $_options = array();
|
26 |
-
|
27 |
-
public function __construct()
|
28 |
-
{
|
29 |
-
/**
|
30 |
-
* due to some weired parsings ... every text field which should contain MD must start with this tag
|
31 |
-
*/
|
32 |
-
$this->_tag = Mage::helper('markdown')->getDetectionTag();
|
33 |
-
$this->_isDisabled = Mage::helper('markdown')->isDisabled();
|
34 |
-
|
35 |
-
$isExtra = Mage::helper('markdown')->isMarkdownExtra() ? '_extra' : '';
|
36 |
-
$this->_renderer = Mage::getModel('markdown/michelf_markdown' . $isExtra);
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* @return SchumacherFM_Markdown_Model_Michelf_Markdown
|
41 |
-
*/
|
42 |
-
public function getRenderer()
|
43 |
-
{
|
44 |
-
return $this->_renderer;
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* @param array $options
|
49 |
-
*
|
50 |
-
* @return $this
|
51 |
-
*/
|
52 |
-
public function setOptions(array $options = null)
|
53 |
-
{
|
54 |
-
$this->_options = $options;
|
55 |
-
return $this;
|
56 |
-
}
|
57 |
-
|
58 |
-
/**
|
59 |
-
* @param string $text
|
60 |
-
*
|
61 |
-
* @return string
|
62 |
-
*/
|
63 |
-
public function renderMarkdown($text)
|
64 |
-
{
|
65 |
-
return $this->_isDisabled
|
66 |
-
? $text
|
67 |
-
: $this->_renderMarkdown($text);
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* @param Varien_Event_Observer $observer
|
72 |
-
*
|
73 |
-
* @return $this
|
74 |
-
*/
|
75 |
-
public function renderPageObserver(Varien_Event_Observer $observer)
|
76 |
-
{
|
77 |
-
if ($this->_isDisabled) {
|
78 |
-
return null;
|
79 |
-
}
|
80 |
-
|
81 |
-
/** @var Mage_Cms_Model_Page $page */
|
82 |
-
$page = $observer->getEvent()->getPage();
|
83 |
-
|
84 |
-
if ($page instanceof Mage_Cms_Model_Page) {
|
85 |
-
$this->setOptions(array(
|
86 |
-
'force' => FALSE,
|
87 |
-
'protectMagento' => TRUE,
|
88 |
-
));
|
89 |
-
$content = $this->_renderMarkdown($page->getContent());
|
90 |
-
$page->setContent($content);
|
91 |
-
}
|
92 |
-
|
93 |
-
return $this;
|
94 |
-
}
|
95 |
-
|
96 |
-
/**
|
97 |
-
* renders every block as markdown except those having the html tags of method _isMarkdown in it
|
98 |
-
*
|
99 |
-
* @param Varien_Event_Observer $observer
|
100 |
-
*
|
101 |
-
* @return $this
|
102 |
-
*/
|
103 |
-
public function renderBlockObserver(Varien_Event_Observer $observer)
|
104 |
-
{
|
105 |
-
if ($this->_isDisabled) {
|
106 |
-
return null;
|
107 |
-
}
|
108 |
-
|
109 |
-
/** @var Mage_Cms_Model_Page $page */
|
110 |
-
$block = $observer->getEvent()->getBlock();
|
111 |
-
|
112 |
-
if ($this->_isAllowedBlock($block)) {
|
113 |
-
/** @var Varien_Object $transport */
|
114 |
-
$transport = $observer->getEvent()->getTransport();
|
115 |
-
|
116 |
-
/**
|
117 |
-
* you can set on any block the property ->setData('is_markdown',true)
|
118 |
-
* then the block will get rendered as markdown even if it contains html
|
119 |
-
*/
|
120 |
-
$isMarkdown = (boolean)$block->getIsMarkdown();
|
121 |
-
$this->setOptions(array(
|
122 |
-
'force' => $isMarkdown,
|
123 |
-
'protectMagento' => FALSE,
|
124 |
-
));
|
125 |
-
$html = $transport->getHtml();
|
126 |
-
$transport->setHtml($this->_renderMarkdown($html));
|
127 |
-
|
128 |
-
}
|
129 |
-
return $this;
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* @param string $text
|
134 |
-
*
|
135 |
-
* @return string
|
136 |
-
*/
|
137 |
-
protected function _renderMarkdown($text)
|
138 |
-
{
|
139 |
-
$force = isset($this->_options['force']) && $this->_options['force'] === TRUE;
|
140 |
-
$protectMagento = isset($this->_options['protectMagento']) && $this->_options['protectMagento'] === TRUE;
|
141 |
-
$this->_currentRenderedText = $text;
|
142 |
-
if (!$this->_isMarkdown() && $force === FALSE) {
|
143 |
-
return $this->_currentRenderedText;
|
144 |
-
}
|
145 |
-
|
146 |
-
$this->_removeMarkdownTag();
|
147 |
-
if ($protectMagento) {
|
148 |
-
$this->_preserveMagentoVariablesEncode();
|
149 |
-
}
|
150 |
-
$this->_currentRenderedText = $this->getRenderer()->defaultTransform($this->_currentRenderedText);
|
151 |
-
if ($protectMagento) {
|
152 |
-
$this->_preserveMagentoVariablesDecode();
|
153 |
-
}
|
154 |
-
return $this->_currentRenderedText;
|
155 |
-
}
|
156 |
-
|
157 |
-
/**
|
158 |
-
* removes the markdown detection tag
|
159 |
-
*
|
160 |
-
* @return $this
|
161 |
-
*/
|
162 |
-
protected function _removeMarkdownTag()
|
163 |
-
{
|
164 |
-
$this->_currentRenderedText = str_replace($this->_tag, '', $this->_currentRenderedText);
|
165 |
-
return $this;
|
166 |
-
}
|
167 |
-
|
168 |
-
/**
|
169 |
-
* @return $this
|
170 |
-
*/
|
171 |
-
protected function _preserveMagentoVariablesEncode()
|
172 |
-
{
|
173 |
-
$matches = array();
|
174 |
-
preg_match_all('~(\{\{[a-z]+.+\}\})~ismU', $this->_currentRenderedText, $matches, PREG_SET_ORDER);
|
175 |
-
if (count($matches) > 0) {
|
176 |
-
foreach ($matches as $match) {
|
177 |
-
$key = md5($match[0]);
|
178 |
-
$this->_preserveContainer[$key] = $match[0];
|
179 |
-
}
|
180 |
-
$this->_currentRenderedText = str_replace(
|
181 |
-
$this->_preserveContainer, array_keys($this->_preserveContainer), $this->_currentRenderedText
|
182 |
-
);
|
183 |
-
}
|
184 |
-
return $this;
|
185 |
-
}
|
186 |
-
|
187 |
-
/**
|
188 |
-
* @return $this
|
189 |
-
*/
|
190 |
-
protected function _preserveMagentoVariablesDecode()
|
191 |
-
{
|
192 |
-
if (count($this->_preserveContainer) === 0) {
|
193 |
-
return $this;
|
194 |
-
}
|
195 |
-
$this->_currentRenderedText = str_replace(
|
196 |
-
array_keys($this->_preserveContainer), $this->_preserveContainer, $this->_currentRenderedText
|
197 |
-
);
|
198 |
-
$this->_preserveContainer = array();
|
199 |
-
return $this;
|
200 |
-
}
|
201 |
-
|
202 |
-
/**
|
203 |
-
* checks if text contains no html ... if so considered as markdown ... not a nice way...
|
204 |
-
*
|
205 |
-
* @return bool
|
206 |
-
*/
|
207 |
-
protected function _isMarkdown()
|
208 |
-
{
|
209 |
-
$flag = !empty($this->_currentRenderedText);
|
210 |
-
return $flag === TRUE && strpos($this->_currentRenderedText, $this->_tag) !== FALSE;
|
211 |
-
}
|
212 |
-
|
213 |
-
/**
|
214 |
-
* @param Mage_Core_Block_Abstract $block
|
215 |
-
*
|
216 |
-
* @return bool
|
217 |
-
*/
|
218 |
-
protected function _isAllowedBlock($block)
|
219 |
-
{
|
220 |
-
return $block instanceof Mage_Core_Block_Abstract;
|
221 |
-
}
|
222 |
|
223 |
}
|
5 |
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
* @copyright Copyright (c)
|
7 |
*/
|
8 |
+
class SchumacherFM_Markdown_Model_Markdown_Render extends SchumacherFM_Markdown_Model_Markdown_Abstract
|
9 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
}
|
app/code/community/SchumacherFM/Markdown/Model/Michelf/Markdown.php
CHANGED
@@ -13,7 +13,7 @@
|
|
13 |
# Markdown Parser Class
|
14 |
#
|
15 |
|
16 |
-
class SchumacherFM_Markdown_Model_Michelf_Markdown
|
17 |
{
|
18 |
|
19 |
### Version ###
|
13 |
# Markdown Parser Class
|
14 |
#
|
15 |
|
16 |
+
class SchumacherFM_Markdown_Model_Michelf_Markdown implements SchumacherFM_Markdown_Model_Markdown_Interface
|
17 |
{
|
18 |
|
19 |
### Version ###
|
app/code/community/SchumacherFM/Markdown/Model/Observer/AdminhtmlBlock.php
CHANGED
@@ -11,6 +11,8 @@ class SchumacherFM_Markdown_Model_Observer_AdminhtmlBlock
|
|
11 |
* adminhtml_block_html_before
|
12 |
*
|
13 |
* @param Varien_Event_Observer $observer
|
|
|
|
|
14 |
*/
|
15 |
public function alterTextareaBlockTemplate(Varien_Event_Observer $observer)
|
16 |
{
|
@@ -21,12 +23,24 @@ class SchumacherFM_Markdown_Model_Observer_AdminhtmlBlock
|
|
21 |
/** @var $block Mage_Adminhtml_Block_Template */
|
22 |
$block = $observer->getEvent()->getBlock();
|
23 |
|
24 |
-
if ($block instanceof
|
25 |
-
/** @var $
|
|
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
/** @var Mage_Adminhtml_Block_Catalog_Helper_Form_Wysiwyg $element */
|
28 |
$element = $block->getElement();
|
29 |
-
if ($this->
|
30 |
$this->_getMarkdownButtons($element);
|
31 |
}
|
32 |
}
|
@@ -37,7 +51,19 @@ class SchumacherFM_Markdown_Model_Observer_AdminhtmlBlock
|
|
37 |
*
|
38 |
* @return bool
|
39 |
*/
|
40 |
-
protected function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
{
|
42 |
$isTextarea = $element instanceof Mage_Adminhtml_Block_Catalog_Helper_Form_Wysiwyg;
|
43 |
$isDescription = stristr($element->getName(), 'description') !== FALSE && stristr($element->getName(), 'meta') === FALSE;
|
@@ -46,30 +72,79 @@ class SchumacherFM_Markdown_Model_Observer_AdminhtmlBlock
|
|
46 |
|
47 |
/**
|
48 |
* @param Varien_Data_Form_Element_Abstract $element
|
|
|
49 |
*/
|
50 |
-
protected function _getMarkdownButtons(Varien_Data_Form_Element_Abstract $element)
|
51 |
{
|
52 |
-
$html
|
|
|
53 |
|
54 |
-
$html
|
55 |
->createBlock('adminhtml/widget_button', '', array(
|
56 |
-
'label' => Mage::helper('markdown')->__('
|
57 |
'type' => 'button',
|
58 |
'class' => 'btn-wysiwyg',
|
59 |
-
'onclick' => 'toggleMarkdown(\'' .
|
60 |
-
|
61 |
-
. '\',\'' . $element->getHtmlId() . '\');'
|
62 |
-
))->toHtml().' ';
|
63 |
|
64 |
-
$html
|
65 |
->createBlock('adminhtml/widget_button', '', array(
|
66 |
-
'label' => Mage::helper('
|
67 |
'type' => 'button',
|
68 |
'class' => 'btn-wysiwyg',
|
69 |
-
'onclick' =>
|
70 |
))->toHtml();
|
71 |
|
72 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
74 |
|
75 |
}
|
11 |
* adminhtml_block_html_before
|
12 |
*
|
13 |
* @param Varien_Event_Observer $observer
|
14 |
+
*
|
15 |
+
* @return null
|
16 |
*/
|
17 |
public function alterTextareaBlockTemplate(Varien_Event_Observer $observer)
|
18 |
{
|
23 |
/** @var $block Mage_Adminhtml_Block_Template */
|
24 |
$block = $observer->getEvent()->getBlock();
|
25 |
|
26 |
+
if ($block instanceof Mage_Adminhtml_Block_Widget_Form_Renderer_Fieldset_Element) {
|
27 |
+
/** @var Varien_Data_Form_Element_Abstract $element */
|
28 |
+
$element = $block->getElement();
|
29 |
|
30 |
+
if ($this->_isEmailTemplateElementAllowed($element)) {
|
31 |
+
$element->setData('after_element_html', ' ');
|
32 |
+
$this->_getMarkdownButtons($element, 'template_text');
|
33 |
+
}
|
34 |
+
|
35 |
+
if ($this->_isElementEditor($element)) {
|
36 |
+
$this->_addLivePreviewToEditor($element);
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
if ($block instanceof Mage_Adminhtml_Block_Catalog_Form_Renderer_Fieldset_Element) {
|
41 |
/** @var Mage_Adminhtml_Block_Catalog_Helper_Form_Wysiwyg $element */
|
42 |
$element = $block->getElement();
|
43 |
+
if ($this->_isCatalogElementAllowed($element)) {
|
44 |
$this->_getMarkdownButtons($element);
|
45 |
}
|
46 |
}
|
51 |
*
|
52 |
* @return bool
|
53 |
*/
|
54 |
+
protected function _isEmailTemplateElementAllowed(Varien_Data_Form_Element_Abstract $element)
|
55 |
+
{
|
56 |
+
$trueOne = $element instanceof Varien_Data_Form_Element_Note;
|
57 |
+
$trueTwo = stristr($element->getHtmlId(), 'insert_variable') !== FALSE;
|
58 |
+
return $trueOne && $trueTwo;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
63 |
+
*
|
64 |
+
* @return bool
|
65 |
+
*/
|
66 |
+
protected function _isCatalogElementAllowed(Varien_Data_Form_Element_Abstract $element)
|
67 |
{
|
68 |
$isTextarea = $element instanceof Mage_Adminhtml_Block_Catalog_Helper_Form_Wysiwyg;
|
69 |
$isDescription = stristr($element->getName(), 'description') !== FALSE && stristr($element->getName(), 'meta') === FALSE;
|
72 |
|
73 |
/**
|
74 |
* @param Varien_Data_Form_Element_Abstract $element
|
75 |
+
* @param string|null $htmlId
|
76 |
*/
|
77 |
+
protected function _getMarkdownButtons(Varien_Data_Form_Element_Abstract $element, $htmlId = null)
|
78 |
{
|
79 |
+
$html = array($element->getData('after_element_html'));
|
80 |
+
$htmlId = empty($htmlId) ? $element->getHtmlId() : $htmlId;
|
81 |
|
82 |
+
$html[] = Mage::getSingleton('core/layout')
|
83 |
->createBlock('adminhtml/widget_button', '', array(
|
84 |
+
'label' => Mage::helper('markdown')->__('[M↓] enable'),
|
85 |
'type' => 'button',
|
86 |
'class' => 'btn-wysiwyg',
|
87 |
+
'onclick' => 'toggleMarkdown(\'' . Mage::helper('markdown')->getDetectionTag(TRUE) . '\',\'' . $htmlId . '\');'
|
88 |
+
))->toHtml();
|
|
|
|
|
89 |
|
90 |
+
$html[] = Mage::getSingleton('core/layout')
|
91 |
->createBlock('adminhtml/widget_button', '', array(
|
92 |
+
'label' => Mage::helper('markdown')->__('[M↓] Preview'),
|
93 |
'type' => 'button',
|
94 |
'class' => 'btn-wysiwyg',
|
95 |
+
'onclick' => Mage::helper('markdown')->getRenderMarkdownJs($htmlId),
|
96 |
))->toHtml();
|
97 |
|
98 |
+
$html[] = Mage::getSingleton('core/layout')
|
99 |
+
->createBlock('adminhtml/widget_button', '', array(
|
100 |
+
'label' => Mage::helper('markdown')->__('[M↓] Syntax'),
|
101 |
+
'type' => 'button',
|
102 |
+
'class' => 'btn-wysiwyg',
|
103 |
+
'onclick' => 'mdExternalUrl(\'' . SchumacherFM_Markdown_Helper_Data::URL_MD_SYNTAX . '\');'
|
104 |
+
))->toHtml();
|
105 |
+
|
106 |
+
if (Mage::helper('markdown')->isMarkdownExtra()) {
|
107 |
+
|
108 |
+
$html[] = Mage::getSingleton('core/layout')
|
109 |
+
->createBlock('adminhtml/widget_button', '', array(
|
110 |
+
'label' => Mage::helper('markdown')->__('[M↓] Extra Syntax'),
|
111 |
+
'type' => 'button',
|
112 |
+
'class' => 'btn-wysiwyg',
|
113 |
+
'onclick' => 'mdExternalUrl(\'' . SchumacherFM_Markdown_Helper_Data::URL_MD_EXTRA_SYNTAX . '\');'
|
114 |
+
))->toHtml();
|
115 |
+
}
|
116 |
+
|
117 |
+
$element->setData('after_element_html', implode(' ', $html));
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Live preview only available for non markdown extra mode.
|
122 |
+
* otherwise the ajax request and php markdown rendering would kill the users patience
|
123 |
+
*
|
124 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
125 |
+
*
|
126 |
+
* @return bool
|
127 |
+
*/
|
128 |
+
protected function _isElementEditor(Varien_Data_Form_Element_Abstract $element)
|
129 |
+
{
|
130 |
+
return !Mage::helper('markdown')->isMarkdownExtra() && $element instanceof Varien_Data_Form_Element_Editor;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* @param Varien_Data_Form_Element_Editor $element
|
135 |
+
*
|
136 |
+
* @return $this
|
137 |
+
*/
|
138 |
+
protected function _addLivePreviewToEditor(Varien_Data_Form_Element_Editor $element)
|
139 |
+
{
|
140 |
+
$previewHtml = '<div id="markdown_live_preview"
|
141 |
+
style="overflow:scroll; height:25em;"
|
142 |
+
data-mddetector="' . Mage::helper('markdown')->getDetectionTag(TRUE) . '"
|
143 |
+
data-elementid="' . $element->getHtmlId() . '" class="buttons-set"><div class="markdown">' .
|
144 |
+
Mage::helper('markdown')->__('[M↓] Live Preview enabled ...')
|
145 |
+
. '</div></div>';
|
146 |
+
$element->setData('after_element_html', $previewHtml);
|
147 |
+
return $this;
|
148 |
}
|
149 |
|
150 |
}
|
app/code/community/SchumacherFM/Markdown/controllers/Adminhtml/MarkdownController.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category SchumacherFM_Markdown
|
4 |
+
* @package Controller
|
5 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
+
* @copyright Copyright (c)
|
7 |
+
*/
|
8 |
+
class SchumacherFM_Markdown_Adminhtml_MarkdownController extends Mage_Adminhtml_Controller_Action
|
9 |
+
{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @return void
|
13 |
+
*/
|
14 |
+
public function renderAction()
|
15 |
+
{
|
16 |
+
$content = $this->getRequest()->getParam('content', null);
|
17 |
+
if (!$this->getRequest()->isPost() || empty($content)) {
|
18 |
+
return $this->_setReturn();
|
19 |
+
}
|
20 |
+
|
21 |
+
$md = Mage::helper('markdown')->render($content);
|
22 |
+
return $this->_setReturn($md);
|
23 |
+
|
24 |
+
}
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @param string $string
|
28 |
+
*
|
29 |
+
* @return $this
|
30 |
+
*/
|
31 |
+
protected function _setReturn($string = '')
|
32 |
+
{
|
33 |
+
$this->getResponse()->setBody($string);
|
34 |
+
return $this;
|
35 |
+
}
|
36 |
+
|
37 |
+
}
|
app/code/community/SchumacherFM/Markdown/etc/adminhtml.xml
CHANGED
@@ -27,4 +27,4 @@
|
|
27 |
</admin>
|
28 |
</resources>
|
29 |
</acl>
|
30 |
-
</config>
|
27 |
</admin>
|
28 |
</resources>
|
29 |
</acl>
|
30 |
+
</config>
|
app/code/community/SchumacherFM/Markdown/etc/config.xml
CHANGED
@@ -40,8 +40,8 @@
|
|
40 |
<observers>
|
41 |
<markdown_renderer>
|
42 |
<type>singleton</type>
|
43 |
-
<class>markdown/
|
44 |
-
<method>
|
45 |
</markdown_renderer>
|
46 |
</observers>
|
47 |
</cms_page_render>
|
@@ -50,14 +50,35 @@
|
|
50 |
<observers>
|
51 |
<markdown_renderer>
|
52 |
<type>singleton</type>
|
53 |
-
<class>markdown/
|
54 |
-
<method>
|
55 |
</markdown_renderer>
|
56 |
</observers>
|
57 |
</core_block_abstract_to_html_after>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
</events>
|
59 |
</frontend>
|
60 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
<adminhtml>
|
62 |
<layout>
|
63 |
<updates>
|
@@ -107,6 +128,7 @@
|
|
107 |
<markdown>
|
108 |
<enable>1</enable>
|
109 |
<md_extra>0</md_extra>
|
|
|
110 |
<detection_tag>!#markdown</detection_tag>
|
111 |
</markdown>
|
112 |
</schumacherfm>
|
40 |
<observers>
|
41 |
<markdown_renderer>
|
42 |
<type>singleton</type>
|
43 |
+
<class>markdown/markdown_observer</class>
|
44 |
+
<method>renderPage</method>
|
45 |
</markdown_renderer>
|
46 |
</observers>
|
47 |
</cms_page_render>
|
50 |
<observers>
|
51 |
<markdown_renderer>
|
52 |
<type>singleton</type>
|
53 |
+
<class>markdown/markdown_observer</class>
|
54 |
+
<method>renderBlock</method>
|
55 |
</markdown_renderer>
|
56 |
</observers>
|
57 |
</core_block_abstract_to_html_after>
|
58 |
+
|
59 |
+
<core_abstract_load_after>
|
60 |
+
<observers>
|
61 |
+
<markdown_core_email_template>
|
62 |
+
<class>markdown/markdown_observer</class>
|
63 |
+
<method>renderEmailTemplate</method>
|
64 |
+
</markdown_core_email_template>
|
65 |
+
</observers>
|
66 |
+
</core_abstract_load_after>
|
67 |
</events>
|
68 |
</frontend>
|
69 |
|
70 |
+
<admin>
|
71 |
+
<routers>
|
72 |
+
<adminhtml>
|
73 |
+
<args>
|
74 |
+
<modules>
|
75 |
+
<markdown before="Mage_Adminhtml">SchumacherFM_Markdown_Adminhtml</markdown>
|
76 |
+
</modules>
|
77 |
+
</args>
|
78 |
+
</adminhtml>
|
79 |
+
</routers>
|
80 |
+
</admin>
|
81 |
+
|
82 |
<adminhtml>
|
83 |
<layout>
|
84 |
<updates>
|
128 |
<markdown>
|
129 |
<enable>1</enable>
|
130 |
<md_extra>0</md_extra>
|
131 |
+
<md_extra_email>0</md_extra_email>
|
132 |
<detection_tag>!#markdown</detection_tag>
|
133 |
</markdown>
|
134 |
</schumacherfm>
|
app/code/community/SchumacherFM/Markdown/etc/system.xml
CHANGED
@@ -19,7 +19,7 @@
|
|
19 |
<show_in_store>1</show_in_store>
|
20 |
<groups>
|
21 |
<markdown translate="label">
|
22 |
-
<label>Markdown</label>
|
23 |
<frontend_type>text</frontend_type>
|
24 |
<sort_order>50</sort_order>
|
25 |
<show_in_default>1</show_in_default>
|
@@ -52,8 +52,29 @@
|
|
52 |
<show_in_website>1</show_in_website>
|
53 |
<show_in_store>1</show_in_store>
|
54 |
<comment>Every content field which contains markdown must have this tag included that it will be parsed.
|
55 |
-
This tag will of course be removed during parsing. If empty, every content is considered as markdown
|
|
|
|
|
56 |
</detection_tag>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
</fields>
|
58 |
</markdown>
|
59 |
</groups>
|
19 |
<show_in_store>1</show_in_store>
|
20 |
<groups>
|
21 |
<markdown translate="label">
|
22 |
+
<label>Markdown [M↓]</label>
|
23 |
<frontend_type>text</frontend_type>
|
24 |
<sort_order>50</sort_order>
|
25 |
<show_in_default>1</show_in_default>
|
52 |
<show_in_website>1</show_in_website>
|
53 |
<show_in_store>1</show_in_store>
|
54 |
<comment>Every content field which contains markdown must have this tag included that it will be parsed.
|
55 |
+
This tag will of course be removed during parsing. If empty, every content is considered as markdown.
|
56 |
+
Only transactional emails which have the detection tag somewhere integrated will be rendered with markdown.
|
57 |
+
</comment>
|
58 |
</detection_tag>
|
59 |
+
<md_extra_email translate="label">
|
60 |
+
<label>Transactional email: Use Markdown Extra</label>
|
61 |
+
<frontend_type>select</frontend_type>
|
62 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
63 |
+
<sort_order>140</sort_order>
|
64 |
+
<show_in_default>1</show_in_default>
|
65 |
+
<show_in_website>1</show_in_website>
|
66 |
+
<show_in_store>1</show_in_store>
|
67 |
+
</md_extra_email>
|
68 |
+
<te_md_css translate="label">
|
69 |
+
<label>Transactional email: Path to CSS file</label>
|
70 |
+
<frontend_type>text</frontend_type>
|
71 |
+
<sort_order>150</sort_order>
|
72 |
+
<show_in_default>1</show_in_default>
|
73 |
+
<show_in_website>1</show_in_website>
|
74 |
+
<show_in_store>1</show_in_store>
|
75 |
+
<comment><![CDATA[Relative path to the CSS to include in a transactional email. Mage::getBaseDir() is prefixed.
|
76 |
+
Will be included in the <style> tag in each email.]]></comment>
|
77 |
+
</te_md_css>
|
78 |
</fields>
|
79 |
</markdown>
|
80 |
</groups>
|
app/design/adminhtml/default/default/layout/markdown.xml
CHANGED
@@ -1,10 +1,16 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<layout>
|
3 |
-
<
|
4 |
<reference name="head">
|
5 |
<action method="addJs"><script>mage/adminhtml/markdown.js</script></action>
|
6 |
<action method="addJs"><script>mage/adminhtml/marked.js</script></action>
|
7 |
<action method="addCss"><name>markdown.css</name></action>
|
8 |
</reference>
|
|
|
|
|
|
|
9 |
</editor>
|
|
|
|
|
|
|
10 |
</layout>
|
1 |
<?xml version="1.0"?>
|
2 |
<layout>
|
3 |
+
<MARKDOWN_HEADER>
|
4 |
<reference name="head">
|
5 |
<action method="addJs"><script>mage/adminhtml/markdown.js</script></action>
|
6 |
<action method="addJs"><script>mage/adminhtml/marked.js</script></action>
|
7 |
<action method="addCss"><name>markdown.css</name></action>
|
8 |
</reference>
|
9 |
+
</MARKDOWN_HEADER>
|
10 |
+
<editor>
|
11 |
+
<update handle="MARKDOWN_HEADER"/>
|
12 |
</editor>
|
13 |
+
<adminhtml_system_email_template_edit>
|
14 |
+
<update handle="MARKDOWN_HEADER"/>
|
15 |
+
</adminhtml_system_email_template_edit>
|
16 |
</layout>
|
js/mage/adminhtml/markdown.js
CHANGED
@@ -6,72 +6,139 @@
|
|
6 |
*/
|
7 |
;
|
8 |
(function () {
|
9 |
-
var
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
var TEXT_SUFFIX = '</div>';
|
14 |
-
|
15 |
-
var htmlId = '';
|
16 |
-
|
17 |
-
var showPreview = function (responseText) {
|
18 |
-
|
19 |
-
dialogWindow = Dialog.info(TEXT_PREFIX + responseText + TEXT_SUFFIX, {
|
20 |
-
draggable: true,
|
21 |
-
resizable: true,
|
22 |
-
closable: true,
|
23 |
-
className: "magento",
|
24 |
-
windowClassName: "popup-window",
|
25 |
-
title: 'Markdown Preview',
|
26 |
-
width: 800,
|
27 |
-
height: 480,
|
28 |
-
zIndex: 1000,
|
29 |
-
recenterAuto: false,
|
30 |
-
hideEffect: Element.hide,
|
31 |
-
showEffect: Element.show,
|
32 |
-
id: dialogWindowId,
|
33 |
-
onClose: closeDialogWindow.bind(this)
|
34 |
-
});
|
35 |
-
}
|
36 |
|
37 |
-
|
38 |
-
if (!window) {
|
39 |
-
window = dialogWindow;
|
40 |
-
}
|
41 |
-
if (window) {
|
42 |
-
window.close();
|
43 |
-
}
|
44 |
-
}
|
45 |
|
46 |
-
|
47 |
-
showPreview(marked($(htmlId).value));
|
48 |
-
}
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
-
|
63 |
-
detectionTag = unescape(detectionTag);
|
64 |
|
65 |
-
|
66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
}
|
68 |
-
alert('Markdown enabled with tag: "' + detectionTag+'"');
|
69 |
}
|
70 |
|
71 |
this.renderMarkdown = renderMarkdown;
|
72 |
-
this.
|
73 |
this.toggleMarkdown = toggleMarkdown;
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
}).call(function () {
|
76 |
return this || (typeof window !== 'undefined' ? window : global);
|
77 |
}());
|
6 |
*/
|
7 |
;
|
8 |
(function () {
|
9 |
+
var dialogWindow,
|
10 |
+
dialogWindowId = 'markdown-preview',
|
11 |
+
TEXT_PREFIX = '<div class="markdown">',
|
12 |
+
TEXT_SUFFIX = '</div>',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
htmlId = '',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
+
showPreview = function (responseText) {
|
|
|
|
|
17 |
|
18 |
+
dialogWindow = Dialog.info(TEXT_PREFIX + responseText + TEXT_SUFFIX, {
|
19 |
+
draggable: true,
|
20 |
+
resizable: true,
|
21 |
+
closable: true,
|
22 |
+
className: "magento",
|
23 |
+
windowClassName: "popup-window",
|
24 |
+
title: 'Markdown Preview',
|
25 |
+
width: 800,
|
26 |
+
height: 480,
|
27 |
+
zIndex: 1000,
|
28 |
+
recenterAuto: false,
|
29 |
+
hideEffect: Element.hide,
|
30 |
+
showEffect: Element.show,
|
31 |
+
id: dialogWindowId,
|
32 |
+
onClose: closeDialogWindow.bind(this)
|
33 |
+
});
|
34 |
+
},
|
35 |
|
36 |
+
closeDialogWindow = function (window) {
|
37 |
+
if (!window) {
|
38 |
+
window = dialogWindow;
|
39 |
+
}
|
40 |
+
if (window) {
|
41 |
+
window.close();
|
42 |
+
}
|
43 |
+
},
|
44 |
|
45 |
+
_renderMarkdownJs = function (mdDetector) {
|
46 |
+
mdDetector = unescape(mdDetector);
|
47 |
+
showPreview(marked($(htmlId).value.replace(mdDetector, '')));
|
48 |
+
},
|
49 |
+
|
50 |
+
_renderMarkdownAjax = function (url) {
|
51 |
+
new Ajax.Request(url, {
|
52 |
+
method: 'post',
|
53 |
+
parameters: {"content": $(htmlId).value},
|
54 |
+
onComplete: function (data) {
|
55 |
+
showPreview((data && data.responseText) ? data.responseText : 'Ajax Error');
|
56 |
+
}
|
57 |
+
});
|
58 |
+
|
59 |
+
},
|
60 |
+
|
61 |
+
renderMarkdown = function (Idhtml, mdDetector, renderUrl) {
|
62 |
+
htmlId = Idhtml;
|
63 |
+
if (renderUrl && typeof renderUrl === 'string') {
|
64 |
+
_renderMarkdownAjax(renderUrl);
|
65 |
+
} else {
|
66 |
+
_renderMarkdownJs(mdDetector);
|
67 |
+
}
|
68 |
+
return;
|
69 |
|
70 |
+
},
|
|
|
71 |
|
72 |
+
mdExternalUrl = function (url, Idhtml) {
|
73 |
+
htmlId = Idhtml;
|
74 |
+
window.open(url);
|
75 |
+
},
|
76 |
+
|
77 |
+
toggleMarkdown = function (detectionTag, Idhtml) {
|
78 |
+
detectionTag = unescape(detectionTag);
|
79 |
+
|
80 |
+
if ($(Idhtml).value.indexOf(detectionTag) === -1) {
|
81 |
+
$(Idhtml).value = detectionTag + "\n" + $(Idhtml).value;
|
82 |
+
}
|
83 |
+
alert('Markdown enabled with tag: "' + detectionTag + '"');
|
84 |
+
},
|
85 |
+
|
86 |
+
_livePreview = function ($markdownLivePreview) {
|
87 |
+
var editorId = $markdownLivePreview.readAttribute('data-elementid'),
|
88 |
+
$editorId = $(editorId),
|
89 |
+
_mdHandling = new _mdHandler();
|
90 |
+
|
91 |
+
_mdHandling.setMdDetector($markdownLivePreview);
|
92 |
+
|
93 |
+
var _originalHeight = $markdownLivePreview.getStyle('height'), _clicked = false;
|
94 |
+
$markdownLivePreview.observe('click', function (e) {
|
95 |
+
var css = {height: ''};
|
96 |
+
if (_clicked) {
|
97 |
+
css['height'] = _originalHeight;
|
98 |
+
_clicked = false;
|
99 |
+
} else {
|
100 |
+
_clicked = true;
|
101 |
+
}
|
102 |
+
$markdownLivePreview.setStyle(css);
|
103 |
+
});
|
104 |
+
|
105 |
+
$editorId.observe('keyup', function (e) {
|
106 |
+
_mdHandling.text = e.target.value;
|
107 |
+
$markdownLivePreview.innerHTML = _mdHandling.hasMarkdown()
|
108 |
+
? _mdHandling.getRenderedMarkdown()
|
109 |
+
: 'Offline ...';
|
110 |
+
});
|
111 |
+
},
|
112 |
+
|
113 |
+
_mdHandler = function () {
|
114 |
+
this.text = '';
|
115 |
+
this._mdDetector = '';
|
116 |
+
};
|
117 |
+
|
118 |
+
_mdHandler.prototype = {
|
119 |
+
setMdDetector: function ($markdownLivePreview) {
|
120 |
+
this._mdDetector = unescape($markdownLivePreview.readAttribute('data-mddetector') || '~~~@#$#@!');
|
121 |
+
return this;
|
122 |
+
},
|
123 |
+
getRenderedMarkdown: function () {
|
124 |
+
return TEXT_PREFIX + marked(this.text.replace(this._mdDetector, '')) + TEXT_SUFFIX;
|
125 |
+
},
|
126 |
+
hasMarkdown: function () {
|
127 |
+
return this.text.indexOf(this._mdDetector) !== -1;
|
128 |
}
|
|
|
129 |
}
|
130 |
|
131 |
this.renderMarkdown = renderMarkdown;
|
132 |
+
this.mdExternalUrl = mdExternalUrl;
|
133 |
this.toggleMarkdown = toggleMarkdown;
|
134 |
|
135 |
+
document.observe('dom:loaded', function () {
|
136 |
+
var markdownLivePreview = $('markdown_live_preview');
|
137 |
+
if (markdownLivePreview) {
|
138 |
+
_livePreview(markdownLivePreview);
|
139 |
+
}
|
140 |
+
});
|
141 |
+
|
142 |
}).call(function () {
|
143 |
return this || (typeof window !== 'undefined' ? window : global);
|
144 |
}());
|
js/mage/adminhtml/marked.js
CHANGED
@@ -17,7 +17,7 @@
|
|
17 |
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
|
18 |
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
|
19 |
nptable: noop,
|
20 |
-
lheading: /^([^\n]+)\n *(=|-){
|
21 |
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
|
22 |
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
|
23 |
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
|
@@ -75,7 +75,9 @@
|
|
75 |
});
|
76 |
|
77 |
block.gfm.paragraph = replace(block.paragraph)
|
78 |
-
('(?!', '(?!'
|
|
|
|
|
79 |
();
|
80 |
|
81 |
/**
|
@@ -320,7 +322,7 @@
|
|
320 |
// for discount behavior.
|
321 |
loose = next || /\n\n(?!\s*$)/.test(item);
|
322 |
if (i !== l - 1) {
|
323 |
-
next = item
|
324 |
if (!loose) loose = next;
|
325 |
}
|
326 |
|
@@ -352,7 +354,7 @@
|
|
352 |
type: this.options.sanitize
|
353 |
? 'paragraph'
|
354 |
: 'html',
|
355 |
-
pre: cap[1] === 'pre' || cap[1] === 'script',
|
356 |
text: cap[0]
|
357 |
});
|
358 |
continue;
|
@@ -407,7 +409,7 @@
|
|
407 |
src = src.substring(cap[0].length);
|
408 |
this.tokens.push({
|
409 |
type: 'paragraph',
|
410 |
-
text: cap[1]
|
411 |
? cap[1].slice(0, -1)
|
412 |
: cap[1]
|
413 |
});
|
@@ -454,8 +456,8 @@
|
|
454 |
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
|
455 |
};
|
456 |
|
457 |
-
inline._inside = /(?:\[[^\]]*\]|[^\]]|\](?=[^\[]*\]))*/;
|
458 |
-
inline._href = /\s*<?([
|
459 |
|
460 |
inline.link = replace(inline.link)
|
461 |
('inside', inline._inside)
|
@@ -567,7 +569,7 @@
|
|
567 |
if (cap = this.rules.autolink.exec(src)) {
|
568 |
src = src.substring(cap[0].length);
|
569 |
if (cap[2] === '@') {
|
570 |
-
text = cap[1]
|
571 |
? this.mangle(cap[1].substring(7))
|
572 |
: this.mangle(cap[1]);
|
573 |
href = this.mangle('mailto:') + text;
|
@@ -622,7 +624,7 @@
|
|
622 |
link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
|
623 |
link = this.links[link.toLowerCase()];
|
624 |
if (!link || !link.href) {
|
625 |
-
out += cap[0]
|
626 |
src = cap[0].substring(1) + src;
|
627 |
continue;
|
628 |
}
|
@@ -694,7 +696,7 @@
|
|
694 |
*/
|
695 |
|
696 |
InlineLexer.prototype.outputLink = function (cap, link) {
|
697 |
-
if (cap[0]
|
698 |
return '<a href="'
|
699 |
+ escape(link.href)
|
700 |
+ '"'
|
@@ -728,9 +730,17 @@
|
|
728 |
InlineLexer.prototype.smartypants = function (text) {
|
729 |
if (!this.options.smartypants) return text;
|
730 |
return text
|
|
|
731 |
.replace(/--/g, '\u2014')
|
732 |
-
|
733 |
-
.replace(/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
734 |
.replace(/\.{3}/g, '\u2026');
|
735 |
};
|
736 |
|
@@ -838,7 +848,9 @@
|
|
838 |
{
|
839 |
return '<h'
|
840 |
+ this.token.depth
|
841 |
-
+ '
|
|
|
|
|
842 |
+ this.inline.output(this.token.text)
|
843 |
+ '</h'
|
844 |
+ this.token.depth
|
@@ -882,9 +894,11 @@
|
|
882 |
body += '<thead>\n<tr>\n';
|
883 |
for (i = 0; i < this.token.header.length; i++) {
|
884 |
heading = this.inline.output(this.token.header[i]);
|
885 |
-
body +=
|
886 |
-
|
887 |
-
|
|
|
|
|
888 |
}
|
889 |
body += '</tr>\n</thead>\n';
|
890 |
|
@@ -895,9 +909,11 @@
|
|
895 |
body += '<tr>\n';
|
896 |
for (j = 0; j < row.length; j++) {
|
897 |
cell = this.inline.output(row[j]);
|
898 |
-
body +=
|
899 |
-
|
900 |
-
|
|
|
|
|
901 |
}
|
902 |
body += '</tr>\n';
|
903 |
}
|
@@ -1041,7 +1057,7 @@
|
|
1041 |
opt = null;
|
1042 |
}
|
1043 |
|
1044 |
-
|
1045 |
|
1046 |
var highlight = opt.highlight
|
1047 |
, tokens
|
@@ -1056,13 +1072,9 @@
|
|
1056 |
|
1057 |
pending = tokens.length;
|
1058 |
|
1059 |
-
var done = function (
|
1060 |
var out, err;
|
1061 |
|
1062 |
-
if (hi !== true) {
|
1063 |
-
delete opt.highlight;
|
1064 |
-
}
|
1065 |
-
|
1066 |
try {
|
1067 |
out = Parser.parse(tokens, opt);
|
1068 |
} catch (e) {
|
@@ -1077,9 +1089,11 @@
|
|
1077 |
};
|
1078 |
|
1079 |
if (!highlight || highlight.length < 3) {
|
1080 |
-
return done(
|
1081 |
}
|
1082 |
|
|
|
|
|
1083 |
if (!pending) return done();
|
1084 |
|
1085 |
for (; i < tokens.length; i++) {
|
@@ -1164,4 +1178,4 @@
|
|
1164 |
|
1165 |
}).call(function () {
|
1166 |
return this || (typeof window !== 'undefined' ? window : global);
|
1167 |
-
}());
|
17 |
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
|
18 |
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
|
19 |
nptable: noop,
|
20 |
+
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
|
21 |
blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/,
|
22 |
list: /^( *)(bull) [\s\S]+?(?:hr|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
|
23 |
html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/,
|
75 |
});
|
76 |
|
77 |
block.gfm.paragraph = replace(block.paragraph)
|
78 |
+
('(?!', '(?!'
|
79 |
+
+ block.gfm.fences.source.replace('\\1', '\\2') + '|'
|
80 |
+
+ block.list.source.replace('\\1', '\\3') + '|')
|
81 |
();
|
82 |
|
83 |
/**
|
322 |
// for discount behavior.
|
323 |
loose = next || /\n\n(?!\s*$)/.test(item);
|
324 |
if (i !== l - 1) {
|
325 |
+
next = item.charAt(item.length - 1) === '\n';
|
326 |
if (!loose) loose = next;
|
327 |
}
|
328 |
|
354 |
type: this.options.sanitize
|
355 |
? 'paragraph'
|
356 |
: 'html',
|
357 |
+
pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',
|
358 |
text: cap[0]
|
359 |
});
|
360 |
continue;
|
409 |
src = src.substring(cap[0].length);
|
410 |
this.tokens.push({
|
411 |
type: 'paragraph',
|
412 |
+
text: cap[1].charAt(cap[1].length - 1) === '\n'
|
413 |
? cap[1].slice(0, -1)
|
414 |
: cap[1]
|
415 |
});
|
456 |
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
|
457 |
};
|
458 |
|
459 |
+
inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
|
460 |
+
inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
|
461 |
|
462 |
inline.link = replace(inline.link)
|
463 |
('inside', inline._inside)
|
569 |
if (cap = this.rules.autolink.exec(src)) {
|
570 |
src = src.substring(cap[0].length);
|
571 |
if (cap[2] === '@') {
|
572 |
+
text = cap[1].charAt(6) === ':'
|
573 |
? this.mangle(cap[1].substring(7))
|
574 |
: this.mangle(cap[1]);
|
575 |
href = this.mangle('mailto:') + text;
|
624 |
link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
|
625 |
link = this.links[link.toLowerCase()];
|
626 |
if (!link || !link.href) {
|
627 |
+
out += cap[0].charAt(0);
|
628 |
src = cap[0].substring(1) + src;
|
629 |
continue;
|
630 |
}
|
696 |
*/
|
697 |
|
698 |
InlineLexer.prototype.outputLink = function (cap, link) {
|
699 |
+
if (cap[0].charAt(0) !== '!') {
|
700 |
return '<a href="'
|
701 |
+ escape(link.href)
|
702 |
+ '"'
|
730 |
InlineLexer.prototype.smartypants = function (text) {
|
731 |
if (!this.options.smartypants) return text;
|
732 |
return text
|
733 |
+
// em-dashes
|
734 |
.replace(/--/g, '\u2014')
|
735 |
+
// opening singles
|
736 |
+
.replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
|
737 |
+
// closing singles & apostrophes
|
738 |
+
.replace(/'/g, '\u2019')
|
739 |
+
// opening doubles
|
740 |
+
.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
|
741 |
+
// closing doubles
|
742 |
+
.replace(/"/g, '\u201d')
|
743 |
+
// ellipses
|
744 |
.replace(/\.{3}/g, '\u2026');
|
745 |
};
|
746 |
|
848 |
{
|
849 |
return '<h'
|
850 |
+ this.token.depth
|
851 |
+
+ ' id="'
|
852 |
+
+ this.token.text.toLowerCase().replace(/[^\w]+/g, '-')
|
853 |
+
+ '">'
|
854 |
+ this.inline.output(this.token.text)
|
855 |
+ '</h'
|
856 |
+ this.token.depth
|
894 |
body += '<thead>\n<tr>\n';
|
895 |
for (i = 0; i < this.token.header.length; i++) {
|
896 |
heading = this.inline.output(this.token.header[i]);
|
897 |
+
body += '<th';
|
898 |
+
if (this.token.align[i]) {
|
899 |
+
body += ' style="text-align:' + this.token.align[i] + '"';
|
900 |
+
}
|
901 |
+
body += '>' + heading + '</th>\n';
|
902 |
}
|
903 |
body += '</tr>\n</thead>\n';
|
904 |
|
909 |
body += '<tr>\n';
|
910 |
for (j = 0; j < row.length; j++) {
|
911 |
cell = this.inline.output(row[j]);
|
912 |
+
body += '<td';
|
913 |
+
if (this.token.align[j]) {
|
914 |
+
body += ' style="text-align:' + this.token.align[j] + '"';
|
915 |
+
}
|
916 |
+
body += '>' + cell + '</td>\n';
|
917 |
}
|
918 |
body += '</tr>\n';
|
919 |
}
|
1057 |
opt = null;
|
1058 |
}
|
1059 |
|
1060 |
+
opt = merge({}, marked.defaults, opt || {});
|
1061 |
|
1062 |
var highlight = opt.highlight
|
1063 |
, tokens
|
1072 |
|
1073 |
pending = tokens.length;
|
1074 |
|
1075 |
+
var done = function () {
|
1076 |
var out, err;
|
1077 |
|
|
|
|
|
|
|
|
|
1078 |
try {
|
1079 |
out = Parser.parse(tokens, opt);
|
1080 |
} catch (e) {
|
1089 |
};
|
1090 |
|
1091 |
if (!highlight || highlight.length < 3) {
|
1092 |
+
return done();
|
1093 |
}
|
1094 |
|
1095 |
+
delete opt.highlight;
|
1096 |
+
|
1097 |
if (!pending) return done();
|
1098 |
|
1099 |
for (; i < tokens.length; i++) {
|
1178 |
|
1179 |
}).call(function () {
|
1180 |
return this || (typeof window !== 'undefined' ? window : global);
|
1181 |
+
}());
|
package.xml
CHANGED
@@ -1,28 +1,30 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>markdown</name>
|
4 |
-
<version>1.
|
5 |
<stability>stable</stability>
|
6 |
<license uri="https://github.com/SchumacherFM/Magento-Markdown">Custom</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
-
<summary>Markdown as module for Magento! Replaces the TinyMCE editor. Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).</summary>
|
10 |
-
<description>Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).
|
11 |

|
12 |
Full documentation of Markdown's syntax is available on John's Markdown page: http://daringfireball.net/projects/markdown/
|
13 |

|
14 |
Full support of Markdown Extra: http://michelf.ca/projects/php-markdown/extra/
|
15 |

|
16 |
-
This module renders all CMS pages and
|
17 |

|
18 |
Rendering of catalog description fields have to be implemented in the phtml files by yourself.
|
19 |

|
20 |
-
Preview in the backend.
|
|
|
|
|
21 |
<notes>https://github.com/SchumacherFM/Magento-Markdown</notes>
|
22 |
<authors><author><name>Cyrill Schumacher</name><user>cyrills</user><email>cyrill@schumacher.fm</email></author></authors>
|
23 |
-
<date>2013-09-
|
24 |
-
<time>
|
25 |
-
<contents><target name="magecommunity"><dir name="SchumacherFM"><dir name="Markdown"><dir><dir name="Helper"><file name="Data.php" hash="
|
26 |
<compatible/>
|
27 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
28 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>markdown</name>
|
4 |
+
<version>1.4.0</version>
|
5 |
<stability>stable</stability>
|
6 |
<license uri="https://github.com/SchumacherFM/Magento-Markdown">Custom</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
+
<summary>Mage Markdown as module for Magento! Replaces the TinyMCE editor. Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).</summary>
|
10 |
+
<description>Mage Markdown is a text-to-HTML conversion tool for web writers. Markdown allows you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML).
|
11 |

|
12 |
Full documentation of Markdown's syntax is available on John's Markdown page: http://daringfireball.net/projects/markdown/
|
13 |

|
14 |
Full support of Markdown Extra: http://michelf.ca/projects/php-markdown/extra/
|
15 |

|
16 |
+
This module renders all CMS pages and CMS blocks.
|
17 |

|
18 |
Rendering of catalog description fields have to be implemented in the phtml files by yourself.
|
19 |

|
20 |
+
Preview in the backend. Live preview available in CMS Pages.
|
21 |
+

|
22 |
+
For further information please see the github repository: https://github.com/SchumacherFM/Magento-Markdown</description>
|
23 |
<notes>https://github.com/SchumacherFM/Magento-Markdown</notes>
|
24 |
<authors><author><name>Cyrill Schumacher</name><user>cyrills</user><email>cyrill@schumacher.fm</email></author></authors>
|
25 |
+
<date>2013-09-08</date>
|
26 |
+
<time>10:27:17</time>
|
27 |
+
<contents><target name="magecommunity"><dir name="SchumacherFM"><dir name="Markdown"><dir><dir name="Helper"><file name="Data.php" hash="35789036d57008a39effa53ed597d737"/></dir><dir name="Model"><dir name="Editor"><file name="Config.php" hash="44c6244ec440e8150778079cd184e5de"/><file name="Observer.php" hash="ad29b486cbe198b89e04db266d10c16b"/></dir><dir name="Markdown"><file name="Abstract.php" hash="496f33e550c20301a8a4c62c5cbf35a2"/><file name="Interface.php" hash="05df0ecf7a7c6bc09481f213cdc98255"/><file name="Observer.php" hash="e357583f380bcc925cc663d44f6120da"/><file name="Render.php" hash="df0addc5cfbd8d805c0b8a1661bbd496"/></dir><dir name="Michelf"><dir name="Markdown"><file name="Extra.php" hash="aaee7a66298007f8c003ba96d53deab9"/><file name="TmpImpl.php" hash="5ec68c28519d8ecb4a43324f5f197a80"/></dir><file name="Markdown.php" hash="76219ba32f37cad14755c8613b390c83"/></dir><dir name="Observer"><file name="AdminhtmlBlock.php" hash="50f7c3f848f847ef7b35206f7f48914f"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="MarkdownController.php" hash="9a7e8a64624159af49a18ad135d721ae"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="1f4034751ea0e0eece21d0015ee95e1a"/><file name="config.xml" hash="e398afbbb64dc97de74baf605ebc64fc"/><file name="system.xml" hash="0cee296bcf061251c7eab51dfefe224f"/></dir><dir name="sql"><dir name="markdown_setup"><file name="install-1.0.0.php" hash="0fe5a9650dd224f691caf585a34c52e6"/></dir></dir></dir><file name=".DS_Store" hash="29236c1e2932a8a54035bfbe9e734f49"/></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="markdown.xml" hash="ceece632ae2ebda2c33f7a7a37f9d7d2"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="SchumacherFM_Markdown.xml" hash="db8742448ef30a5af1bd60865f429c26"/></dir></target><target name="magelocale"><dir><dir name="de_DE"><file name="SchumacherFM_Markdown.csv" hash="d41d8cd98f00b204e9800998ecf8427e"/></dir><dir name="en_US"><file name="SchumacherFM_Markdown.csv" hash="d41d8cd98f00b204e9800998ecf8427e"/></dir></dir></target><target name="mage"><dir name="js"><dir name="mage"><dir name="adminhtml"><file name="markdown.js" hash="62a8ef8105db7defd76fa9f8bca6bfce"/><file name="marked.js" hash="5dbb480da6528c11cd99f3d17cc6aad5"/></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><file name="markdown.css" hash="68699f62ea8666484819346ff143ee88"/></dir></dir></dir></target></contents>
|
28 |
<compatible/>
|
29 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
30 |
</package>
|