Version Notes
https://github.com/SchumacherFM/Magento-Markdown
Tons of new features! See the github pages for the version history.
Download this release
Release Info
Developer | Cyrill Schumacher |
Extension | markdown |
Version | 2.0.0 |
Comparing to | |
See all releases |
Code changes from version 1.4.2 to 2.0.0
- app/code/community/SchumacherFM/Markdown/Helper/Data.php +140 -15
- app/code/community/SchumacherFM/Markdown/Model/Editor/Config.php +0 -85
- app/code/community/SchumacherFM/Markdown/Model/Editor/Observer.php +1 -20
- app/code/community/SchumacherFM/Markdown/Model/Markdown/Abstract.php +24 -10
- app/code/community/SchumacherFM/Markdown/Model/Markdown/Observer.php +14 -11
- app/code/community/SchumacherFM/Markdown/Model/Observer/Adminhtml/Block.php +318 -0
- app/code/community/SchumacherFM/Markdown/Model/Observer/Adminhtml/EpicEditor.php +87 -0
- app/code/community/SchumacherFM/Markdown/Model/Observer/Adminhtml/LayoutUpdate.php +66 -0
- app/code/community/SchumacherFM/Markdown/Model/Observer/AdminhtmlBlock.php +0 -150
- app/code/community/SchumacherFM/Markdown/controllers/Adminhtml/MarkdownController.php +82 -6
- app/code/community/SchumacherFM/Markdown/etc/adminhtml.xml +3 -3
- app/code/community/SchumacherFM/Markdown/etc/config.xml +29 -18
- app/code/community/SchumacherFM/Markdown/etc/system.xml +150 -19
- app/design/adminhtml/default/default/layout/markdown.xml +18 -9
- js/mage/adminhtml/markdown.js +0 -144
- js/mage/adminhtml/marked.js +0 -1181
- js/markdown/adminhtml/epiceditor.js +1896 -0
- js/markdown/adminhtml/filereader.js +446 -0
- js/markdown/adminhtml/highlight.pack.js +2 -0
- js/markdown/adminhtml/highlight/styles/xcode.css +154 -0
- js/markdown/adminhtml/markdown.js +715 -0
- js/markdown/adminhtml/marked.js +1165 -0
- js/markdown/adminhtml/reMarked.js +636 -0
- package.xml +19 -16
- skin/adminhtml/default/default/epiceditor/highlight/styles/default.css +135 -0
- skin/adminhtml/default/default/epiceditor/highlight/styles/github.css +127 -0
- skin/adminhtml/default/default/epiceditor/highlight/styles/googlecode.css +144 -0
- skin/adminhtml/default/default/epiceditor/themes/base/epiceditor.css +64 -0
- skin/adminhtml/default/default/epiceditor/themes/editor/epic-dark.css +15 -0
- skin/adminhtml/default/default/epiceditor/themes/editor/epic-light.css +14 -0
- skin/adminhtml/default/default/epiceditor/themes/preview/bartik.css +167 -0
- skin/adminhtml/default/default/epiceditor/themes/preview/github.css +368 -0
- skin/adminhtml/default/default/epiceditor/themes/preview/githubNxcode.css +533 -0
- skin/adminhtml/default/default/epiceditor/themes/preview/preview-dark.css +143 -0
- skin/adminhtml/default/default/markdown.css +0 -310
- skin/adminhtml/default/default/markdown/mdm.css +6 -0
app/code/community/SchumacherFM/Markdown/Helper/Data.php
CHANGED
@@ -7,7 +7,6 @@
|
|
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 |
/**
|
@@ -20,13 +19,21 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
20 |
*
|
21 |
* @return string
|
22 |
*/
|
23 |
-
public function render($text, array $options =
|
24 |
{
|
25 |
return Mage::getSingleton('markdown/markdown_render')
|
26 |
->setOptions($options)
|
27 |
->renderMarkdown($text);
|
28 |
}
|
29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
/**
|
31 |
* @param bool $encoded
|
32 |
*
|
@@ -34,7 +41,10 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
34 |
*/
|
35 |
public function getDetectionTag($encoded = FALSE)
|
36 |
{
|
37 |
-
$tag = Mage::getStoreConfig('
|
|
|
|
|
|
|
38 |
return $encoded ? rawurlencode($tag) : $tag;
|
39 |
}
|
40 |
|
@@ -47,7 +57,7 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
47 |
*/
|
48 |
public function isDisabled()
|
49 |
{
|
50 |
-
return !(boolean)Mage::getStoreConfig('
|
51 |
}
|
52 |
|
53 |
/**
|
@@ -55,9 +65,9 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
55 |
*
|
56 |
* @return bool
|
57 |
*/
|
58 |
-
public function isMarkdownExtra($type =
|
59 |
{
|
60 |
-
return (boolean)Mage::getStoreConfig('
|
61 |
}
|
62 |
|
63 |
/**
|
@@ -70,7 +80,7 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
70 |
*/
|
71 |
public function getTransactionalEmailCSS()
|
72 |
{
|
73 |
-
$file = Mage::getStoreConfig('
|
74 |
if (empty($file)) {
|
75 |
return '';
|
76 |
}
|
@@ -85,24 +95,139 @@ class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
|
85 |
}
|
86 |
|
87 |
/**
|
|
|
|
|
88 |
* @return string
|
89 |
*/
|
90 |
-
public function getAdminRenderUrl()
|
91 |
{
|
92 |
-
return Mage::helper(
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
-
* @param
|
97 |
*
|
98 |
* @return string
|
99 |
*/
|
100 |
-
public function
|
101 |
{
|
102 |
-
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
}
|
106 |
-
return
|
107 |
}
|
108 |
}
|
7 |
*/
|
8 |
class SchumacherFM_Markdown_Helper_Data extends Mage_Core_Helper_Abstract
|
9 |
{
|
|
|
10 |
const URL_MD_EXTRA_SYNTAX = 'http://michelf.ca/projects/php-markdown/extra/';
|
11 |
|
12 |
/**
|
19 |
*
|
20 |
* @return string
|
21 |
*/
|
22 |
+
public function render($text, array $options = NULL)
|
23 |
{
|
24 |
return Mage::getSingleton('markdown/markdown_render')
|
25 |
->setOptions($options)
|
26 |
->renderMarkdown($text);
|
27 |
}
|
28 |
|
29 |
+
/**
|
30 |
+
* @return mixed|string
|
31 |
+
*/
|
32 |
+
public function getCheatSheetUrl()
|
33 |
+
{
|
34 |
+
return Mage::getStoreConfig('markdown/markdown/cheatsheet');
|
35 |
+
}
|
36 |
+
|
37 |
/**
|
38 |
* @param bool $encoded
|
39 |
*
|
41 |
*/
|
42 |
public function getDetectionTag($encoded = FALSE)
|
43 |
{
|
44 |
+
$tag = trim(Mage::getStoreConfig('markdown/markdown/detection_tag'));
|
45 |
+
if (empty($tag) === TRUE) {
|
46 |
+
return '';
|
47 |
+
}
|
48 |
return $encoded ? rawurlencode($tag) : $tag;
|
49 |
}
|
50 |
|
57 |
*/
|
58 |
public function isDisabled()
|
59 |
{
|
60 |
+
return !(boolean)Mage::getStoreConfig('markdown/markdown/enable');
|
61 |
}
|
62 |
|
63 |
/**
|
65 |
*
|
66 |
* @return bool
|
67 |
*/
|
68 |
+
public function isMarkdownExtra($type = NULL)
|
69 |
{
|
70 |
+
return (boolean)Mage::getStoreConfig('markdown/markdown_extra/enable' . (!empty($type) ? '_' . $type : ''));
|
71 |
}
|
72 |
|
73 |
/**
|
80 |
*/
|
81 |
public function getTransactionalEmailCSS()
|
82 |
{
|
83 |
+
$file = Mage::getStoreConfig('markdown/markdown_extra/te_md_css');
|
84 |
if (empty($file)) {
|
85 |
return '';
|
86 |
}
|
95 |
}
|
96 |
|
97 |
/**
|
98 |
+
* @param array $params
|
99 |
+
*
|
100 |
* @return string
|
101 |
*/
|
102 |
+
public function getAdminRenderUrl(array $params = NULL)
|
103 |
{
|
104 |
+
return Mage::helper('adminhtml')->getUrl('adminhtml/markdown/render', $params);
|
105 |
}
|
106 |
|
107 |
/**
|
108 |
+
* @param array $params
|
109 |
*
|
110 |
* @return string
|
111 |
*/
|
112 |
+
public function getAdminFileUploadUrl(array $params = NULL)
|
113 |
{
|
114 |
+
return Mage::helper('adminhtml')->getUrl('adminhtml/markdown/fileUpload', $params);
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* @param array $params
|
119 |
+
*
|
120 |
+
* @return string
|
121 |
+
*/
|
122 |
+
public function getAdminEnableUrl(array $params = NULL)
|
123 |
+
{
|
124 |
+
return Mage::helper('adminhtml')->getUrl('adminhtml/markdown/enable', $params);
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* @return bool
|
129 |
+
*/
|
130 |
+
public function isEpicEditorEnabled()
|
131 |
+
{
|
132 |
+
return (boolean)Mage::getStoreConfig('markdown/epiceditor/enable');
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* @return bool
|
137 |
+
*/
|
138 |
+
public function isEpicEditorLoadOnClick()
|
139 |
+
{
|
140 |
+
return (boolean)Mage::getStoreConfig('markdown/epiceditor/load_on_click_textarea');
|
141 |
+
}
|
142 |
+
|
143 |
+
/**
|
144 |
+
* if json is invalid returns false
|
145 |
+
*
|
146 |
+
* @return string|boolean
|
147 |
+
*/
|
148 |
+
public function getEpicEditorConfig()
|
149 |
+
{
|
150 |
+
$config = $this->_getJsonConfig('epiceditor');
|
151 |
+
$config = FALSE !== $config ? json_decode($config, TRUE) : array();
|
152 |
+
$config['basePath'] = Mage::getBaseUrl('skin') . 'adminhtml/default/default/epiceditor/';
|
153 |
+
return json_encode($config);
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* if json is invalid returns false
|
158 |
+
*
|
159 |
+
* @param string $type
|
160 |
+
*
|
161 |
+
* @return bool|string
|
162 |
+
*/
|
163 |
+
protected function _getJsonConfig($type)
|
164 |
+
{
|
165 |
+
$config = trim(Mage::getStoreConfig('markdown/' . $type . '/config'));
|
166 |
+
if (empty($config)) {
|
167 |
+
return FALSE;
|
168 |
+
}
|
169 |
+
$decoded = json_decode($config);
|
170 |
+
return $decoded instanceof stdClass ? rawurlencode($config) : FALSE;
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* @return bool
|
175 |
+
*/
|
176 |
+
public function isReMarkedEnabled()
|
177 |
+
{
|
178 |
+
return (boolean)Mage::getStoreConfig('markdown/remarked/enable');
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* if json is invalid returns false
|
183 |
+
*
|
184 |
+
* @return string|boolean
|
185 |
+
*/
|
186 |
+
public function getReMarkedConfig()
|
187 |
+
{
|
188 |
+
return $this->_getJsonConfig('remarked');
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* @param $imageUrl
|
193 |
+
*
|
194 |
+
* @return string
|
195 |
+
*/
|
196 |
+
public function getTemplateMediaUrl($imageUrl)
|
197 |
+
{
|
198 |
+
return sprintf('{{media url="%s"}}', $imageUrl);
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* @param $content
|
203 |
+
*
|
204 |
+
* @return mixed
|
205 |
+
*/
|
206 |
+
public function renderTemplateMediaUrl($content)
|
207 |
+
{
|
208 |
+
return preg_replace('~\{\{media\s+url="([^"]+)"\s*\}\}~i', Mage::getBaseUrl('media') . '\\1', $content);
|
209 |
+
}
|
210 |
+
|
211 |
+
/**
|
212 |
+
* @return array
|
213 |
+
*/
|
214 |
+
public function getAllowedLayoutHandles()
|
215 |
+
{
|
216 |
+
$handles = array(
|
217 |
+
'editor' => 1,
|
218 |
+
'adminhtml_cms_block_edit' => 1,
|
219 |
+
'adminhtml_cms_page_edit' => 1,
|
220 |
+
'adminhtml_system_email_template_edit' => 1,
|
221 |
+
'adminhtml_catalog_product_edit' => 1,
|
222 |
+
'adminhtml_catalog_category_edit' => 1,
|
223 |
+
);
|
224 |
+
|
225 |
+
$customHandles = trim((string)Mage::getStoreConfig('markdown/markdown/custom_layout_handles'));
|
226 |
+
if (!empty($customHandles)) {
|
227 |
+
$customHandles = preg_split('~\s+~', $customHandles, -1, PREG_SPLIT_NO_EMPTY);
|
228 |
+
$customHandles = array_flip($customHandles);
|
229 |
+
$handles = array_merge($handles, $customHandles);
|
230 |
}
|
231 |
+
return $handles;
|
232 |
}
|
233 |
}
|
app/code/community/SchumacherFM/Markdown/Model/Editor/Config.php
DELETED
@@ -1,85 +0,0 @@
|
|
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_Editor_Config
|
9 |
-
{
|
10 |
-
/**
|
11 |
-
* Prepare variable wysiwyg config
|
12 |
-
*
|
13 |
-
* @param Varien_Object $config
|
14 |
-
*
|
15 |
-
* @return array
|
16 |
-
*/
|
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 |
-
)
|
41 |
-
),
|
42 |
-
array(
|
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 |
-
),
|
62 |
-
);
|
63 |
-
|
64 |
-
if (Mage::helper('markdown')->isMarkdownExtra()) {
|
65 |
-
$variableWysiwygPlugin[] = array(
|
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 |
-
)
|
77 |
-
);
|
78 |
-
}
|
79 |
-
|
80 |
-
$configPlugins = $config->getData('plugins');
|
81 |
-
$variableConfig['plugins'] = array_merge($configPlugins, $variableWysiwygPlugin);
|
82 |
-
return $variableConfig;
|
83 |
-
}
|
84 |
-
|
85 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/code/community/SchumacherFM/Markdown/Model/Editor/Observer.php
CHANGED
@@ -7,25 +7,6 @@
|
|
7 |
*/
|
8 |
class SchumacherFM_Markdown_Model_Editor_Observer
|
9 |
{
|
10 |
-
/**
|
11 |
-
* Add markdown wysiwyg plugin config
|
12 |
-
*
|
13 |
-
* @param Varien_Event_Observer $observer
|
14 |
-
*
|
15 |
-
* @return SchumacherFM_Markdown_Model_Editor_Observer
|
16 |
-
*/
|
17 |
-
public function prepareWysiwygPluginConfig(Varien_Event_Observer $observer)
|
18 |
-
{
|
19 |
-
if (Mage::helper('markdown')->isDisabled()) {
|
20 |
-
return null;
|
21 |
-
}
|
22 |
-
|
23 |
-
$config = $observer->getEvent()->getConfig();
|
24 |
-
$settings = Mage::getModel('markdown/editor_config')->getWysiwygPluginSettings($config);
|
25 |
-
$config->addData($settings);
|
26 |
-
return $this;
|
27 |
-
}
|
28 |
-
|
29 |
/**
|
30 |
* is Markdown is enabled then disable completely the wysiwyg editor
|
31 |
*
|
@@ -43,4 +24,4 @@ class SchumacherFM_Markdown_Model_Editor_Observer
|
|
43 |
$configurationModel->saveConfig('cms/wysiwyg/enabled', $isEnabled ? 'disabled' : 'enabled');
|
44 |
}
|
45 |
}
|
46 |
-
}
|
7 |
*/
|
8 |
class SchumacherFM_Markdown_Model_Editor_Observer
|
9 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
/**
|
11 |
* is Markdown is enabled then disable completely the wysiwyg editor
|
12 |
*
|
24 |
$configurationModel->saveConfig('cms/wysiwyg/enabled', $isEnabled ? 'disabled' : 'enabled');
|
25 |
}
|
26 |
}
|
27 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Markdown/Abstract.php
CHANGED
@@ -23,10 +23,11 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
23 |
/**
|
24 |
* @var SchumacherFM_Markdown_Model_Michelf_Markdown
|
25 |
*/
|
26 |
-
protected $_renderer =
|
27 |
|
28 |
protected $_options = array(
|
29 |
'force' => FALSE,
|
|
|
30 |
'protectMagento' => TRUE,
|
31 |
);
|
32 |
|
@@ -44,7 +45,7 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
44 |
*/
|
45 |
public final function getRenderer()
|
46 |
{
|
47 |
-
if ($this->_renderer !==
|
48 |
return $this->_renderer;
|
49 |
}
|
50 |
|
@@ -60,7 +61,7 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
60 |
*/
|
61 |
protected function _getIsExtraRenderer()
|
62 |
{
|
63 |
-
return Mage::helper('markdown')->isMarkdownExtra();
|
64 |
}
|
65 |
|
66 |
/**
|
@@ -80,9 +81,9 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
80 |
*
|
81 |
* @return $this
|
82 |
*/
|
83 |
-
public function setOptions(array $options =
|
84 |
{
|
85 |
-
$this->_options = $options;
|
86 |
return $this;
|
87 |
}
|
88 |
|
@@ -105,9 +106,10 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
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;
|
111 |
|
112 |
if (!$this->_isMarkdown() && $force === FALSE) {
|
113 |
return $this->_currentRenderedText;
|
@@ -123,6 +125,7 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
123 |
if ($protectMagento === TRUE) {
|
124 |
$this->_preserveMagentoVariablesDecode();
|
125 |
}
|
|
|
126 |
return $this->_currentRenderedText;
|
127 |
}
|
128 |
|
@@ -133,7 +136,11 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
133 |
*/
|
134 |
protected function _removeMarkdownTag()
|
135 |
{
|
136 |
-
|
|
|
|
|
|
|
|
|
137 |
return $this;
|
138 |
}
|
139 |
|
@@ -178,8 +185,16 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
178 |
*/
|
179 |
private function _isMarkdown()
|
180 |
{
|
181 |
-
|
182 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
183 |
}
|
184 |
|
185 |
/**
|
@@ -191,5 +206,4 @@ abstract class SchumacherFM_Markdown_Model_Markdown_Abstract
|
|
191 |
{
|
192 |
return strpos($text, $this->_tag) !== FALSE;
|
193 |
}
|
194 |
-
|
195 |
}
|
23 |
/**
|
24 |
* @var SchumacherFM_Markdown_Model_Michelf_Markdown
|
25 |
*/
|
26 |
+
protected $_renderer = NULL;
|
27 |
|
28 |
protected $_options = array(
|
29 |
'force' => FALSE,
|
30 |
+
'extra' => FALSE,
|
31 |
'protectMagento' => TRUE,
|
32 |
);
|
33 |
|
45 |
*/
|
46 |
public final function getRenderer()
|
47 |
{
|
48 |
+
if ($this->_renderer !== NULL) {
|
49 |
return $this->_renderer;
|
50 |
}
|
51 |
|
61 |
*/
|
62 |
protected function _getIsExtraRenderer()
|
63 |
{
|
64 |
+
return Mage::helper('markdown')->isMarkdownExtra() || $this->_options['extra'] === TRUE;
|
65 |
}
|
66 |
|
67 |
/**
|
81 |
*
|
82 |
* @return $this
|
83 |
*/
|
84 |
+
public function setOptions(array $options = NULL)
|
85 |
{
|
86 |
+
$this->_options = array_merge($this->_options, $options);
|
87 |
return $this;
|
88 |
}
|
89 |
|
106 |
*/
|
107 |
protected function _renderMarkdown($text)
|
108 |
{
|
109 |
+
Varien_Profiler::start('renderMarkdown');
|
110 |
$force = isset($this->_options['force']) && $this->_options['force'] === TRUE;
|
111 |
$protectMagento = isset($this->_options['protectMagento']) && $this->_options['protectMagento'] === TRUE;
|
112 |
+
$this->_currentRenderedText = $text;
|
113 |
|
114 |
if (!$this->_isMarkdown() && $force === FALSE) {
|
115 |
return $this->_currentRenderedText;
|
125 |
if ($protectMagento === TRUE) {
|
126 |
$this->_preserveMagentoVariablesDecode();
|
127 |
}
|
128 |
+
Varien_Profiler::stop('renderMarkdown');
|
129 |
return $this->_currentRenderedText;
|
130 |
}
|
131 |
|
136 |
*/
|
137 |
protected function _removeMarkdownTag()
|
138 |
{
|
139 |
+
if (empty($this->_tag) === TRUE) {
|
140 |
+
return $this;
|
141 |
+
}
|
142 |
+
|
143 |
+
$this->_currentRenderedText = trim(str_replace($this->_tag, '', $this->_currentRenderedText));
|
144 |
return $this;
|
145 |
}
|
146 |
|
185 |
*/
|
186 |
private function _isMarkdown()
|
187 |
{
|
188 |
+
if (empty($this->_currentRenderedText) === TRUE) {
|
189 |
+
return FALSE;
|
190 |
+
}
|
191 |
+
if (empty($this->_tag) === TRUE) {
|
192 |
+
return TRUE;
|
193 |
+
}
|
194 |
+
if (strpos($this->_currentRenderedText, $this->_tag) === FALSE) {
|
195 |
+
return FALSE;
|
196 |
+
}
|
197 |
+
return TRUE;
|
198 |
}
|
199 |
|
200 |
/**
|
206 |
{
|
207 |
return strpos($text, $this->_tag) !== FALSE;
|
208 |
}
|
|
|
209 |
}
|
app/code/community/SchumacherFM/Markdown/Model/Markdown/Observer.php
CHANGED
@@ -10,7 +10,7 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
10 |
/**
|
11 |
* @var null
|
12 |
*/
|
13 |
-
protected $_currentObserverMethod =
|
14 |
|
15 |
/**
|
16 |
* @var array
|
@@ -27,7 +27,7 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
27 |
{
|
28 |
$isset = isset($this->_mdExtraUsage[$this->_currentObserverMethod]);
|
29 |
if (!$isset) {
|
30 |
-
return
|
31 |
}
|
32 |
|
33 |
return Mage::helper('markdown')->isMarkdownExtra($this->_mdExtraUsage[$this->_currentObserverMethod]);
|
@@ -40,7 +40,7 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
40 |
{
|
41 |
$globalExtra = parent::_getIsExtraRenderer();
|
42 |
$_observerMdExtraUsage = $this->_isObserverMdExtraUsage();
|
43 |
-
if ($_observerMdExtraUsage ===
|
44 |
return $globalExtra;
|
45 |
}
|
46 |
return $_observerMdExtraUsage;
|
@@ -55,17 +55,22 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
55 |
{
|
56 |
$this->_currentObserverMethod = __FUNCTION__;
|
57 |
if ($this->_isDisabled) {
|
58 |
-
return
|
59 |
}
|
60 |
|
61 |
$object = $observer->getEvent()->getObject();
|
62 |
if (!$object instanceof Mage_Core_Model_Email_Template) {
|
63 |
-
return
|
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);
|
@@ -81,13 +86,13 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
81 |
{
|
82 |
$this->_currentObserverMethod = __FUNCTION__;
|
83 |
if ($this->_isDisabled) {
|
84 |
-
return
|
85 |
}
|
86 |
|
87 |
/** @var Mage_Cms_Model_Page $page */
|
88 |
$page = $observer->getEvent()->getPage();
|
89 |
if (!$page instanceof Mage_Cms_Model_Page) {
|
90 |
-
return
|
91 |
}
|
92 |
$content = $this->_renderMarkdown($page->getContent());
|
93 |
$page->setContent($content);
|
@@ -104,14 +109,14 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
104 |
{
|
105 |
$this->_currentObserverMethod = __FUNCTION__;
|
106 |
if ($this->_isDisabled) {
|
107 |
-
return
|
108 |
}
|
109 |
|
110 |
/** @var Mage_Cms_Block_Block $page */
|
111 |
$block = $observer->getEvent()->getBlock();
|
112 |
|
113 |
if (!$this->_isAllowedBlock($block)) {
|
114 |
-
return
|
115 |
}
|
116 |
|
117 |
/** @var Varien_Object $transport */
|
@@ -128,7 +133,6 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
128 |
));
|
129 |
$html = $transport->getHtml();
|
130 |
$transport->setHtml($this->_renderMarkdown($html));
|
131 |
-
|
132 |
}
|
133 |
|
134 |
/**
|
@@ -140,5 +144,4 @@ class SchumacherFM_Markdown_Model_Markdown_Observer extends SchumacherFM_Markdow
|
|
140 |
{
|
141 |
return $block instanceof Mage_Cms_Block_Block || $block instanceof Mage_Cms_Block_Widget_Block;
|
142 |
}
|
143 |
-
|
144 |
}
|
10 |
/**
|
11 |
* @var null
|
12 |
*/
|
13 |
+
protected $_currentObserverMethod = NULL;
|
14 |
|
15 |
/**
|
16 |
* @var array
|
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]);
|
40 |
{
|
41 |
$globalExtra = parent::_getIsExtraRenderer();
|
42 |
$_observerMdExtraUsage = $this->_isObserverMdExtraUsage();
|
43 |
+
if ($_observerMdExtraUsage === NULL) {
|
44 |
return $globalExtra;
|
45 |
}
|
46 |
return $_observerMdExtraUsage;
|
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 |
+
|
70 |
+
$this->setOptions(array(
|
71 |
+
'extra' => Mage::helper('markdown')->isMarkdownExtra('email')
|
72 |
+
));
|
73 |
+
|
74 |
$object->setData('template_text', $this->_renderMarkdown($template));
|
75 |
$css = Mage::helper('markdown')->getTransactionalEmailCSS();
|
76 |
$object->setData('template_styles', $css);
|
86 |
{
|
87 |
$this->_currentObserverMethod = __FUNCTION__;
|
88 |
if ($this->_isDisabled) {
|
89 |
+
return NULL;
|
90 |
}
|
91 |
|
92 |
/** @var Mage_Cms_Model_Page $page */
|
93 |
$page = $observer->getEvent()->getPage();
|
94 |
if (!$page instanceof Mage_Cms_Model_Page) {
|
95 |
+
return NULL;
|
96 |
}
|
97 |
$content = $this->_renderMarkdown($page->getContent());
|
98 |
$page->setContent($content);
|
109 |
{
|
110 |
$this->_currentObserverMethod = __FUNCTION__;
|
111 |
if ($this->_isDisabled) {
|
112 |
+
return NULL;
|
113 |
}
|
114 |
|
115 |
/** @var Mage_Cms_Block_Block $page */
|
116 |
$block = $observer->getEvent()->getBlock();
|
117 |
|
118 |
if (!$this->_isAllowedBlock($block)) {
|
119 |
+
return NULL;
|
120 |
}
|
121 |
|
122 |
/** @var Varien_Object $transport */
|
133 |
));
|
134 |
$html = $transport->getHtml();
|
135 |
$transport->setHtml($this->_renderMarkdown($html));
|
|
|
136 |
}
|
137 |
|
138 |
/**
|
144 |
{
|
145 |
return $block instanceof Mage_Cms_Block_Block || $block instanceof Mage_Cms_Block_Widget_Block;
|
146 |
}
|
|
|
147 |
}
|
app/code/community/SchumacherFM/Markdown/Model/Observer/Adminhtml/Block.php
ADDED
@@ -0,0 +1,318 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category SchumacherFM_Markdown
|
4 |
+
* @package Observer
|
5 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
+
* @copyright Copyright (c)
|
7 |
+
*/
|
8 |
+
class SchumacherFM_Markdown_Model_Observer_Adminhtml_Block
|
9 |
+
{
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var bool
|
13 |
+
*/
|
14 |
+
protected $_configInserted = FALSE;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var array
|
18 |
+
*/
|
19 |
+
protected $_afterElementHtml = array();
|
20 |
+
|
21 |
+
/**
|
22 |
+
* adminhtml_block_html_before
|
23 |
+
*
|
24 |
+
* @param Varien_Event_Observer $observer
|
25 |
+
*
|
26 |
+
* @return null
|
27 |
+
*/
|
28 |
+
public function alterTextareaBlockTemplate(Varien_Event_Observer $observer)
|
29 |
+
{
|
30 |
+
if (Mage::helper('markdown')->isDisabled()) {
|
31 |
+
return NULL;
|
32 |
+
}
|
33 |
+
|
34 |
+
/** @var $block Mage_Adminhtml_Block_Template */
|
35 |
+
$block = $observer->getEvent()->getBlock();
|
36 |
+
|
37 |
+
$isWidgetElement = $block instanceof Mage_Adminhtml_Block_Widget_Form_Renderer_Fieldset_Element;
|
38 |
+
$isCatalogElement = $block instanceof Mage_Adminhtml_Block_Catalog_Form_Renderer_Fieldset_Element;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* main reason for this layout handle thing is to avoid loading of lot of unused JS/CSS ...
|
42 |
+
*/
|
43 |
+
$isLayoutHandleAllowed = Mage::getSingleton('markdown/observer_adminhtml_layoutUpdate')->isAllowed();
|
44 |
+
|
45 |
+
if ($isWidgetElement || $isCatalogElement) {
|
46 |
+
/** @var Varien_Data_Form_Element_Abstract $element */
|
47 |
+
$element = $block->getElement();
|
48 |
+
|
49 |
+
$_isElementEditor = $this->_isElementEditor($element);
|
50 |
+
$_isCatalogElementAllowed = $this->_isCatalogElementAllowed($element);
|
51 |
+
$_isEmailTemplateElementAllowed = $this->_isEmailTemplateElementAllowed($element);
|
52 |
+
|
53 |
+
if ($_isElementEditor || $_isCatalogElementAllowed || $_isEmailTemplateElementAllowed) {
|
54 |
+
$method = $isLayoutHandleAllowed ? '_integrate' : '_addMarkdownHint';
|
55 |
+
$this->$method($element);
|
56 |
+
}
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
62 |
+
*
|
63 |
+
* @return $this
|
64 |
+
*/
|
65 |
+
protected function _addMarkdownHint(Varien_Data_Form_Element_Abstract $element)
|
66 |
+
{
|
67 |
+
$element->setData('after_element_html', '<small>' .
|
68 |
+
Mage::helper('markdown')->__('Markdown feature may be available here!')
|
69 |
+
. '</small>' . $element->getData('after_element_html'));
|
70 |
+
|
71 |
+
/* not sure if useful ...
|
72 |
+
$params = array(
|
73 |
+
'layoutHandle' => '@todo',
|
74 |
+
'returnUrl' => Mage::app()->getRequest()->getRequestUri(),
|
75 |
+
);
|
76 |
+
$url = Mage::helper('markdown')->getAdminEnableUrl($params);
|
77 |
+
$element->setData('after_element_html', '<small><a href="' . $url . '">' .
|
78 |
+
Mage::helper('markdown')->__('Click to add Markdown feature!')
|
79 |
+
. '</a></small>');
|
80 |
+
*/
|
81 |
+
return $this;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
86 |
+
*
|
87 |
+
* @return $this
|
88 |
+
*/
|
89 |
+
protected function _integrate(Varien_Data_Form_Element_Abstract $element)
|
90 |
+
{
|
91 |
+
$uniqueEntityId = $this->_getUniqueEntityId($element);
|
92 |
+
$idPrefix = $element->getForm()->getHtmlIdPrefix();
|
93 |
+
$element->setId(str_replace($idPrefix, '', $element->getHtmlId()) . $uniqueEntityId);
|
94 |
+
|
95 |
+
// adds to every Element the MD buttons at the bottom of the textarea
|
96 |
+
return $this->_getMarkdownButtons($element)->_addEpicEditorHtml($element)->_mergeAfterElementHtml($element);
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
101 |
+
*
|
102 |
+
* @return $this
|
103 |
+
*/
|
104 |
+
protected function _mergeAfterElementHtml(Varien_Data_Form_Element_Abstract $element)
|
105 |
+
{
|
106 |
+
$this->_afterElementHtml[90] = $element->getData('after_element_html');
|
107 |
+
|
108 |
+
$config = array();
|
109 |
+
$config['dt'] = Mage::helper('markdown')->getDetectionTag(TRUE);
|
110 |
+
$config['fuu'] = Mage::helper('markdown')->getAdminFileUploadUrl(); // file upload url
|
111 |
+
|
112 |
+
/**
|
113 |
+
* when rendering via marked.js include that place holder ... if rendere via PHP replace {{media url...}}
|
114 |
+
* with the real image.
|
115 |
+
*/
|
116 |
+
$config['phi'] = Mage::getBaseUrl('media');
|
117 |
+
|
118 |
+
if ($this->_isMarkdownExtra($element)) {
|
119 |
+
$config['eru'] = Mage::helper('markdown')->getAdminRenderUrl(array('markdownExtra' => 1)); // extra renderer url
|
120 |
+
}
|
121 |
+
|
122 |
+
$config['eeloc'] = Mage::helper('markdown')->isEpicEditorLoadOnClick();
|
123 |
+
|
124 |
+
if (Mage::helper('markdown')->isReMarkedEnabled() === TRUE) {
|
125 |
+
$config['rmc'] = Mage::helper('markdown')->getReMarkedConfig();
|
126 |
+
}
|
127 |
+
|
128 |
+
if ($this->_configInserted === FALSE) {
|
129 |
+
$this->_afterElementHtml[1000] = '<div id="markdownGlobalConfig" data-config=\'' .
|
130 |
+
Zend_Json_Encoder::encode($config)
|
131 |
+
. '\' style="display:none;"></div>';
|
132 |
+
$this->_configInserted = TRUE;
|
133 |
+
}
|
134 |
+
|
135 |
+
ksort($this->_afterElementHtml);
|
136 |
+
$element->setData('after_element_html', implode(' ', $this->_afterElementHtml));
|
137 |
+
$this->_afterElementHtml = array();
|
138 |
+
$element->addClass('initFileReader');
|
139 |
+
return $this;
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
144 |
+
*
|
145 |
+
* @return $this
|
146 |
+
*/
|
147 |
+
protected function _addEpicEditorHtml(Varien_Data_Form_Element_Abstract $element)
|
148 |
+
{
|
149 |
+
if (!Mage::helper('markdown')->isEpicEditorEnabled()) {
|
150 |
+
return $this;
|
151 |
+
}
|
152 |
+
|
153 |
+
$id = $element->getHtmlId();
|
154 |
+
|
155 |
+
$element->addClass('initEpicEditor');
|
156 |
+
$this->_afterElementHtml[100] = '<div id="epiceditor_EE_' . $id . '"' . $this->_getEpicEditorHtmlConfig($element) . '></div>';
|
157 |
+
return $this;
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
162 |
+
*
|
163 |
+
* @return string
|
164 |
+
*/
|
165 |
+
protected function _getEpicEditorHtmlConfig(Varien_Data_Form_Element_Abstract $element)
|
166 |
+
{
|
167 |
+
$config = Mage::helper('markdown')->getEpicEditorConfig();
|
168 |
+
$dataConfig = '';
|
169 |
+
if ($config) {
|
170 |
+
$dataConfig = ' data-config=\'' . $config . '\'';
|
171 |
+
}
|
172 |
+
return $dataConfig;
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* this is mainly a work around for the category section because fields will
|
177 |
+
* be there loaded via ajax with the same id each time ... and that confuses me and
|
178 |
+
* Epic Editor 8-)
|
179 |
+
*
|
180 |
+
* @param Varien_Data_Form_Element_Abstract $parentElement
|
181 |
+
*
|
182 |
+
* @return string
|
183 |
+
*/
|
184 |
+
protected function _getUniqueEntityId(Varien_Data_Form_Element_Abstract $parentElement)
|
185 |
+
{
|
186 |
+
/** @var Varien_Data_Form_Element_Collection $elements */
|
187 |
+
$elements = $parentElement->getForm()->getElements();
|
188 |
+
|
189 |
+
$idString = '';
|
190 |
+
foreach ($elements as $fieldSet) {
|
191 |
+
/** @var Varien_Data_Form_Element_Fieldset $fieldSet */
|
192 |
+
$sortedElements = $fieldSet->getSortedElements();
|
193 |
+
foreach ($sortedElements as $sortedElement) {
|
194 |
+
/** @var $sortedElement Varien_Data_Form_Element_Abstract */
|
195 |
+
if (stristr($sortedElement->getName(), 'id') !== FALSE) {
|
196 |
+
$idString .= $sortedElement->getValue();
|
197 |
+
}
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
// prevent trouble with strange values due to localStorage ...
|
202 |
+
$secretKey = Mage::getModel('adminhtml/url')->getSecretKey();
|
203 |
+
$path = Mage::app()->getRequest()->getRequestUri();
|
204 |
+
$idString .= '_' . md5(str_replace($secretKey, '', $path));
|
205 |
+
|
206 |
+
// we could also use here md5 but it want to see the values.
|
207 |
+
return preg_replace('~[^a-z0-9_\-]+~i', '', $idString);
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
212 |
+
*
|
213 |
+
* @return bool
|
214 |
+
*/
|
215 |
+
protected function _isEmailTemplateElementAllowed(Varien_Data_Form_Element_Abstract $element)
|
216 |
+
{
|
217 |
+
$trueOne = $element instanceof Varien_Data_Form_Element_Textarea;
|
218 |
+
$trueTwo = stristr($element->getHtmlId(), 'template_text') !== FALSE;
|
219 |
+
return $trueOne && $trueTwo;
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
224 |
+
*
|
225 |
+
* @return bool
|
226 |
+
*/
|
227 |
+
protected function _isCatalogElementAllowed(Varien_Data_Form_Element_Abstract $element)
|
228 |
+
{
|
229 |
+
$isTextArea = $element instanceof Mage_Adminhtml_Block_Catalog_Helper_Form_Wysiwyg;
|
230 |
+
$isDescription = stristr($element->getName(), 'description') !== FALSE && stristr($element->getName(), 'meta') === FALSE;
|
231 |
+
return $isDescription && $isTextArea;
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
236 |
+
*
|
237 |
+
* @return bool
|
238 |
+
*/
|
239 |
+
protected function _isElementEditor(Varien_Data_Form_Element_Abstract $element)
|
240 |
+
{
|
241 |
+
return $element instanceof Varien_Data_Form_Element_Editor;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* checks if md extra is enabled
|
246 |
+
*
|
247 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
248 |
+
*
|
249 |
+
* @return bool
|
250 |
+
*/
|
251 |
+
protected function _isMarkdownExtra(Varien_Data_Form_Element_Abstract $element)
|
252 |
+
{
|
253 |
+
$_isEmailTemplateElementAllowed = $this->_isEmailTemplateElementAllowed($element);
|
254 |
+
|
255 |
+
return Mage::helper('markdown')->isMarkdownExtra() ||
|
256 |
+
(Mage::helper('markdown')->isMarkdownExtra('email') && $_isEmailTemplateElementAllowed);
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* @param Varien_Data_Form_Element_Abstract $element
|
261 |
+
*/
|
262 |
+
protected function _getMarkdownButtons(Varien_Data_Form_Element_Abstract $element)
|
263 |
+
{
|
264 |
+
$htmlId = $element->getHtmlId();
|
265 |
+
|
266 |
+
if (Mage::helper('markdown')->getDetectionTag() !== '') {
|
267 |
+
$this->_afterElementHtml[200] = Mage::getSingleton('core/layout')
|
268 |
+
->createBlock('adminhtml/widget_button', '', array(
|
269 |
+
'label' => Mage::helper('markdown')->__('[M↓] enable'),
|
270 |
+
'type' => 'button',
|
271 |
+
'onclick' => 'toggleMarkdown(\'' . $htmlId . '\');'
|
272 |
+
))->toHtml();
|
273 |
+
}
|
274 |
+
|
275 |
+
$this->_afterElementHtml[210] = Mage::getSingleton('core/layout')
|
276 |
+
->createBlock('adminhtml/widget_button', '', array(
|
277 |
+
'label' => Mage::helper('markdown')->__('[M↓] Source'),
|
278 |
+
'type' => 'button',
|
279 |
+
'title' => Mage::helper('markdown')->__('View generated HTML source code'),
|
280 |
+
'onclick' => 'toggleMarkdownSource(this,\'' . $htmlId . '\');'
|
281 |
+
))->toHtml();
|
282 |
+
|
283 |
+
$this->_afterElementHtml[300] = Mage::getSingleton('core/layout')
|
284 |
+
->createBlock('adminhtml/widget_button', '', array(
|
285 |
+
'label' => Mage::helper('markdown')->__('[M↓] Syntax'),
|
286 |
+
'type' => 'button',
|
287 |
+
'onclick' => 'mdExternalUrl(\'' . Mage::helper('markdown')->getCheatSheetUrl() . '\');'
|
288 |
+
))->toHtml();
|
289 |
+
|
290 |
+
if ($this->_isMarkdownExtra($element)) {
|
291 |
+
$this->_afterElementHtml[400] = Mage::getSingleton('core/layout')
|
292 |
+
->createBlock('adminhtml/widget_button', '', array(
|
293 |
+
'label' => Mage::helper('markdown')->__('[M↓] Extra Syntax'),
|
294 |
+
'type' => 'button',
|
295 |
+
'onclick' => 'mdExternalUrl(\'' . SchumacherFM_Markdown_Helper_Data::URL_MD_EXTRA_SYNTAX . '\');'
|
296 |
+
))->toHtml();
|
297 |
+
}
|
298 |
+
|
299 |
+
if (Mage::helper('markdown')->isEpicEditorEnabled()) {
|
300 |
+
$this->_afterElementHtml[500] = Mage::getSingleton('core/layout')
|
301 |
+
->createBlock('adminhtml/widget_button', '', array(
|
302 |
+
'label' => Mage::helper('markdown')->__('EpicEditor'),
|
303 |
+
'type' => 'button',
|
304 |
+
'onclick' => 'toggleEpicEditor(this,\'' . $htmlId . '\');'
|
305 |
+
))->toHtml();
|
306 |
+
}
|
307 |
+
|
308 |
+
if (Mage::helper('markdown')->isReMarkedEnabled() === TRUE) {
|
309 |
+
$this->_afterElementHtml[600] = Mage::getSingleton('core/layout')
|
310 |
+
->createBlock('adminhtml/widget_button', '', array(
|
311 |
+
'label' => Mage::helper('markdown')->__('HTML2[M↓]'),
|
312 |
+
'type' => 'button',
|
313 |
+
'onclick' => 'htmlToMarkDown(this,\'' . $htmlId . '\');'
|
314 |
+
))->toHtml();
|
315 |
+
}
|
316 |
+
return $this;
|
317 |
+
}
|
318 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Observer/Adminhtml/EpicEditor.php
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category SchumacherFM_Markdown
|
4 |
+
* @package Observer
|
5 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
+
* @copyright Copyright (c)
|
7 |
+
*
|
8 |
+
* avoiding to load files on every page in the adminhtml area.
|
9 |
+
*/
|
10 |
+
class SchumacherFM_Markdown_Model_Observer_Adminhtml_EpicEditor
|
11 |
+
{
|
12 |
+
/**
|
13 |
+
*
|
14 |
+
* @var array
|
15 |
+
*/
|
16 |
+
protected $_epicEditorFiles = array(
|
17 |
+
'js' => array(
|
18 |
+
'markdown/adminhtml/epiceditor.js',
|
19 |
+
'markdown/adminhtml/highlight.pack.js',
|
20 |
+
),
|
21 |
+
);
|
22 |
+
|
23 |
+
/**
|
24 |
+
* adminhtml_block_html_before
|
25 |
+
*
|
26 |
+
* @param Varien_Event_Observer $observer
|
27 |
+
*
|
28 |
+
* @return null
|
29 |
+
*/
|
30 |
+
public function injectEpicEditor(Varien_Event_Observer $observer)
|
31 |
+
{
|
32 |
+
if (Mage::helper('markdown')->isDisabled() || !Mage::helper('markdown')->isEpicEditorEnabled()) {
|
33 |
+
return NULL;
|
34 |
+
}
|
35 |
+
|
36 |
+
/** @var $block Mage_Adminhtml_Block_Page */
|
37 |
+
$block = $observer->getEvent()->getBlock();
|
38 |
+
|
39 |
+
if ($this->_isAllowedBlock($block) === FALSE) {
|
40 |
+
return NULL;
|
41 |
+
}
|
42 |
+
|
43 |
+
/** @var Mage_Adminhtml_Block_Page_Head $headBlock */
|
44 |
+
$headBlock = $block->getLayout()->getBlock('head');
|
45 |
+
|
46 |
+
if (isset($this->_epicEditorFiles['js'])) {
|
47 |
+
foreach ($this->_epicEditorFiles['js'] as $js) {
|
48 |
+
$headBlock->addJs($js);
|
49 |
+
}
|
50 |
+
}
|
51 |
+
if (isset($this->_epicEditorFiles['css'])) {
|
52 |
+
foreach ($this->_epicEditorFiles['css'] as $css) {
|
53 |
+
$headBlock->addCss($css);
|
54 |
+
}
|
55 |
+
}
|
56 |
+
return NULL;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @param Mage_Core_Block_Abstract $block
|
61 |
+
*
|
62 |
+
* @return bool
|
63 |
+
*/
|
64 |
+
protected function _isAllowedBlock(Mage_Core_Block_Abstract $block)
|
65 |
+
{
|
66 |
+
$isPage = $block instanceof Mage_Adminhtml_Block_Page;
|
67 |
+
$isLayoutHandleAllowed = Mage::getSingleton('markdown/observer_adminhtml_layoutUpdate')->isAllowed();
|
68 |
+
return $isPage && $isLayoutHandleAllowed;
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* @param array $epicEditorFiles
|
73 |
+
*/
|
74 |
+
public function setEpicEditorFiles($epicEditorFiles)
|
75 |
+
{
|
76 |
+
$this->_epicEditorFiles = $epicEditorFiles;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* @return array
|
81 |
+
*/
|
82 |
+
public function getEpicEditorFiles()
|
83 |
+
{
|
84 |
+
return $this->_epicEditorFiles;
|
85 |
+
}
|
86 |
+
|
87 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Observer/Adminhtml/LayoutUpdate.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @category SchumacherFM_Markdown
|
4 |
+
* @package Observer
|
5 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
+
* @copyright Copyright (c)
|
7 |
+
*/
|
8 |
+
class SchumacherFM_Markdown_Model_Observer_Adminhtml_LayoutUpdate
|
9 |
+
{
|
10 |
+
|
11 |
+
protected $_isAllowedFlag = FALSE;
|
12 |
+
|
13 |
+
/**
|
14 |
+
* adminhtml_block_html_before
|
15 |
+
*
|
16 |
+
* @param Varien_Event_Observer $observer
|
17 |
+
*
|
18 |
+
* @return null
|
19 |
+
*/
|
20 |
+
public function injectMarkdownFiles(Varien_Event_Observer $observer)
|
21 |
+
{
|
22 |
+
if (Mage::helper('markdown')->isDisabled()) {
|
23 |
+
return NULL;
|
24 |
+
}
|
25 |
+
|
26 |
+
/** @var Mage_Core_Model_Layout $layout */
|
27 |
+
$layout = $observer->getEvent()->getLayout();
|
28 |
+
|
29 |
+
/** @var Mage_Core_Model_Layout_Update $update */
|
30 |
+
$update = $layout->getUpdate();
|
31 |
+
|
32 |
+
if ($this->_isAllowed($update)) {
|
33 |
+
$update->addHandle('MARKDOWN_HEADER');
|
34 |
+
}
|
35 |
+
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @param Mage_Core_Model_Layout_Update $update
|
40 |
+
*
|
41 |
+
* @return bool
|
42 |
+
*/
|
43 |
+
protected function _isAllowed(Mage_Core_Model_Layout_Update $update)
|
44 |
+
{
|
45 |
+
|
46 |
+
$handles = $update->getHandles();
|
47 |
+
$allowedHandles = Mage::helper('markdown')->getAllowedLayoutHandles();
|
48 |
+
|
49 |
+
foreach ($handles as $handle) {
|
50 |
+
if (isset($allowedHandles[$handle])) {
|
51 |
+
$this->_isAllowedFlag = TRUE;
|
52 |
+
break;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
return $this->_isAllowedFlag;
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* @return bool
|
60 |
+
*/
|
61 |
+
public function isAllowed()
|
62 |
+
{
|
63 |
+
return $this->_isAllowedFlag;
|
64 |
+
}
|
65 |
+
|
66 |
+
}
|
app/code/community/SchumacherFM/Markdown/Model/Observer/AdminhtmlBlock.php
DELETED
@@ -1,150 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* @category SchumacherFM_Markdown
|
4 |
-
* @package Helper
|
5 |
-
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
6 |
-
* @copyright Copyright (c)
|
7 |
-
*/
|
8 |
-
class SchumacherFM_Markdown_Model_Observer_AdminhtmlBlock
|
9 |
-
{
|
10 |
-
/**
|
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 |
-
{
|
19 |
-
if (Mage::helper('markdown')->isDisabled()) {
|
20 |
-
return null;
|
21 |
-
}
|
22 |
-
|
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 |
-
}
|
47 |
-
}
|
48 |
-
|
49 |
-
/**
|
50 |
-
* @param Varien_Data_Form_Element_Abstract $element
|
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;
|
70 |
-
return $isDescription && $isTextarea;
|
71 |
-
}
|
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
CHANGED
@@ -8,30 +8,106 @@
|
|
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
|
|
|
|
|
17 |
if (!$this->getRequest()->isPost() || empty($content)) {
|
18 |
-
return $this->_setReturn();
|
19 |
}
|
20 |
|
21 |
-
$md = Mage::helper('markdown')->render($content
|
22 |
-
|
|
|
23 |
|
|
|
|
|
|
|
24 |
}
|
25 |
|
26 |
/**
|
27 |
* @param string $string
|
|
|
28 |
*
|
29 |
* @return $this
|
30 |
*/
|
31 |
-
protected function _setReturn($string = '')
|
32 |
{
|
33 |
-
|
|
|
|
|
|
|
34 |
return $this;
|
35 |
}
|
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
}
|
8 |
class SchumacherFM_Markdown_Adminhtml_MarkdownController extends Mage_Adminhtml_Controller_Action
|
9 |
{
|
10 |
|
11 |
+
/**
|
12 |
+
* @see Adminhtml/Block.php --> _addMarkdownHint()
|
13 |
+
* not sure if useful
|
14 |
+
*/
|
15 |
+
public function enableAction(){
|
16 |
+
|
17 |
+
}
|
18 |
+
|
19 |
/**
|
20 |
* @return void
|
21 |
*/
|
22 |
public function renderAction()
|
23 |
{
|
24 |
+
$content = $this->getRequest()->getParam('content', NULL);
|
25 |
+
$markdownExtra = ((int)$this->getRequest()->getParam('markdownExtra', 0)) === 1;
|
26 |
+
|
27 |
if (!$this->getRequest()->isPost() || empty($content)) {
|
28 |
+
return $this->_setReturn('Incorrect Request');
|
29 |
}
|
30 |
|
31 |
+
$md = Mage::helper('markdown')->render($content, array(
|
32 |
+
'extra' => $markdownExtra
|
33 |
+
));
|
34 |
|
35 |
+
$md = Mage::helper('markdown')->renderTemplateMediaUrl($md);
|
36 |
+
|
37 |
+
return $this->_setReturn($md);
|
38 |
}
|
39 |
|
40 |
/**
|
41 |
* @param string $string
|
42 |
+
* @param bool $jsonEncode
|
43 |
*
|
44 |
* @return $this
|
45 |
*/
|
46 |
+
protected function _setReturn($string = '', $jsonEncode = FALSE)
|
47 |
{
|
48 |
+
if (TRUE === $jsonEncode) {
|
49 |
+
$this->getResponse()->setHeader('Content-type', 'application/json', TRUE);
|
50 |
+
}
|
51 |
+
$this->getResponse()->setBody($jsonEncode ? Zend_Json_Encoder::encode($string) : $string);
|
52 |
return $this;
|
53 |
}
|
54 |
|
55 |
+
/**
|
56 |
+
* @todo better subdirectories
|
57 |
+
* saves a file in the dir: media/wysiwyg/markdown/....
|
58 |
+
*
|
59 |
+
* @return $this
|
60 |
+
*/
|
61 |
+
public function fileUploadAction()
|
62 |
+
{
|
63 |
+
|
64 |
+
$return = array(
|
65 |
+
'err' => TRUE,
|
66 |
+
'msg' => 'An error occurred.',
|
67 |
+
'fileUrl' => ''
|
68 |
+
);
|
69 |
+
$binaryData = base64_decode($this->getRequest()->getParam('binaryData', ''));
|
70 |
+
$file = json_decode($this->getRequest()->getParam('file', '[]'), TRUE);
|
71 |
+
$fileName = preg_replace('~[^\w\.]+~i', '', isset($file['name']) ? $file['name'] : '');
|
72 |
+
|
73 |
+
if (empty($fileName) || empty($binaryData) || empty($file)) {
|
74 |
+
$return['msg'] = 'Either fileName or binaryData or file is empty ...';
|
75 |
+
return $this->_setReturn($return, TRUE);
|
76 |
+
}
|
77 |
+
|
78 |
+
$savePath = $this->_getStorageRoot() . $this->_getStorageSubDirectory();
|
79 |
+
$io = new Varien_Io_File();
|
80 |
+
if ($io->checkAndCreateFolder($savePath)) {
|
81 |
+
$result = (int)file_put_contents($savePath . $fileName, $binaryData); // io->write will not work :-(
|
82 |
+
if ($result > 10) {
|
83 |
+
$return['err'] = FALSE;
|
84 |
+
$return['msg'] = '';
|
85 |
+
$return['fileUrl'] = Mage::helper('markdown')->getTemplateMediaUrl($this->_getStorageSubDirectory() . $fileName);
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
$this->_setReturn($return, TRUE);
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* @return mixed|string
|
94 |
+
*/
|
95 |
+
protected function _getStorageSubDirectory()
|
96 |
+
{
|
97 |
+
$userDir = Mage::getStoreConfig('markdown/file_reader/upload_dir');
|
98 |
+
if (empty($userDir)) {
|
99 |
+
$userDir = Mage_Cms_Model_Wysiwyg_Config::IMAGE_DIRECTORY . DS . 'markdown' . DS;
|
100 |
+
}
|
101 |
+
return $userDir;
|
102 |
+
}
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Images Storage root directory
|
106 |
+
*
|
107 |
+
* @return string
|
108 |
+
*/
|
109 |
+
protected function _getStorageRoot()
|
110 |
+
{
|
111 |
+
return Mage::getConfig()->getOptions()->getMediaDir() . DS;
|
112 |
+
}
|
113 |
}
|
app/code/community/SchumacherFM/Markdown/etc/adminhtml.xml
CHANGED
@@ -16,9 +16,9 @@
|
|
16 |
<children>
|
17 |
<config>
|
18 |
<children>
|
19 |
-
<
|
20 |
-
<title
|
21 |
-
</
|
22 |
</children>
|
23 |
</config>
|
24 |
</children>
|
16 |
<children>
|
17 |
<config>
|
18 |
<children>
|
19 |
+
<markdown translate="title" module="schumacherfm_markdown">
|
20 |
+
<title>Markdown [M↓]</title>
|
21 |
+
</markdown>
|
22 |
</children>
|
23 |
</config>
|
24 |
</children>
|
app/code/community/SchumacherFM/Markdown/etc/config.xml
CHANGED
@@ -1,8 +1,4 @@
|
|
1 |
-
<?xml version="1.0"
|
2 |
-
<!--* @category SchumacherFM_Markdown-->
|
3 |
-
<!--* @package etc-->
|
4 |
-
<!--* @author Cyrill at Schumacher dot fm / @SchumacherFM-->
|
5 |
-
<!--* @copyright Copyright (c)-->
|
6 |
<config>
|
7 |
<modules>
|
8 |
<SchumacherFM_Markdown>
|
@@ -97,20 +93,24 @@
|
|
97 |
</modules>
|
98 |
</translate>
|
99 |
<events>
|
100 |
-
<
|
101 |
<observers>
|
102 |
-
<
|
103 |
-
<class>markdown/
|
104 |
-
<method>
|
105 |
-
</
|
106 |
</observers>
|
107 |
-
</
|
108 |
<adminhtml_block_html_before>
|
109 |
<observers>
|
110 |
-
<
|
111 |
-
<class>markdown/
|
112 |
<method>alterTextareaBlockTemplate</method>
|
113 |
-
</
|
|
|
|
|
|
|
|
|
114 |
</observers>
|
115 |
</adminhtml_block_html_before>
|
116 |
<core_config_data_save_after>
|
@@ -124,14 +124,25 @@
|
|
124 |
</events>
|
125 |
</adminhtml>
|
126 |
<default>
|
127 |
-
<
|
128 |
<markdown>
|
129 |
<enable>1</enable>
|
130 |
-
<
|
131 |
-
<md_extra_email>0</md_extra_email>
|
132 |
<detection_tag>!#markdown</detection_tag>
|
133 |
</markdown>
|
134 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
</default>
|
136 |
<phpunit>
|
137 |
<suite>
|
1 |
+
<?xml version="1.0"?><!--* @category SchumacherFM_Markdown--><!--* @package etc--><!--* @author Cyrill at Schumacher dot fm / @SchumacherFM--><!--* @copyright Copyright (c)-->
|
|
|
|
|
|
|
|
|
2 |
<config>
|
3 |
<modules>
|
4 |
<SchumacherFM_Markdown>
|
93 |
</modules>
|
94 |
</translate>
|
95 |
<events>
|
96 |
+
<controller_action_layout_load_before>
|
97 |
<observers>
|
98 |
+
<markdown_controller_action_layout_load_before>
|
99 |
+
<class>markdown/observer_adminhtml_layoutUpdate</class>
|
100 |
+
<method>injectMarkdownFiles</method>
|
101 |
+
</markdown_controller_action_layout_load_before>
|
102 |
</observers>
|
103 |
+
</controller_action_layout_load_before>
|
104 |
<adminhtml_block_html_before>
|
105 |
<observers>
|
106 |
+
<markdown_adminhtml_block_html_before_textarea>
|
107 |
+
<class>markdown/observer_adminhtml_block</class>
|
108 |
<method>alterTextareaBlockTemplate</method>
|
109 |
+
</markdown_adminhtml_block_html_before_textarea>
|
110 |
+
<markdown_adminhtml_block_html_before_page>
|
111 |
+
<class>markdown/observer_adminhtml_epicEditor</class>
|
112 |
+
<method>injectEpicEditor</method>
|
113 |
+
</markdown_adminhtml_block_html_before_page>
|
114 |
</observers>
|
115 |
</adminhtml_block_html_before>
|
116 |
<core_config_data_save_after>
|
124 |
</events>
|
125 |
</adminhtml>
|
126 |
<default>
|
127 |
+
<markdown>
|
128 |
<markdown>
|
129 |
<enable>1</enable>
|
130 |
+
<cheatsheet>https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet</cheatsheet>
|
|
|
131 |
<detection_tag>!#markdown</detection_tag>
|
132 |
</markdown>
|
133 |
+
<markdown_extra>
|
134 |
+
<enable>0</enable>
|
135 |
+
<enable_email>0</enable_email>
|
136 |
+
</markdown_extra>
|
137 |
+
|
138 |
+
<epiceditor>
|
139 |
+
<enable>0</enable>
|
140 |
+
<load_on_click_textarea>0</load_on_click_textarea>
|
141 |
+
</epiceditor>
|
142 |
+
<remarked>
|
143 |
+
<enable>1</enable>
|
144 |
+
</remarked>
|
145 |
+
</markdown>
|
146 |
</default>
|
147 |
<phpunit>
|
148 |
<suite>
|
app/code/community/SchumacherFM/Markdown/etc/system.xml
CHANGED
@@ -1,5 +1,4 @@
|
|
1 |
-
<?xml version="1.0"
|
2 |
-
<!--
|
3 |
/**
|
4 |
* @category SchumacherFM
|
5 |
* @package SchumacherFM_Markdown
|
@@ -9,14 +8,15 @@
|
|
9 |
-->
|
10 |
<config>
|
11 |
<sections>
|
12 |
-
<
|
13 |
-
<label
|
14 |
-
<tab>
|
15 |
<frontend_type>text</frontend_type>
|
16 |
-
<sort_order>
|
17 |
<show_in_default>1</show_in_default>
|
18 |
<show_in_website>1</show_in_website>
|
19 |
<show_in_store>1</show_in_store>
|
|
|
20 |
<groups>
|
21 |
<markdown translate="label">
|
22 |
<label>Markdown [M↓]</label>
|
@@ -35,15 +35,17 @@
|
|
35 |
<show_in_website>1</show_in_website>
|
36 |
<show_in_store>1</show_in_store>
|
37 |
</enable>
|
38 |
-
<
|
39 |
-
<label>
|
40 |
-
<frontend_type>
|
41 |
-
<
|
42 |
-
<sort_order>20</sort_order>
|
43 |
<show_in_default>1</show_in_default>
|
44 |
<show_in_website>1</show_in_website>
|
45 |
<show_in_store>1</show_in_store>
|
46 |
-
|
|
|
|
|
|
|
47 |
<detection_tag translate="label">
|
48 |
<label>Markdown Detection Tag</label>
|
49 |
<frontend_type>text</frontend_type>
|
@@ -51,12 +53,45 @@
|
|
51 |
<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
|
55 |
-
|
56 |
-
|
57 |
</comment>
|
58 |
</detection_tag>
|
59 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
<label>Transactional email: Use Markdown Extra</label>
|
61 |
<frontend_type>select</frontend_type>
|
62 |
<source_model>adminhtml/system_config_source_yesno</source_model>
|
@@ -64,7 +99,7 @@
|
|
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 |
-
</
|
68 |
<te_md_css translate="label">
|
69 |
<label>Transactional email: Path to CSS file</label>
|
70 |
<frontend_type>text</frontend_type>
|
@@ -76,8 +111,104 @@
|
|
76 |
Will be included in the <style> tag in each email.]]></comment>
|
77 |
</te_md_css>
|
78 |
</fields>
|
79 |
-
</
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
</groups>
|
81 |
-
</
|
82 |
</sections>
|
83 |
</config>
|
1 |
+
<?xml version="1.0"?><!--
|
|
|
2 |
/**
|
3 |
* @category SchumacherFM
|
4 |
* @package SchumacherFM_Markdown
|
8 |
-->
|
9 |
<config>
|
10 |
<sections>
|
11 |
+
<markdown>
|
12 |
+
<label>Markdown [M↓]</label>
|
13 |
+
<tab>general</tab>
|
14 |
<frontend_type>text</frontend_type>
|
15 |
+
<sort_order>2001</sort_order>
|
16 |
<show_in_default>1</show_in_default>
|
17 |
<show_in_website>1</show_in_website>
|
18 |
<show_in_store>1</show_in_store>
|
19 |
+
|
20 |
<groups>
|
21 |
<markdown translate="label">
|
22 |
<label>Markdown [M↓]</label>
|
35 |
<show_in_website>1</show_in_website>
|
36 |
<show_in_store>1</show_in_store>
|
37 |
</enable>
|
38 |
+
<cheatsheet translate="label">
|
39 |
+
<label>Markdown Cheat Sheet URL</label>
|
40 |
+
<frontend_type>text</frontend_type>
|
41 |
+
<sort_order>15</sort_order>
|
|
|
42 |
<show_in_default>1</show_in_default>
|
43 |
<show_in_website>1</show_in_website>
|
44 |
<show_in_store>1</show_in_store>
|
45 |
+
<comment>Alternatives http://daringfireball.net/projects/markdown/syntax or
|
46 |
+
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet or your own page
|
47 |
+
</comment>
|
48 |
+
</cheatsheet>
|
49 |
<detection_tag translate="label">
|
50 |
<label>Markdown Detection Tag</label>
|
51 |
<frontend_type>text</frontend_type>
|
53 |
<show_in_default>1</show_in_default>
|
54 |
<show_in_website>1</show_in_website>
|
55 |
<show_in_store>1</show_in_store>
|
56 |
+
<comment>Every content field which contains markdown must have this tag included otherwise it will not be parsed.
|
57 |
+
This tag will of course be removed during parsing. If empty, every content is considered as markdown.
|
58 |
+
Only transactional emails which have the detection tag somewhere integrated will be rendered with markdown.
|
59 |
</comment>
|
60 |
</detection_tag>
|
61 |
+
<custom_layout_handles translate="label">
|
62 |
+
<label>Additional Layout Handles</label>
|
63 |
+
<frontend_type>textarea</frontend_type>
|
64 |
+
<sort_order>220</sort_order>
|
65 |
+
<show_in_default>1</show_in_default>
|
66 |
+
<show_in_website>1</show_in_website>
|
67 |
+
<show_in_store>1</show_in_store>
|
68 |
+
<comment>Expert Mode: Load Markdown feature and EpicEditor also via these custom layout handles.
|
69 |
+
A whitespace separated list. Q: Where can I find the name of a Layout Handle? A: View the class attribute
|
70 |
+
on the body tag. Most handles starts with adminhtml-... Replace the - with _. Full string is required.
|
71 |
+
</comment>
|
72 |
+
</custom_layout_handles>
|
73 |
+
|
74 |
+
</fields>
|
75 |
+
</markdown>
|
76 |
+
|
77 |
+
<markdown_extra translate="label">
|
78 |
+
<label>Markdown Extra</label>
|
79 |
+
<frontend_type>text</frontend_type>
|
80 |
+
<sort_order>60</sort_order>
|
81 |
+
<show_in_default>1</show_in_default>
|
82 |
+
<show_in_website>1</show_in_website>
|
83 |
+
<show_in_store>1</show_in_store>
|
84 |
+
<fields>
|
85 |
+
<enable translate="label">
|
86 |
+
<label>Use Markdown Extra</label>
|
87 |
+
<frontend_type>select</frontend_type>
|
88 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
89 |
+
<sort_order>20</sort_order>
|
90 |
+
<show_in_default>1</show_in_default>
|
91 |
+
<show_in_website>1</show_in_website>
|
92 |
+
<show_in_store>1</show_in_store>
|
93 |
+
</enable>
|
94 |
+
<enable_email translate="label">
|
95 |
<label>Transactional email: Use Markdown Extra</label>
|
96 |
<frontend_type>select</frontend_type>
|
97 |
<source_model>adminhtml/system_config_source_yesno</source_model>
|
99 |
<show_in_default>1</show_in_default>
|
100 |
<show_in_website>1</show_in_website>
|
101 |
<show_in_store>1</show_in_store>
|
102 |
+
</enable_email>
|
103 |
<te_md_css translate="label">
|
104 |
<label>Transactional email: Path to CSS file</label>
|
105 |
<frontend_type>text</frontend_type>
|
111 |
Will be included in the <style> tag in each email.]]></comment>
|
112 |
</te_md_css>
|
113 |
</fields>
|
114 |
+
</markdown_extra>
|
115 |
+
|
116 |
+
<file_reader translate="label">
|
117 |
+
<label>Drag'n'Drop File Upload</label>
|
118 |
+
<frontend_type>text</frontend_type>
|
119 |
+
<sort_order>70</sort_order>
|
120 |
+
<show_in_default>1</show_in_default>
|
121 |
+
<show_in_website>1</show_in_website>
|
122 |
+
<show_in_store>1</show_in_store>
|
123 |
+
<fields>
|
124 |
+
<upload_dir translate="label">
|
125 |
+
<label>Upload directory</label>
|
126 |
+
<frontend_type>text</frontend_type>
|
127 |
+
<sort_order>100</sort_order>
|
128 |
+
<show_in_default>1</show_in_default>
|
129 |
+
<show_in_website>1</show_in_website>
|
130 |
+
<show_in_store>1</show_in_store>
|
131 |
+
<comment><![CDATA[Directory must be writable for the webserver. If directory did not exists system will
|
132 |
+
attempt to create it recursively. Please add trailing slash.
|
133 |
+
Default upload directory is media/wysiwyg/markdown/]]></comment>
|
134 |
+
</upload_dir>
|
135 |
+
</fields>
|
136 |
+
</file_reader>
|
137 |
+
|
138 |
+
<epiceditor>
|
139 |
+
<label>EpicEditor</label>
|
140 |
+
<frontend_type>text</frontend_type>
|
141 |
+
<sort_order>100</sort_order>
|
142 |
+
<show_in_default>1</show_in_default>
|
143 |
+
<show_in_website>1</show_in_website>
|
144 |
+
<show_in_store>1</show_in_store>
|
145 |
+
<fields>
|
146 |
+
<enable translate="label">
|
147 |
+
<label>Enable EpicEditor</label>
|
148 |
+
<frontend_type>select</frontend_type>
|
149 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
150 |
+
<sort_order>200</sort_order>
|
151 |
+
<show_in_default>1</show_in_default>
|
152 |
+
<show_in_website>1</show_in_website>
|
153 |
+
<show_in_store>1</show_in_store>
|
154 |
+
<comment><![CDATA[Enables the awesome Markdown <a href="http://epiceditor.com" target="_blank">EpicEditor</a>.]]></comment>
|
155 |
+
</enable>
|
156 |
+
<load_on_click_textarea translate="label">
|
157 |
+
<label>Load EpicEditor on click</label>
|
158 |
+
<frontend_type>select</frontend_type>
|
159 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
160 |
+
<sort_order>210</sort_order>
|
161 |
+
<show_in_default>1</show_in_default>
|
162 |
+
<show_in_website>1</show_in_website>
|
163 |
+
<show_in_store>1</show_in_store>
|
164 |
+
<comment><![CDATA[Loads the EpicEditor only on the first click into a textarea field. After that loading
|
165 |
+
and unloading of the EpicEditor must be done via button. Hint: only enable that if you're not using
|
166 |
+
too much the Drag'n'Drop image upload.]]></comment>
|
167 |
+
</load_on_click_textarea>
|
168 |
+
<config translate="label">
|
169 |
+
<label>EpicEditor Config</label>
|
170 |
+
<frontend_type>textarea</frontend_type>
|
171 |
+
<sort_order>220</sort_order>
|
172 |
+
<show_in_default>1</show_in_default>
|
173 |
+
<show_in_website>1</show_in_website>
|
174 |
+
<show_in_store>1</show_in_store>
|
175 |
+
<comment>Expert Mode: A valid JSON object. Will be merged into the EpicEditor config.</comment>
|
176 |
+
</config>
|
177 |
+
</fields>
|
178 |
+
</epiceditor>
|
179 |
+
|
180 |
+
<remarked>
|
181 |
+
<label>HTML to Markdown</label>
|
182 |
+
<frontend_type>text</frontend_type>
|
183 |
+
<sort_order>150</sort_order>
|
184 |
+
<show_in_default>1</show_in_default>
|
185 |
+
<show_in_website>1</show_in_website>
|
186 |
+
<show_in_store>1</show_in_store>
|
187 |
+
<fields>
|
188 |
+
<enable translate="label">
|
189 |
+
<label>Enable Converter</label>
|
190 |
+
<frontend_type>select</frontend_type>
|
191 |
+
<source_model>adminhtml/system_config_source_yesno</source_model>
|
192 |
+
<sort_order>200</sort_order>
|
193 |
+
<show_in_default>1</show_in_default>
|
194 |
+
<show_in_website>1</show_in_website>
|
195 |
+
<show_in_store>1</show_in_store>
|
196 |
+
<comment><![CDATA[Enables the awesome reMarked.js HTML to Markdown converter]]></comment>
|
197 |
+
</enable>
|
198 |
+
<config translate="label">
|
199 |
+
<label>reMarked.js Config</label>
|
200 |
+
<frontend_type>textarea</frontend_type>
|
201 |
+
<sort_order>220</sort_order>
|
202 |
+
<show_in_default>1</show_in_default>
|
203 |
+
<show_in_website>1</show_in_website>
|
204 |
+
<show_in_store>1</show_in_store>
|
205 |
+
<comment><![CDATA[Expert Mode: A valid JSON object. Will be merged into the
|
206 |
+
<a href="https://github.com/leeoniya/reMarked.js" target="_blank">reMarked.js</a> config.]]></comment>
|
207 |
+
</config>
|
208 |
+
</fields>
|
209 |
+
</remarked>
|
210 |
+
|
211 |
</groups>
|
212 |
+
</markdown>
|
213 |
</sections>
|
214 |
</config>
|
app/design/adminhtml/default/default/layout/markdown.xml
CHANGED
@@ -1,16 +1,25 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<layout>
|
|
|
3 |
<MARKDOWN_HEADER>
|
4 |
<reference name="head">
|
5 |
-
<action method="addJs"
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>
|
1 |
<?xml version="1.0"?>
|
2 |
<layout>
|
3 |
+
<!--@see SchumacherFM_Markdown_Model_Observer_Adminhtml_LayoutUpdate-->
|
4 |
<MARKDOWN_HEADER>
|
5 |
<reference name="head">
|
6 |
+
<action method="addJs">
|
7 |
+
<script>markdown/adminhtml/reMarked.js</script>
|
8 |
+
</action>
|
9 |
+
<action method="addJs">
|
10 |
+
<script>markdown/adminhtml/marked.js</script>
|
11 |
+
</action>
|
12 |
+
<action method="addJs">
|
13 |
+
<script>markdown/adminhtml/filereader.js</script>
|
14 |
+
</action>
|
15 |
+
<action method="addJs">
|
16 |
+
<script>markdown/adminhtml/markdown.js</script>
|
17 |
+
</action>
|
18 |
+
<action method="addItem">
|
19 |
+
<type>skin_css</type>
|
20 |
+
<name>markdown/mdm.css</name>
|
21 |
+
<params/>
|
22 |
+
</action>
|
23 |
</reference>
|
24 |
</MARKDOWN_HEADER>
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
</layout>
|
js/mage/adminhtml/markdown.js
DELETED
@@ -1,144 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* @category SchumacherFM_Markdown
|
3 |
-
* @package JavaScript
|
4 |
-
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
5 |
-
* @copyright Copyright (c)
|
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
DELETED
@@ -1,1181 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* marked - a markdown parser
|
3 |
-
* Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
|
4 |
-
* https://github.com/chjj/marked
|
5 |
-
*/
|
6 |
-
|
7 |
-
;(function () {
|
8 |
-
|
9 |
-
/**
|
10 |
-
* Block-Level Grammar
|
11 |
-
*/
|
12 |
-
|
13 |
-
var block = {
|
14 |
-
newline: /^\n+/,
|
15 |
-
code: /^( {4}[^\n]+\n*)+/,
|
16 |
-
fences: noop,
|
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*$)/,
|
24 |
-
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
|
25 |
-
table: noop,
|
26 |
-
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
|
27 |
-
text: /^[^\n]+/
|
28 |
-
};
|
29 |
-
|
30 |
-
block.bullet = /(?:[*+-]|\d+\.)/;
|
31 |
-
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
|
32 |
-
block.item = replace(block.item, 'gm')
|
33 |
-
(/bull/g, block.bullet)
|
34 |
-
();
|
35 |
-
|
36 |
-
block.list = replace(block.list)
|
37 |
-
(/bull/g, block.bullet)
|
38 |
-
('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
|
39 |
-
();
|
40 |
-
|
41 |
-
block._tag = '(?!(?:'
|
42 |
-
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
|
43 |
-
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
|
44 |
-
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
|
45 |
-
|
46 |
-
block.html = replace(block.html)
|
47 |
-
('comment', /<!--[\s\S]*?-->/)
|
48 |
-
('closed', /<(tag)[\s\S]+?<\/\1>/)
|
49 |
-
('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
|
50 |
-
(/tag/g, block._tag)
|
51 |
-
();
|
52 |
-
|
53 |
-
block.paragraph = replace(block.paragraph)
|
54 |
-
('hr', block.hr)
|
55 |
-
('heading', block.heading)
|
56 |
-
('lheading', block.lheading)
|
57 |
-
('blockquote', block.blockquote)
|
58 |
-
('tag', '<' + block._tag)
|
59 |
-
('def', block.def)
|
60 |
-
();
|
61 |
-
|
62 |
-
/**
|
63 |
-
* Normal Block Grammar
|
64 |
-
*/
|
65 |
-
|
66 |
-
block.normal = merge({}, block);
|
67 |
-
|
68 |
-
/**
|
69 |
-
* GFM Block Grammar
|
70 |
-
*/
|
71 |
-
|
72 |
-
block.gfm = merge({}, block.normal, {
|
73 |
-
fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
|
74 |
-
paragraph: /^/
|
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 |
-
/**
|
84 |
-
* GFM + Tables Block Grammar
|
85 |
-
*/
|
86 |
-
|
87 |
-
block.tables = merge({}, block.gfm, {
|
88 |
-
nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
|
89 |
-
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
|
90 |
-
});
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Block Lexer
|
94 |
-
*/
|
95 |
-
|
96 |
-
function Lexer(options) {
|
97 |
-
this.tokens = [];
|
98 |
-
this.tokens.links = {};
|
99 |
-
this.options = options || marked.defaults;
|
100 |
-
this.rules = block.normal;
|
101 |
-
|
102 |
-
if (this.options.gfm) {
|
103 |
-
if (this.options.tables) {
|
104 |
-
this.rules = block.tables;
|
105 |
-
} else {
|
106 |
-
this.rules = block.gfm;
|
107 |
-
}
|
108 |
-
}
|
109 |
-
}
|
110 |
-
|
111 |
-
/**
|
112 |
-
* Expose Block Rules
|
113 |
-
*/
|
114 |
-
|
115 |
-
Lexer.rules = block;
|
116 |
-
|
117 |
-
/**
|
118 |
-
* Static Lex Method
|
119 |
-
*/
|
120 |
-
|
121 |
-
Lexer.lex = function (src, options) {
|
122 |
-
var lexer = new Lexer(options);
|
123 |
-
return lexer.lex(src);
|
124 |
-
};
|
125 |
-
|
126 |
-
/**
|
127 |
-
* Preprocessing
|
128 |
-
*/
|
129 |
-
|
130 |
-
Lexer.prototype.lex = function (src) {
|
131 |
-
src = src
|
132 |
-
.replace(/\r\n|\r/g, '\n')
|
133 |
-
.replace(/\t/g, ' ')
|
134 |
-
.replace(/\u00a0/g, ' ')
|
135 |
-
.replace(/\u2424/g, '\n');
|
136 |
-
|
137 |
-
return this.token(src, true);
|
138 |
-
};
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Lexing
|
142 |
-
*/
|
143 |
-
|
144 |
-
Lexer.prototype.token = function (src, top) {
|
145 |
-
var src = src.replace(/^ +$/gm, '')
|
146 |
-
, next
|
147 |
-
, loose
|
148 |
-
, cap
|
149 |
-
, bull
|
150 |
-
, b
|
151 |
-
, item
|
152 |
-
, space
|
153 |
-
, i
|
154 |
-
, l;
|
155 |
-
|
156 |
-
while (src) {
|
157 |
-
// newline
|
158 |
-
if (cap = this.rules.newline.exec(src)) {
|
159 |
-
src = src.substring(cap[0].length);
|
160 |
-
if (cap[0].length > 1) {
|
161 |
-
this.tokens.push({
|
162 |
-
type: 'space'
|
163 |
-
});
|
164 |
-
}
|
165 |
-
}
|
166 |
-
|
167 |
-
// code
|
168 |
-
if (cap = this.rules.code.exec(src)) {
|
169 |
-
src = src.substring(cap[0].length);
|
170 |
-
cap = cap[0].replace(/^ {4}/gm, '');
|
171 |
-
this.tokens.push({
|
172 |
-
type: 'code',
|
173 |
-
text: !this.options.pedantic
|
174 |
-
? cap.replace(/\n+$/, '')
|
175 |
-
: cap
|
176 |
-
});
|
177 |
-
continue;
|
178 |
-
}
|
179 |
-
|
180 |
-
// fences (gfm)
|
181 |
-
if (cap = this.rules.fences.exec(src)) {
|
182 |
-
src = src.substring(cap[0].length);
|
183 |
-
this.tokens.push({
|
184 |
-
type: 'code',
|
185 |
-
lang: cap[2],
|
186 |
-
text: cap[3]
|
187 |
-
});
|
188 |
-
continue;
|
189 |
-
}
|
190 |
-
|
191 |
-
// heading
|
192 |
-
if (cap = this.rules.heading.exec(src)) {
|
193 |
-
src = src.substring(cap[0].length);
|
194 |
-
this.tokens.push({
|
195 |
-
type: 'heading',
|
196 |
-
depth: cap[1].length,
|
197 |
-
text: cap[2]
|
198 |
-
});
|
199 |
-
continue;
|
200 |
-
}
|
201 |
-
|
202 |
-
// table no leading pipe (gfm)
|
203 |
-
if (top && (cap = this.rules.nptable.exec(src))) {
|
204 |
-
src = src.substring(cap[0].length);
|
205 |
-
|
206 |
-
item = {
|
207 |
-
type: 'table',
|
208 |
-
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
|
209 |
-
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
210 |
-
cells: cap[3].replace(/\n$/, '').split('\n')
|
211 |
-
};
|
212 |
-
|
213 |
-
for (i = 0; i < item.align.length; i++) {
|
214 |
-
if (/^ *-+: *$/.test(item.align[i])) {
|
215 |
-
item.align[i] = 'right';
|
216 |
-
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
217 |
-
item.align[i] = 'center';
|
218 |
-
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
219 |
-
item.align[i] = 'left';
|
220 |
-
} else {
|
221 |
-
item.align[i] = null;
|
222 |
-
}
|
223 |
-
}
|
224 |
-
|
225 |
-
for (i = 0; i < item.cells.length; i++) {
|
226 |
-
item.cells[i] = item.cells[i].split(/ *\| */);
|
227 |
-
}
|
228 |
-
|
229 |
-
this.tokens.push(item);
|
230 |
-
|
231 |
-
continue;
|
232 |
-
}
|
233 |
-
|
234 |
-
// lheading
|
235 |
-
if (cap = this.rules.lheading.exec(src)) {
|
236 |
-
src = src.substring(cap[0].length);
|
237 |
-
this.tokens.push({
|
238 |
-
type: 'heading',
|
239 |
-
depth: cap[2] === '=' ? 1 : 2,
|
240 |
-
text: cap[1]
|
241 |
-
});
|
242 |
-
continue;
|
243 |
-
}
|
244 |
-
|
245 |
-
// hr
|
246 |
-
if (cap = this.rules.hr.exec(src)) {
|
247 |
-
src = src.substring(cap[0].length);
|
248 |
-
this.tokens.push({
|
249 |
-
type: 'hr'
|
250 |
-
});
|
251 |
-
continue;
|
252 |
-
}
|
253 |
-
|
254 |
-
// blockquote
|
255 |
-
if (cap = this.rules.blockquote.exec(src)) {
|
256 |
-
src = src.substring(cap[0].length);
|
257 |
-
|
258 |
-
this.tokens.push({
|
259 |
-
type: 'blockquote_start'
|
260 |
-
});
|
261 |
-
|
262 |
-
cap = cap[0].replace(/^ *> ?/gm, '');
|
263 |
-
|
264 |
-
// Pass `top` to keep the current
|
265 |
-
// "toplevel" state. This is exactly
|
266 |
-
// how markdown.pl works.
|
267 |
-
this.token(cap, top);
|
268 |
-
|
269 |
-
this.tokens.push({
|
270 |
-
type: 'blockquote_end'
|
271 |
-
});
|
272 |
-
|
273 |
-
continue;
|
274 |
-
}
|
275 |
-
|
276 |
-
// list
|
277 |
-
if (cap = this.rules.list.exec(src)) {
|
278 |
-
src = src.substring(cap[0].length);
|
279 |
-
bull = cap[2];
|
280 |
-
|
281 |
-
this.tokens.push({
|
282 |
-
type: 'list_start',
|
283 |
-
ordered: bull.length > 1
|
284 |
-
});
|
285 |
-
|
286 |
-
// Get each top-level item.
|
287 |
-
cap = cap[0].match(this.rules.item);
|
288 |
-
|
289 |
-
next = false;
|
290 |
-
l = cap.length;
|
291 |
-
i = 0;
|
292 |
-
|
293 |
-
for (; i < l; i++) {
|
294 |
-
item = cap[i];
|
295 |
-
|
296 |
-
// Remove the list item's bullet
|
297 |
-
// so it is seen as the next token.
|
298 |
-
space = item.length;
|
299 |
-
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
|
300 |
-
|
301 |
-
// Outdent whatever the
|
302 |
-
// list item contains. Hacky.
|
303 |
-
if (~item.indexOf('\n ')) {
|
304 |
-
space -= item.length;
|
305 |
-
item = !this.options.pedantic
|
306 |
-
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
|
307 |
-
: item.replace(/^ {1,4}/gm, '');
|
308 |
-
}
|
309 |
-
|
310 |
-
// Determine whether the next list item belongs here.
|
311 |
-
// Backpedal if it does not belong in this list.
|
312 |
-
if (this.options.smartLists && i !== l - 1) {
|
313 |
-
b = block.bullet.exec(cap[i + 1])[0];
|
314 |
-
if (bull !== b && !(bull.length > 1 && b.length > 1)) {
|
315 |
-
src = cap.slice(i + 1).join('\n') + src;
|
316 |
-
i = l - 1;
|
317 |
-
}
|
318 |
-
}
|
319 |
-
|
320 |
-
// Determine whether item is loose or not.
|
321 |
-
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
|
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 |
-
|
329 |
-
this.tokens.push({
|
330 |
-
type: loose
|
331 |
-
? 'loose_item_start'
|
332 |
-
: 'list_item_start'
|
333 |
-
});
|
334 |
-
|
335 |
-
// Recurse.
|
336 |
-
this.token(item, false);
|
337 |
-
|
338 |
-
this.tokens.push({
|
339 |
-
type: 'list_item_end'
|
340 |
-
});
|
341 |
-
}
|
342 |
-
|
343 |
-
this.tokens.push({
|
344 |
-
type: 'list_end'
|
345 |
-
});
|
346 |
-
|
347 |
-
continue;
|
348 |
-
}
|
349 |
-
|
350 |
-
// html
|
351 |
-
if (cap = this.rules.html.exec(src)) {
|
352 |
-
src = src.substring(cap[0].length);
|
353 |
-
this.tokens.push({
|
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;
|
361 |
-
}
|
362 |
-
|
363 |
-
// def
|
364 |
-
if (top && (cap = this.rules.def.exec(src))) {
|
365 |
-
src = src.substring(cap[0].length);
|
366 |
-
this.tokens.links[cap[1].toLowerCase()] = {
|
367 |
-
href: cap[2],
|
368 |
-
title: cap[3]
|
369 |
-
};
|
370 |
-
continue;
|
371 |
-
}
|
372 |
-
|
373 |
-
// table (gfm)
|
374 |
-
if (top && (cap = this.rules.table.exec(src))) {
|
375 |
-
src = src.substring(cap[0].length);
|
376 |
-
|
377 |
-
item = {
|
378 |
-
type: 'table',
|
379 |
-
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
|
380 |
-
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
381 |
-
cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
|
382 |
-
};
|
383 |
-
|
384 |
-
for (i = 0; i < item.align.length; i++) {
|
385 |
-
if (/^ *-+: *$/.test(item.align[i])) {
|
386 |
-
item.align[i] = 'right';
|
387 |
-
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
388 |
-
item.align[i] = 'center';
|
389 |
-
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
390 |
-
item.align[i] = 'left';
|
391 |
-
} else {
|
392 |
-
item.align[i] = null;
|
393 |
-
}
|
394 |
-
}
|
395 |
-
|
396 |
-
for (i = 0; i < item.cells.length; i++) {
|
397 |
-
item.cells[i] = item.cells[i]
|
398 |
-
.replace(/^ *\| *| *\| *$/g, '')
|
399 |
-
.split(/ *\| */);
|
400 |
-
}
|
401 |
-
|
402 |
-
this.tokens.push(item);
|
403 |
-
|
404 |
-
continue;
|
405 |
-
}
|
406 |
-
|
407 |
-
// top-level paragraph
|
408 |
-
if (top && (cap = this.rules.paragraph.exec(src))) {
|
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 |
-
});
|
416 |
-
continue;
|
417 |
-
}
|
418 |
-
|
419 |
-
// text
|
420 |
-
if (cap = this.rules.text.exec(src)) {
|
421 |
-
// Top-level should never reach here.
|
422 |
-
src = src.substring(cap[0].length);
|
423 |
-
this.tokens.push({
|
424 |
-
type: 'text',
|
425 |
-
text: cap[0]
|
426 |
-
});
|
427 |
-
continue;
|
428 |
-
}
|
429 |
-
|
430 |
-
if (src) {
|
431 |
-
throw new
|
432 |
-
Error('Infinite loop on byte: ' + src.charCodeAt(0));
|
433 |
-
}
|
434 |
-
}
|
435 |
-
|
436 |
-
return this.tokens;
|
437 |
-
};
|
438 |
-
|
439 |
-
/**
|
440 |
-
* Inline-Level Grammar
|
441 |
-
*/
|
442 |
-
|
443 |
-
var inline = {
|
444 |
-
escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
|
445 |
-
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
|
446 |
-
url: noop,
|
447 |
-
tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
|
448 |
-
link: /^!?\[(inside)\]\(href\)/,
|
449 |
-
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
|
450 |
-
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
|
451 |
-
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
|
452 |
-
em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
|
453 |
-
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
|
454 |
-
br: /^ {2,}\n(?!\s*$)/,
|
455 |
-
del: noop,
|
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)
|
464 |
-
('href', inline._href)
|
465 |
-
();
|
466 |
-
|
467 |
-
inline.reflink = replace(inline.reflink)
|
468 |
-
('inside', inline._inside)
|
469 |
-
();
|
470 |
-
|
471 |
-
/**
|
472 |
-
* Normal Inline Grammar
|
473 |
-
*/
|
474 |
-
|
475 |
-
inline.normal = merge({}, inline);
|
476 |
-
|
477 |
-
/**
|
478 |
-
* Pedantic Inline Grammar
|
479 |
-
*/
|
480 |
-
|
481 |
-
inline.pedantic = merge({}, inline.normal, {
|
482 |
-
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
|
483 |
-
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
|
484 |
-
});
|
485 |
-
|
486 |
-
/**
|
487 |
-
* GFM Inline Grammar
|
488 |
-
*/
|
489 |
-
|
490 |
-
inline.gfm = merge({}, inline.normal, {
|
491 |
-
escape: replace(inline.escape)('])', '~|])')(),
|
492 |
-
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
|
493 |
-
del: /^~~(?=\S)([\s\S]*?\S)~~/,
|
494 |
-
text: replace(inline.text)
|
495 |
-
(']|', '~]|')
|
496 |
-
('|', '|https?://|')
|
497 |
-
()
|
498 |
-
});
|
499 |
-
|
500 |
-
/**
|
501 |
-
* GFM + Line Breaks Inline Grammar
|
502 |
-
*/
|
503 |
-
|
504 |
-
inline.breaks = merge({}, inline.gfm, {
|
505 |
-
br: replace(inline.br)('{2,}', '*')(),
|
506 |
-
text: replace(inline.gfm.text)('{2,}', '*')()
|
507 |
-
});
|
508 |
-
|
509 |
-
/**
|
510 |
-
* Inline Lexer & Compiler
|
511 |
-
*/
|
512 |
-
|
513 |
-
function InlineLexer(links, options) {
|
514 |
-
this.options = options || marked.defaults;
|
515 |
-
this.links = links;
|
516 |
-
this.rules = inline.normal;
|
517 |
-
|
518 |
-
if (!this.links) {
|
519 |
-
throw new
|
520 |
-
Error('Tokens array requires a `links` property.');
|
521 |
-
}
|
522 |
-
|
523 |
-
if (this.options.gfm) {
|
524 |
-
if (this.options.breaks) {
|
525 |
-
this.rules = inline.breaks;
|
526 |
-
} else {
|
527 |
-
this.rules = inline.gfm;
|
528 |
-
}
|
529 |
-
} else if (this.options.pedantic) {
|
530 |
-
this.rules = inline.pedantic;
|
531 |
-
}
|
532 |
-
}
|
533 |
-
|
534 |
-
/**
|
535 |
-
* Expose Inline Rules
|
536 |
-
*/
|
537 |
-
|
538 |
-
InlineLexer.rules = inline;
|
539 |
-
|
540 |
-
/**
|
541 |
-
* Static Lexing/Compiling Method
|
542 |
-
*/
|
543 |
-
|
544 |
-
InlineLexer.output = function (src, links, options) {
|
545 |
-
var inline = new InlineLexer(links, options);
|
546 |
-
return inline.output(src);
|
547 |
-
};
|
548 |
-
|
549 |
-
/**
|
550 |
-
* Lexing/Compiling
|
551 |
-
*/
|
552 |
-
|
553 |
-
InlineLexer.prototype.output = function (src) {
|
554 |
-
var out = ''
|
555 |
-
, link
|
556 |
-
, text
|
557 |
-
, href
|
558 |
-
, cap;
|
559 |
-
|
560 |
-
while (src) {
|
561 |
-
// escape
|
562 |
-
if (cap = this.rules.escape.exec(src)) {
|
563 |
-
src = src.substring(cap[0].length);
|
564 |
-
out += cap[1];
|
565 |
-
continue;
|
566 |
-
}
|
567 |
-
|
568 |
-
// autolink
|
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;
|
576 |
-
} else {
|
577 |
-
text = escape(cap[1]);
|
578 |
-
href = text;
|
579 |
-
}
|
580 |
-
out += '<a href="'
|
581 |
-
+ href
|
582 |
-
+ '">'
|
583 |
-
+ text
|
584 |
-
+ '</a>';
|
585 |
-
continue;
|
586 |
-
}
|
587 |
-
|
588 |
-
// url (gfm)
|
589 |
-
if (cap = this.rules.url.exec(src)) {
|
590 |
-
src = src.substring(cap[0].length);
|
591 |
-
text = escape(cap[1]);
|
592 |
-
href = text;
|
593 |
-
out += '<a href="'
|
594 |
-
+ href
|
595 |
-
+ '">'
|
596 |
-
+ text
|
597 |
-
+ '</a>';
|
598 |
-
continue;
|
599 |
-
}
|
600 |
-
|
601 |
-
// tag
|
602 |
-
if (cap = this.rules.tag.exec(src)) {
|
603 |
-
src = src.substring(cap[0].length);
|
604 |
-
out += this.options.sanitize
|
605 |
-
? escape(cap[0])
|
606 |
-
: cap[0];
|
607 |
-
continue;
|
608 |
-
}
|
609 |
-
|
610 |
-
// link
|
611 |
-
if (cap = this.rules.link.exec(src)) {
|
612 |
-
src = src.substring(cap[0].length);
|
613 |
-
out += this.outputLink(cap, {
|
614 |
-
href: cap[2],
|
615 |
-
title: cap[3]
|
616 |
-
});
|
617 |
-
continue;
|
618 |
-
}
|
619 |
-
|
620 |
-
// reflink, nolink
|
621 |
-
if ((cap = this.rules.reflink.exec(src))
|
622 |
-
|| (cap = this.rules.nolink.exec(src))) {
|
623 |
-
src = src.substring(cap[0].length);
|
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 |
-
}
|
631 |
-
out += this.outputLink(cap, link);
|
632 |
-
continue;
|
633 |
-
}
|
634 |
-
|
635 |
-
// strong
|
636 |
-
if (cap = this.rules.strong.exec(src)) {
|
637 |
-
src = src.substring(cap[0].length);
|
638 |
-
out += '<strong>'
|
639 |
-
+ this.output(cap[2] || cap[1])
|
640 |
-
+ '</strong>';
|
641 |
-
continue;
|
642 |
-
}
|
643 |
-
|
644 |
-
// em
|
645 |
-
if (cap = this.rules.em.exec(src)) {
|
646 |
-
src = src.substring(cap[0].length);
|
647 |
-
out += '<em>'
|
648 |
-
+ this.output(cap[2] || cap[1])
|
649 |
-
+ '</em>';
|
650 |
-
continue;
|
651 |
-
}
|
652 |
-
|
653 |
-
// code
|
654 |
-
if (cap = this.rules.code.exec(src)) {
|
655 |
-
src = src.substring(cap[0].length);
|
656 |
-
out += '<code>'
|
657 |
-
+ escape(cap[2], true)
|
658 |
-
+ '</code>';
|
659 |
-
continue;
|
660 |
-
}
|
661 |
-
|
662 |
-
// br
|
663 |
-
if (cap = this.rules.br.exec(src)) {
|
664 |
-
src = src.substring(cap[0].length);
|
665 |
-
out += '<br>';
|
666 |
-
continue;
|
667 |
-
}
|
668 |
-
|
669 |
-
// del (gfm)
|
670 |
-
if (cap = this.rules.del.exec(src)) {
|
671 |
-
src = src.substring(cap[0].length);
|
672 |
-
out += '<del>'
|
673 |
-
+ this.output(cap[1])
|
674 |
-
+ '</del>';
|
675 |
-
continue;
|
676 |
-
}
|
677 |
-
|
678 |
-
// text
|
679 |
-
if (cap = this.rules.text.exec(src)) {
|
680 |
-
src = src.substring(cap[0].length);
|
681 |
-
out += escape(this.smartypants(cap[0]));
|
682 |
-
continue;
|
683 |
-
}
|
684 |
-
|
685 |
-
if (src) {
|
686 |
-
throw new
|
687 |
-
Error('Infinite loop on byte: ' + src.charCodeAt(0));
|
688 |
-
}
|
689 |
-
}
|
690 |
-
|
691 |
-
return out;
|
692 |
-
};
|
693 |
-
|
694 |
-
/**
|
695 |
-
* Compile Link
|
696 |
-
*/
|
697 |
-
|
698 |
-
InlineLexer.prototype.outputLink = function (cap, link) {
|
699 |
-
if (cap[0].charAt(0) !== '!') {
|
700 |
-
return '<a href="'
|
701 |
-
+ escape(link.href)
|
702 |
-
+ '"'
|
703 |
-
+ (link.title
|
704 |
-
? ' title="'
|
705 |
-
+ escape(link.title)
|
706 |
-
+ '"'
|
707 |
-
: '')
|
708 |
-
+ '>'
|
709 |
-
+ this.output(cap[1])
|
710 |
-
+ '</a>';
|
711 |
-
} else {
|
712 |
-
return '<img src="'
|
713 |
-
+ escape(link.href)
|
714 |
-
+ '" alt="'
|
715 |
-
+ escape(cap[1])
|
716 |
-
+ '"'
|
717 |
-
+ (link.title
|
718 |
-
? ' title="'
|
719 |
-
+ escape(link.title)
|
720 |
-
+ '"'
|
721 |
-
: '')
|
722 |
-
+ '>';
|
723 |
-
}
|
724 |
-
};
|
725 |
-
|
726 |
-
/**
|
727 |
-
* Smartypants Transformations
|
728 |
-
*/
|
729 |
-
|
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 |
-
|
747 |
-
/**
|
748 |
-
* Mangle Links
|
749 |
-
*/
|
750 |
-
|
751 |
-
InlineLexer.prototype.mangle = function (text) {
|
752 |
-
var out = ''
|
753 |
-
, l = text.length
|
754 |
-
, i = 0
|
755 |
-
, ch;
|
756 |
-
|
757 |
-
for (; i < l; i++) {
|
758 |
-
ch = text.charCodeAt(i);
|
759 |
-
if (Math.random() > 0.5) {
|
760 |
-
ch = 'x' + ch.toString(16);
|
761 |
-
}
|
762 |
-
out += '&#' + ch + ';';
|
763 |
-
}
|
764 |
-
|
765 |
-
return out;
|
766 |
-
};
|
767 |
-
|
768 |
-
/**
|
769 |
-
* Parsing & Compiling
|
770 |
-
*/
|
771 |
-
|
772 |
-
function Parser(options) {
|
773 |
-
this.tokens = [];
|
774 |
-
this.token = null;
|
775 |
-
this.options = options || marked.defaults;
|
776 |
-
}
|
777 |
-
|
778 |
-
/**
|
779 |
-
* Static Parse Method
|
780 |
-
*/
|
781 |
-
|
782 |
-
Parser.parse = function (src, options) {
|
783 |
-
var parser = new Parser(options);
|
784 |
-
return parser.parse(src);
|
785 |
-
};
|
786 |
-
|
787 |
-
/**
|
788 |
-
* Parse Loop
|
789 |
-
*/
|
790 |
-
|
791 |
-
Parser.prototype.parse = function (src) {
|
792 |
-
this.inline = new InlineLexer(src.links, this.options);
|
793 |
-
this.tokens = src.reverse();
|
794 |
-
|
795 |
-
var out = '';
|
796 |
-
while (this.next()) {
|
797 |
-
out += this.tok();
|
798 |
-
}
|
799 |
-
|
800 |
-
return out;
|
801 |
-
};
|
802 |
-
|
803 |
-
/**
|
804 |
-
* Next Token
|
805 |
-
*/
|
806 |
-
|
807 |
-
Parser.prototype.next = function () {
|
808 |
-
return this.token = this.tokens.pop();
|
809 |
-
};
|
810 |
-
|
811 |
-
/**
|
812 |
-
* Preview Next Token
|
813 |
-
*/
|
814 |
-
|
815 |
-
Parser.prototype.peek = function () {
|
816 |
-
return this.tokens[this.tokens.length - 1] || 0;
|
817 |
-
};
|
818 |
-
|
819 |
-
/**
|
820 |
-
* Parse Text Tokens
|
821 |
-
*/
|
822 |
-
|
823 |
-
Parser.prototype.parseText = function () {
|
824 |
-
var body = this.token.text;
|
825 |
-
|
826 |
-
while (this.peek().type === 'text') {
|
827 |
-
body += '\n' + this.next().text;
|
828 |
-
}
|
829 |
-
|
830 |
-
return this.inline.output(body);
|
831 |
-
};
|
832 |
-
|
833 |
-
/**
|
834 |
-
* Parse Current Token
|
835 |
-
*/
|
836 |
-
|
837 |
-
Parser.prototype.tok = function () {
|
838 |
-
switch (this.token.type) {
|
839 |
-
case 'space':
|
840 |
-
{
|
841 |
-
return '';
|
842 |
-
}
|
843 |
-
case 'hr':
|
844 |
-
{
|
845 |
-
return '<hr>\n';
|
846 |
-
}
|
847 |
-
case 'heading':
|
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
|
857 |
-
+ '>\n';
|
858 |
-
}
|
859 |
-
case 'code':
|
860 |
-
{
|
861 |
-
if (this.options.highlight) {
|
862 |
-
var code = this.options.highlight(this.token.text, this.token.lang);
|
863 |
-
if (code != null && code !== this.token.text) {
|
864 |
-
this.token.escaped = true;
|
865 |
-
this.token.text = code;
|
866 |
-
}
|
867 |
-
}
|
868 |
-
|
869 |
-
if (!this.token.escaped) {
|
870 |
-
this.token.text = escape(this.token.text, true);
|
871 |
-
}
|
872 |
-
|
873 |
-
return '<pre><code'
|
874 |
-
+ (this.token.lang
|
875 |
-
? ' class="'
|
876 |
-
+ this.options.langPrefix
|
877 |
-
+ this.token.lang
|
878 |
-
+ '"'
|
879 |
-
: '')
|
880 |
-
+ '>'
|
881 |
-
+ this.token.text
|
882 |
-
+ '</code></pre>\n';
|
883 |
-
}
|
884 |
-
case 'table':
|
885 |
-
{
|
886 |
-
var body = ''
|
887 |
-
, heading
|
888 |
-
, i
|
889 |
-
, row
|
890 |
-
, cell
|
891 |
-
, j;
|
892 |
-
|
893 |
-
// header
|
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 |
-
|
905 |
-
// body
|
906 |
-
body += '<tbody>\n'
|
907 |
-
for (i = 0; i < this.token.cells.length; i++) {
|
908 |
-
row = this.token.cells[i];
|
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 |
-
}
|
920 |
-
body += '</tbody>\n';
|
921 |
-
|
922 |
-
return '<table>\n'
|
923 |
-
+ body
|
924 |
-
+ '</table>\n';
|
925 |
-
}
|
926 |
-
case 'blockquote_start':
|
927 |
-
{
|
928 |
-
var body = '';
|
929 |
-
|
930 |
-
while (this.next().type !== 'blockquote_end') {
|
931 |
-
body += this.tok();
|
932 |
-
}
|
933 |
-
|
934 |
-
return '<blockquote>\n'
|
935 |
-
+ body
|
936 |
-
+ '</blockquote>\n';
|
937 |
-
}
|
938 |
-
case 'list_start':
|
939 |
-
{
|
940 |
-
var type = this.token.ordered ? 'ol' : 'ul'
|
941 |
-
, body = '';
|
942 |
-
|
943 |
-
while (this.next().type !== 'list_end') {
|
944 |
-
body += this.tok();
|
945 |
-
}
|
946 |
-
|
947 |
-
return '<'
|
948 |
-
+ type
|
949 |
-
+ '>\n'
|
950 |
-
+ body
|
951 |
-
+ '</'
|
952 |
-
+ type
|
953 |
-
+ '>\n';
|
954 |
-
}
|
955 |
-
case 'list_item_start':
|
956 |
-
{
|
957 |
-
var body = '';
|
958 |
-
|
959 |
-
while (this.next().type !== 'list_item_end') {
|
960 |
-
body += this.token.type === 'text'
|
961 |
-
? this.parseText()
|
962 |
-
: this.tok();
|
963 |
-
}
|
964 |
-
|
965 |
-
return '<li>'
|
966 |
-
+ body
|
967 |
-
+ '</li>\n';
|
968 |
-
}
|
969 |
-
case 'loose_item_start':
|
970 |
-
{
|
971 |
-
var body = '';
|
972 |
-
|
973 |
-
while (this.next().type !== 'list_item_end') {
|
974 |
-
body += this.tok();
|
975 |
-
}
|
976 |
-
|
977 |
-
return '<li>'
|
978 |
-
+ body
|
979 |
-
+ '</li>\n';
|
980 |
-
}
|
981 |
-
case 'html':
|
982 |
-
{
|
983 |
-
return !this.token.pre && !this.options.pedantic
|
984 |
-
? this.inline.output(this.token.text)
|
985 |
-
: this.token.text;
|
986 |
-
}
|
987 |
-
case 'paragraph':
|
988 |
-
{
|
989 |
-
return '<p>'
|
990 |
-
+ this.inline.output(this.token.text)
|
991 |
-
+ '</p>\n';
|
992 |
-
}
|
993 |
-
case 'text':
|
994 |
-
{
|
995 |
-
return '<p>'
|
996 |
-
+ this.parseText()
|
997 |
-
+ '</p>\n';
|
998 |
-
}
|
999 |
-
}
|
1000 |
-
};
|
1001 |
-
|
1002 |
-
/**
|
1003 |
-
* Helpers
|
1004 |
-
*/
|
1005 |
-
|
1006 |
-
function escape(html, encode) {
|
1007 |
-
return html
|
1008 |
-
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
|
1009 |
-
.replace(/</g, '<')
|
1010 |
-
.replace(/>/g, '>')
|
1011 |
-
.replace(/"/g, '"')
|
1012 |
-
.replace(/'/g, ''');
|
1013 |
-
}
|
1014 |
-
|
1015 |
-
function replace(regex, opt) {
|
1016 |
-
regex = regex.source;
|
1017 |
-
opt = opt || '';
|
1018 |
-
return function self(name, val) {
|
1019 |
-
if (!name) return new RegExp(regex, opt);
|
1020 |
-
val = val.source || val;
|
1021 |
-
val = val.replace(/(^|[^\[])\^/g, '$1');
|
1022 |
-
regex = regex.replace(name, val);
|
1023 |
-
return self;
|
1024 |
-
};
|
1025 |
-
}
|
1026 |
-
|
1027 |
-
function noop() {
|
1028 |
-
}
|
1029 |
-
|
1030 |
-
noop.exec = noop;
|
1031 |
-
|
1032 |
-
function merge(obj) {
|
1033 |
-
var i = 1
|
1034 |
-
, target
|
1035 |
-
, key;
|
1036 |
-
|
1037 |
-
for (; i < arguments.length; i++) {
|
1038 |
-
target = arguments[i];
|
1039 |
-
for (key in target) {
|
1040 |
-
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
1041 |
-
obj[key] = target[key];
|
1042 |
-
}
|
1043 |
-
}
|
1044 |
-
}
|
1045 |
-
|
1046 |
-
return obj;
|
1047 |
-
}
|
1048 |
-
|
1049 |
-
/**
|
1050 |
-
* Marked
|
1051 |
-
*/
|
1052 |
-
|
1053 |
-
function marked(src, opt, callback) {
|
1054 |
-
if (callback || typeof opt === 'function') {
|
1055 |
-
if (!callback) {
|
1056 |
-
callback = opt;
|
1057 |
-
opt = null;
|
1058 |
-
}
|
1059 |
-
|
1060 |
-
opt = merge({}, marked.defaults, opt || {});
|
1061 |
-
|
1062 |
-
var highlight = opt.highlight
|
1063 |
-
, tokens
|
1064 |
-
, pending
|
1065 |
-
, i = 0;
|
1066 |
-
|
1067 |
-
try {
|
1068 |
-
tokens = Lexer.lex(src, opt)
|
1069 |
-
} catch (e) {
|
1070 |
-
return callback(e);
|
1071 |
-
}
|
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) {
|
1081 |
-
err = e;
|
1082 |
-
}
|
1083 |
-
|
1084 |
-
opt.highlight = highlight;
|
1085 |
-
|
1086 |
-
return err
|
1087 |
-
? callback(err)
|
1088 |
-
: callback(null, out);
|
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++) {
|
1100 |
-
(function (token) {
|
1101 |
-
if (token.type !== 'code') {
|
1102 |
-
return --pending || done();
|
1103 |
-
}
|
1104 |
-
return highlight(token.text, token.lang, function (err, code) {
|
1105 |
-
if (code == null || code === token.text) {
|
1106 |
-
return --pending || done();
|
1107 |
-
}
|
1108 |
-
token.text = code;
|
1109 |
-
token.escaped = true;
|
1110 |
-
--pending || done();
|
1111 |
-
});
|
1112 |
-
})(tokens[i]);
|
1113 |
-
}
|
1114 |
-
|
1115 |
-
return;
|
1116 |
-
}
|
1117 |
-
try {
|
1118 |
-
if (opt) opt = merge({}, marked.defaults, opt);
|
1119 |
-
return Parser.parse(Lexer.lex(src, opt), opt);
|
1120 |
-
} catch (e) {
|
1121 |
-
e.message += '\nPlease report this to https://github.com/chjj/marked.';
|
1122 |
-
if ((opt || marked.defaults).silent) {
|
1123 |
-
return '<p>An error occured:</p><pre>'
|
1124 |
-
+ escape(e.message + '', true)
|
1125 |
-
+ '</pre>';
|
1126 |
-
}
|
1127 |
-
throw e;
|
1128 |
-
}
|
1129 |
-
}
|
1130 |
-
|
1131 |
-
/**
|
1132 |
-
* Options
|
1133 |
-
*/
|
1134 |
-
|
1135 |
-
marked.options =
|
1136 |
-
marked.setOptions = function (opt) {
|
1137 |
-
merge(marked.defaults, opt);
|
1138 |
-
return marked;
|
1139 |
-
};
|
1140 |
-
|
1141 |
-
marked.defaults = {
|
1142 |
-
gfm: true,
|
1143 |
-
tables: true,
|
1144 |
-
breaks: false,
|
1145 |
-
pedantic: false,
|
1146 |
-
sanitize: false,
|
1147 |
-
smartLists: false,
|
1148 |
-
silent: false,
|
1149 |
-
highlight: null,
|
1150 |
-
langPrefix: 'lang-',
|
1151 |
-
smartypants: false
|
1152 |
-
};
|
1153 |
-
|
1154 |
-
/**
|
1155 |
-
* Expose
|
1156 |
-
*/
|
1157 |
-
|
1158 |
-
marked.Parser = Parser;
|
1159 |
-
marked.parser = Parser.parse;
|
1160 |
-
|
1161 |
-
marked.Lexer = Lexer;
|
1162 |
-
marked.lexer = Lexer.lex;
|
1163 |
-
|
1164 |
-
marked.InlineLexer = InlineLexer;
|
1165 |
-
marked.inlineLexer = InlineLexer.output;
|
1166 |
-
|
1167 |
-
marked.parse = marked;
|
1168 |
-
|
1169 |
-
if (typeof exports === 'object') {
|
1170 |
-
module.exports = marked;
|
1171 |
-
} else if (typeof define === 'function' && define.amd) {
|
1172 |
-
define(function () {
|
1173 |
-
return marked;
|
1174 |
-
});
|
1175 |
-
} else {
|
1176 |
-
this.marked = marked;
|
1177 |
-
}
|
1178 |
-
|
1179 |
-
}).call(function () {
|
1180 |
-
return this || (typeof window !== 'undefined' ? window : global);
|
1181 |
-
}());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
js/markdown/adminhtml/epiceditor.js
ADDED
@@ -0,0 +1,1896 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* EpicEditor - An Embeddable JavaScript Markdown Editor (https://github.com/OscarGodson/EpicEditor)
|
3 |
+
* Copyright (c) 2011-2012, Oscar Godson. (MIT Licensed)
|
4 |
+
*
|
5 |
+
* @SchumacherFM: Version without marked() which is included in seperate file
|
6 |
+
*/
|
7 |
+
|
8 |
+
(function (window, undefined) {
|
9 |
+
/**
|
10 |
+
* Applies attributes to a DOM object
|
11 |
+
* @param {object} context The DOM obj you want to apply the attributes to
|
12 |
+
* @param {object} attrs A key/value pair of attributes you want to apply
|
13 |
+
* @returns {undefined}
|
14 |
+
*/
|
15 |
+
function _applyAttrs(context, attrs) {
|
16 |
+
for (var attr in attrs) {
|
17 |
+
if (attrs.hasOwnProperty(attr)) {
|
18 |
+
context.setAttribute(attr, attrs[attr]);
|
19 |
+
}
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Applies styles to a DOM object
|
25 |
+
* @param {object} context The DOM obj you want to apply the attributes to
|
26 |
+
* @param {object} attrs A key/value pair of attributes you want to apply
|
27 |
+
* @returns {undefined}
|
28 |
+
*/
|
29 |
+
function _applyStyles(context, attrs) {
|
30 |
+
for (var attr in attrs) {
|
31 |
+
if (attrs.hasOwnProperty(attr)) {
|
32 |
+
context.style[attr] = attrs[attr];
|
33 |
+
}
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Returns a DOM objects computed style
|
39 |
+
* @param {object} el The element you want to get the style from
|
40 |
+
* @param {string} styleProp The property you want to get from the element
|
41 |
+
* @returns {string} Returns a string of the value. If property is not set it will return a blank string
|
42 |
+
*/
|
43 |
+
function _getStyle(el, styleProp) {
|
44 |
+
var x = el
|
45 |
+
, y = null;
|
46 |
+
if (window.getComputedStyle) {
|
47 |
+
y = document.defaultView.getComputedStyle(x, null).getPropertyValue(styleProp);
|
48 |
+
}
|
49 |
+
else if (x.currentStyle) {
|
50 |
+
y = x.currentStyle[styleProp];
|
51 |
+
}
|
52 |
+
return y;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Saves the current style state for the styles requested, then applies styles
|
57 |
+
* to overwrite the existing one. The old styles are returned as an object so
|
58 |
+
* you can pass it back in when you want to revert back to the old style
|
59 |
+
* @param {object} el The element to get the styles of
|
60 |
+
* @param {string} type Can be "save" or "apply". apply will just apply styles you give it. Save will write styles
|
61 |
+
* @param {object} styles Key/value style/property pairs
|
62 |
+
* @returns {object}
|
63 |
+
*/
|
64 |
+
function _saveStyleState(el, type, styles) {
|
65 |
+
var returnState = {}
|
66 |
+
, style;
|
67 |
+
if (type === 'save') {
|
68 |
+
for (style in styles) {
|
69 |
+
if (styles.hasOwnProperty(style)) {
|
70 |
+
returnState[style] = _getStyle(el, style);
|
71 |
+
}
|
72 |
+
}
|
73 |
+
// After it's all done saving all the previous states, change the styles
|
74 |
+
_applyStyles(el, styles);
|
75 |
+
}
|
76 |
+
else if (type === 'apply') {
|
77 |
+
_applyStyles(el, styles);
|
78 |
+
}
|
79 |
+
return returnState;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Gets an elements total width including it's borders and padding
|
84 |
+
* @param {object} el The element to get the total width of
|
85 |
+
* @returns {int}
|
86 |
+
*/
|
87 |
+
function _outerWidth(el) {
|
88 |
+
var b = parseInt(_getStyle(el, 'border-left-width'), 10) + parseInt(_getStyle(el, 'border-right-width'), 10)
|
89 |
+
, p = parseInt(_getStyle(el, 'padding-left'), 10) + parseInt(_getStyle(el, 'padding-right'), 10)
|
90 |
+
, w = el.offsetWidth
|
91 |
+
, t;
|
92 |
+
// For IE in case no border is set and it defaults to "medium"
|
93 |
+
if (isNaN(b)) { b = 0; }
|
94 |
+
t = b + p + w;
|
95 |
+
return t;
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Gets an elements total height including it's borders and padding
|
100 |
+
* @param {object} el The element to get the total width of
|
101 |
+
* @returns {int}
|
102 |
+
*/
|
103 |
+
function _outerHeight(el) {
|
104 |
+
var b = parseInt(_getStyle(el, 'border-top-width'), 10) + parseInt(_getStyle(el, 'border-bottom-width'), 10)
|
105 |
+
, p = parseInt(_getStyle(el, 'padding-top'), 10) + parseInt(_getStyle(el, 'padding-bottom'), 10)
|
106 |
+
, w = parseInt(_getStyle(el, 'height'), 10)
|
107 |
+
, t;
|
108 |
+
// For IE in case no border is set and it defaults to "medium"
|
109 |
+
if (isNaN(b)) { b = 0; }
|
110 |
+
t = b + p + w;
|
111 |
+
return t;
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Inserts a <link> tag specifically for CSS
|
116 |
+
* @param {string} path The path to the CSS file
|
117 |
+
* @param {object} context In what context you want to apply this to (document, iframe, etc)
|
118 |
+
* @param {string} id An id for you to reference later for changing properties of the <link>
|
119 |
+
* @returns {undefined}
|
120 |
+
*/
|
121 |
+
function _insertCSSLink(path, context, id) {
|
122 |
+
id = id || '';
|
123 |
+
var headID = context.getElementsByTagName("head")[0]
|
124 |
+
, cssNode = context.createElement('link');
|
125 |
+
|
126 |
+
_applyAttrs(cssNode, {
|
127 |
+
type: 'text/css'
|
128 |
+
, id: id
|
129 |
+
, rel: 'stylesheet'
|
130 |
+
, href: path
|
131 |
+
, name: path
|
132 |
+
, media: 'screen'
|
133 |
+
});
|
134 |
+
|
135 |
+
headID.appendChild(cssNode);
|
136 |
+
}
|
137 |
+
|
138 |
+
// Simply replaces a class (o), to a new class (n) on an element provided (e)
|
139 |
+
function _replaceClass(e, o, n) {
|
140 |
+
e.className = e.className.replace(o, n);
|
141 |
+
}
|
142 |
+
|
143 |
+
// Feature detects an iframe to get the inner document for writing to
|
144 |
+
function _getIframeInnards(el) {
|
145 |
+
return el.contentDocument || el.contentWindow.document;
|
146 |
+
}
|
147 |
+
|
148 |
+
// Grabs the text from an element and preserves whitespace
|
149 |
+
function _getText(el) {
|
150 |
+
var theText;
|
151 |
+
// Make sure to check for type of string because if the body of the page
|
152 |
+
// doesn't have any text it'll be "" which is falsey and will go into
|
153 |
+
// the else which is meant for Firefox and shit will break
|
154 |
+
if (typeof document.body.innerText == 'string') {
|
155 |
+
theText = el.innerText;
|
156 |
+
}
|
157 |
+
else {
|
158 |
+
// First replace <br>s before replacing the rest of the HTML
|
159 |
+
theText = el.innerHTML.replace(/<br>/gi, "\n");
|
160 |
+
// Now we can clean the HTML
|
161 |
+
theText = theText.replace(/<(?:.|\n)*?>/gm, '');
|
162 |
+
// Now fix HTML entities
|
163 |
+
theText = theText.replace(/</gi, '<');
|
164 |
+
theText = theText.replace(/>/gi, '>');
|
165 |
+
}
|
166 |
+
return theText;
|
167 |
+
}
|
168 |
+
|
169 |
+
function _setText(el, content) {
|
170 |
+
// Don't convert lt/gt characters as HTML when viewing the editor window
|
171 |
+
// TODO: Write a test to catch regressions for this
|
172 |
+
content = content.replace(/</g, '<');
|
173 |
+
content = content.replace(/>/g, '>');
|
174 |
+
content = content.replace(/\n/g, '<br>');
|
175 |
+
|
176 |
+
// Make sure to there aren't two spaces in a row (replace one with )
|
177 |
+
// If you find and replace every space with a text will not wrap.
|
178 |
+
// Hence the name (Non-Breaking-SPace).
|
179 |
+
// TODO: Probably need to test this somehow...
|
180 |
+
content = content.replace(/<br>\s/g, '<br> ')
|
181 |
+
content = content.replace(/\s\s\s/g, ' ')
|
182 |
+
content = content.replace(/\s\s/g, ' ')
|
183 |
+
content = content.replace(/^ /, ' ')
|
184 |
+
|
185 |
+
el.innerHTML = content;
|
186 |
+
return true;
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Converts the 'raw' format of a file's contents into plaintext
|
191 |
+
* @param {string} content Contents of the file
|
192 |
+
* @returns {string} the sanitized content
|
193 |
+
*/
|
194 |
+
function _sanitizeRawContent(content) {
|
195 |
+
// Get this, 2 spaces in a content editable actually converts to:
|
196 |
+
// 0020 00a0, meaning, "space no-break space". So, manually convert
|
197 |
+
// no-break spaces to spaces again before handing to marked.
|
198 |
+
// Also, WebKit converts no-break to unicode equivalent and FF HTML.
|
199 |
+
return content.replace(/\u00a0/g, ' ').replace(/ /g, ' ');
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Will return the version number if the browser is IE. If not will return -1
|
204 |
+
* TRY NEVER TO USE THIS AND USE FEATURE DETECTION IF POSSIBLE
|
205 |
+
* @returns {Number} -1 if false or the version number if true
|
206 |
+
*/
|
207 |
+
function _isIE() {
|
208 |
+
var rv = -1 // Return value assumes failure.
|
209 |
+
, ua = navigator.userAgent
|
210 |
+
, re;
|
211 |
+
if (navigator.appName == 'Microsoft Internet Explorer') {
|
212 |
+
re = /MSIE ([0-9]{1,}[\.0-9]{0,})/;
|
213 |
+
if (re.exec(ua) != null) {
|
214 |
+
rv = parseFloat(RegExp.$1, 10);
|
215 |
+
}
|
216 |
+
}
|
217 |
+
return rv;
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Same as the isIE(), but simply returns a boolean
|
222 |
+
* THIS IS TERRIBLE AND IS ONLY USED BECAUSE FULLSCREEN IN SAFARI IS BORKED
|
223 |
+
* If some other engine uses WebKit and has support for fullscreen they
|
224 |
+
* probably wont get native fullscreen until Safari's fullscreen is fixed
|
225 |
+
* @returns {Boolean} true if Safari
|
226 |
+
*/
|
227 |
+
function _isSafari() {
|
228 |
+
var n = window.navigator;
|
229 |
+
return n.userAgent.indexOf('Safari') > -1 && n.userAgent.indexOf('Chrome') == -1;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Same as the isIE(), but simply returns a boolean
|
234 |
+
* THIS IS TERRIBLE ONLY USE IF ABSOLUTELY NEEDED
|
235 |
+
* @returns {Boolean} true if Safari
|
236 |
+
*/
|
237 |
+
function _isFirefox() {
|
238 |
+
var n = window.navigator;
|
239 |
+
return n.userAgent.indexOf('Firefox') > -1 && n.userAgent.indexOf('Seamonkey') == -1;
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Determines if supplied value is a function
|
244 |
+
* @param {object} object to determine type
|
245 |
+
*/
|
246 |
+
function _isFunction(functionToCheck) {
|
247 |
+
var getType = {};
|
248 |
+
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
249 |
+
}
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
|
253 |
+
* @param {boolean} [deepMerge=false] If true, will deep merge meaning it will merge sub-objects like {obj:obj2{foo:'bar'}}
|
254 |
+
* @param {object} first object
|
255 |
+
* @param {object} second object
|
256 |
+
* @returnss {object} a new object based on obj1 and obj2
|
257 |
+
*/
|
258 |
+
function _mergeObjs() {
|
259 |
+
// copy reference to target object
|
260 |
+
var target = arguments[0] || {}
|
261 |
+
, i = 1
|
262 |
+
, length = arguments.length
|
263 |
+
, deep = false
|
264 |
+
, options
|
265 |
+
, name
|
266 |
+
, src
|
267 |
+
, copy
|
268 |
+
|
269 |
+
// Handle a deep copy situation
|
270 |
+
if (typeof target === "boolean") {
|
271 |
+
deep = target;
|
272 |
+
target = arguments[1] || {};
|
273 |
+
// skip the boolean and the target
|
274 |
+
i = 2;
|
275 |
+
}
|
276 |
+
|
277 |
+
// Handle case when target is a string or something (possible in deep copy)
|
278 |
+
if (typeof target !== "object" && !_isFunction(target)) {
|
279 |
+
target = {};
|
280 |
+
}
|
281 |
+
// extend jQuery itself if only one argument is passed
|
282 |
+
if (length === i) {
|
283 |
+
target = this;
|
284 |
+
--i;
|
285 |
+
}
|
286 |
+
|
287 |
+
for (; i < length; i++) {
|
288 |
+
// Only deal with non-null/undefined values
|
289 |
+
if ((options = arguments[i]) != null) {
|
290 |
+
// Extend the base object
|
291 |
+
for (name in options) {
|
292 |
+
// @NOTE: added hasOwnProperty check
|
293 |
+
if (options.hasOwnProperty(name)) {
|
294 |
+
src = target[name];
|
295 |
+
copy = options[name];
|
296 |
+
// Prevent never-ending loop
|
297 |
+
if (target === copy) {
|
298 |
+
continue;
|
299 |
+
}
|
300 |
+
// Recurse if we're merging object values
|
301 |
+
if (deep && copy && typeof copy === "object" && !copy.nodeType) {
|
302 |
+
target[name] = _mergeObjs(deep,
|
303 |
+
// Never move original objects, clone them
|
304 |
+
src || (copy.length != null ? [] : {})
|
305 |
+
, copy);
|
306 |
+
} else if (copy !== undefined) { // Don't bring in undefined values
|
307 |
+
target[name] = copy;
|
308 |
+
}
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
312 |
+
}
|
313 |
+
|
314 |
+
// Return the modified object
|
315 |
+
return target;
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Initiates the EpicEditor object and sets up offline storage as well
|
320 |
+
* @class Represents an EpicEditor instance
|
321 |
+
* @param {object} options An optional customization object
|
322 |
+
* @returns {object} EpicEditor will be returned
|
323 |
+
*/
|
324 |
+
function EpicEditor(options) {
|
325 |
+
// Default settings will be overwritten/extended by options arg
|
326 |
+
var self = this
|
327 |
+
, opts = options || {}
|
328 |
+
, _defaultFileSchema
|
329 |
+
, _defaultFile
|
330 |
+
, defaults = { container: 'epiceditor'
|
331 |
+
, basePath: 'epiceditor'
|
332 |
+
, textarea: undefined
|
333 |
+
, clientSideStorage: true
|
334 |
+
, localStorageName: 'epiceditor'
|
335 |
+
, useNativeFullscreen: true
|
336 |
+
, file: { name: null
|
337 |
+
, defaultContent: ''
|
338 |
+
, autoSave: 100 // Set to false for no auto saving
|
339 |
+
}
|
340 |
+
, theme: { base: '/themes/base/epiceditor.css'
|
341 |
+
, preview: '/themes/preview/github.css'
|
342 |
+
, editor: '/themes/editor/epic-dark.css'
|
343 |
+
}
|
344 |
+
, focusOnLoad: false
|
345 |
+
, shortcut: { modifier: 18 // alt keycode
|
346 |
+
, fullscreen: 70 // f keycode
|
347 |
+
, preview: 80 // p keycode
|
348 |
+
}
|
349 |
+
, string: { togglePreview: 'Toggle Preview Mode'
|
350 |
+
, toggleEdit: 'Toggle Edit Mode'
|
351 |
+
, toggleFullscreen: 'Enter Fullscreen'
|
352 |
+
}
|
353 |
+
, parser: typeof marked == 'function' ? marked : null
|
354 |
+
, autogrow: false
|
355 |
+
, button: { fullscreen: true
|
356 |
+
, preview: true
|
357 |
+
, bar: "auto"
|
358 |
+
}
|
359 |
+
}
|
360 |
+
, defaultStorage
|
361 |
+
, autogrowDefaults = { minHeight: 80
|
362 |
+
, maxHeight: false
|
363 |
+
, scroll: true
|
364 |
+
};
|
365 |
+
|
366 |
+
self.settings = _mergeObjs(true, defaults, opts);
|
367 |
+
|
368 |
+
var buttons = self.settings.button;
|
369 |
+
self._fullscreenEnabled = typeof(buttons) === 'object' ? typeof buttons.fullscreen === 'undefined' || buttons.fullscreen : buttons === true;
|
370 |
+
self._editEnabled = typeof(buttons) === 'object' ? typeof buttons.edit === 'undefined' || buttons.edit : buttons === true;
|
371 |
+
self._previewEnabled = typeof(buttons) === 'object' ? typeof buttons.preview === 'undefined' || buttons.preview : buttons === true;
|
372 |
+
|
373 |
+
if (!(typeof self.settings.parser == 'function' && typeof self.settings.parser('TEST') == 'string')) {
|
374 |
+
self.settings.parser = function (str) {
|
375 |
+
return str;
|
376 |
+
}
|
377 |
+
}
|
378 |
+
|
379 |
+
if (self.settings.autogrow) {
|
380 |
+
if (self.settings.autogrow === true) {
|
381 |
+
self.settings.autogrow = autogrowDefaults;
|
382 |
+
}
|
383 |
+
else {
|
384 |
+
self.settings.autogrow = _mergeObjs(true, autogrowDefaults, self.settings.autogrow);
|
385 |
+
}
|
386 |
+
self._oldHeight = -1;
|
387 |
+
}
|
388 |
+
|
389 |
+
// If you put an absolute link as the path of any of the themes ignore the basePath
|
390 |
+
// preview theme
|
391 |
+
if (!self.settings.theme.preview.match(/^https?:\/\//)) {
|
392 |
+
self.settings.theme.preview = self.settings.basePath + self.settings.theme.preview;
|
393 |
+
}
|
394 |
+
// editor theme
|
395 |
+
if (!self.settings.theme.editor.match(/^https?:\/\//)) {
|
396 |
+
self.settings.theme.editor = self.settings.basePath + self.settings.theme.editor;
|
397 |
+
}
|
398 |
+
// base theme
|
399 |
+
if (!self.settings.theme.base.match(/^https?:\/\//)) {
|
400 |
+
self.settings.theme.base = self.settings.basePath + self.settings.theme.base;
|
401 |
+
}
|
402 |
+
|
403 |
+
// Grab the container element and save it to self.element
|
404 |
+
// if it's a string assume it's an ID and if it's an object
|
405 |
+
// assume it's a DOM element
|
406 |
+
if (typeof self.settings.container == 'string') {
|
407 |
+
self.element = document.getElementById(self.settings.container);
|
408 |
+
}
|
409 |
+
else if (typeof self.settings.container == 'object') {
|
410 |
+
self.element = self.settings.container;
|
411 |
+
}
|
412 |
+
|
413 |
+
if (typeof self.settings.textarea == 'undefined' && typeof self.element != 'undefined') {
|
414 |
+
var textareas = self.element.getElementsByTagName('textarea');
|
415 |
+
if (textareas.length > 0) {
|
416 |
+
self.settings.textarea = textareas[0];
|
417 |
+
_applyStyles(self.settings.textarea, {
|
418 |
+
display: 'none'
|
419 |
+
});
|
420 |
+
}
|
421 |
+
}
|
422 |
+
|
423 |
+
// Figure out the file name. If no file name is given we'll use the ID.
|
424 |
+
// If there's no ID either we'll use a namespaced file name that's incremented
|
425 |
+
// based on the calling order. As long as it doesn't change, drafts will be saved.
|
426 |
+
if (!self.settings.file.name) {
|
427 |
+
if (typeof self.settings.container == 'string') {
|
428 |
+
self.settings.file.name = self.settings.container;
|
429 |
+
}
|
430 |
+
else if (typeof self.settings.container == 'object') {
|
431 |
+
if (self.element.id) {
|
432 |
+
self.settings.file.name = self.element.id;
|
433 |
+
}
|
434 |
+
else {
|
435 |
+
if (!EpicEditor._data.unnamedEditors) {
|
436 |
+
EpicEditor._data.unnamedEditors = [];
|
437 |
+
}
|
438 |
+
EpicEditor._data.unnamedEditors.push(self);
|
439 |
+
self.settings.file.name = '__epiceditor-untitled-' + EpicEditor._data.unnamedEditors.length;
|
440 |
+
}
|
441 |
+
}
|
442 |
+
}
|
443 |
+
|
444 |
+
if (self.settings.button.bar === "show") {
|
445 |
+
self.settings.button.bar = true;
|
446 |
+
}
|
447 |
+
|
448 |
+
if (self.settings.button.bar === "hide") {
|
449 |
+
self.settings.button.bar = false;
|
450 |
+
}
|
451 |
+
|
452 |
+
// Protect the id and overwrite if passed in as an option
|
453 |
+
// TODO: Put underscrore to denote that this is private
|
454 |
+
self._instanceId = 'epiceditor-' + Math.round(Math.random() * 100000);
|
455 |
+
self._storage = {};
|
456 |
+
self._canSave = true;
|
457 |
+
|
458 |
+
// Setup local storage of files
|
459 |
+
self._defaultFileSchema = function () {
|
460 |
+
return {
|
461 |
+
content: self.settings.file.defaultContent
|
462 |
+
, created: new Date()
|
463 |
+
, modified: new Date()
|
464 |
+
}
|
465 |
+
}
|
466 |
+
|
467 |
+
if (localStorage && self.settings.clientSideStorage) {
|
468 |
+
this._storage = localStorage;
|
469 |
+
if (this._storage[self.settings.localStorageName] && self.getFiles(self.settings.file.name) === undefined) {
|
470 |
+
_defaultFile = self._defaultFileSchema();
|
471 |
+
_defaultFile.content = self.settings.file.defaultContent;
|
472 |
+
}
|
473 |
+
}
|
474 |
+
|
475 |
+
if (!this._storage[self.settings.localStorageName]) {
|
476 |
+
defaultStorage = {};
|
477 |
+
defaultStorage[self.settings.file.name] = self._defaultFileSchema();
|
478 |
+
defaultStorage = JSON.stringify(defaultStorage);
|
479 |
+
this._storage[self.settings.localStorageName] = defaultStorage;
|
480 |
+
}
|
481 |
+
|
482 |
+
// A string to prepend files with to save draft versions of files
|
483 |
+
// and reset all preview drafts on each load!
|
484 |
+
self._previewDraftLocation = '__draft-';
|
485 |
+
self._storage[self._previewDraftLocation + self.settings.localStorageName] = self._storage[self.settings.localStorageName];
|
486 |
+
|
487 |
+
// This needs to replace the use of classes to check the state of EE
|
488 |
+
self._eeState = {
|
489 |
+
fullscreen: false
|
490 |
+
, preview: false
|
491 |
+
, edit: false
|
492 |
+
, loaded: false
|
493 |
+
, unloaded: false
|
494 |
+
}
|
495 |
+
|
496 |
+
// Now that it exists, allow binding of events if it doesn't exist yet
|
497 |
+
if (!self.events) {
|
498 |
+
self.events = {};
|
499 |
+
}
|
500 |
+
|
501 |
+
return this;
|
502 |
+
}
|
503 |
+
|
504 |
+
/**
|
505 |
+
* Inserts the EpicEditor into the DOM via an iframe and gets it ready for editing and previewing
|
506 |
+
* @returns {object} EpicEditor will be returned
|
507 |
+
*/
|
508 |
+
EpicEditor.prototype.load = function (callback) {
|
509 |
+
|
510 |
+
// Get out early if it's already loaded
|
511 |
+
if (this.is('loaded')) { return this; }
|
512 |
+
|
513 |
+
// TODO: Gotta get the privates with underscores!
|
514 |
+
// TODO: Gotta document what these are for...
|
515 |
+
var self = this
|
516 |
+
, _HtmlTemplates
|
517 |
+
, iframeElement
|
518 |
+
, baseTag
|
519 |
+
, utilBtns
|
520 |
+
, utilBar
|
521 |
+
, utilBarTimer
|
522 |
+
, keypressTimer
|
523 |
+
, mousePos = { y: -1, x: -1 }
|
524 |
+
, _elementStates
|
525 |
+
, _isInEdit
|
526 |
+
, nativeFs = false
|
527 |
+
, nativeFsWebkit = false
|
528 |
+
, nativeFsMoz = false
|
529 |
+
, nativeFsW3C = false
|
530 |
+
, fsElement
|
531 |
+
, isMod = false
|
532 |
+
, isCtrl = false
|
533 |
+
, eventableIframes
|
534 |
+
, i // i is reused for loops
|
535 |
+
, boundAutogrow;
|
536 |
+
|
537 |
+
// Startup is a way to check if this EpicEditor is starting up. Useful for
|
538 |
+
// checking and doing certain things before EpicEditor emits a load event.
|
539 |
+
self._eeState.startup = true;
|
540 |
+
|
541 |
+
if (self.settings.useNativeFullscreen) {
|
542 |
+
nativeFsWebkit = document.body.webkitRequestFullScreen ? true : false;
|
543 |
+
nativeFsMoz = document.body.mozRequestFullScreen ? true : false;
|
544 |
+
nativeFsW3C = document.body.requestFullscreen ? true : false;
|
545 |
+
nativeFs = nativeFsWebkit || nativeFsMoz || nativeFsW3C;
|
546 |
+
}
|
547 |
+
|
548 |
+
// Fucking Safari's native fullscreen works terribly
|
549 |
+
// REMOVE THIS IF SAFARI 7 WORKS BETTER
|
550 |
+
if (_isSafari()) {
|
551 |
+
nativeFs = false;
|
552 |
+
nativeFsWebkit = false;
|
553 |
+
}
|
554 |
+
|
555 |
+
// It opens edit mode by default (for now);
|
556 |
+
if (!self.is('edit') && !self.is('preview')) {
|
557 |
+
self._eeState.edit = true;
|
558 |
+
}
|
559 |
+
|
560 |
+
callback = callback || function () {};
|
561 |
+
|
562 |
+
// The editor HTML
|
563 |
+
// TODO: edit-mode class should be dynamically added
|
564 |
+
_HtmlTemplates = {
|
565 |
+
// This is wrapping iframe element. It contains the other two iframes and the utilbar
|
566 |
+
chrome: '<div id="epiceditor-wrapper" class="epiceditor-edit-mode">' +
|
567 |
+
'<iframe frameborder="0" id="epiceditor-editor-frame"></iframe>' +
|
568 |
+
'<iframe frameborder="0" id="epiceditor-previewer-frame"></iframe>' +
|
569 |
+
'<div id="epiceditor-utilbar">' +
|
570 |
+
(self._previewEnabled ? '<button title="' + this.settings.string.togglePreview + '" class="epiceditor-toggle-btn epiceditor-toggle-preview-btn"></button> ' : '') +
|
571 |
+
(self._editEnabled ? '<button title="' + this.settings.string.toggleEdit + '" class="epiceditor-toggle-btn epiceditor-toggle-edit-btn"></button> ' : '') +
|
572 |
+
(self._fullscreenEnabled ? '<button title="' + this.settings.string.toggleFullscreen + '" class="epiceditor-fullscreen-btn"></button>' : '') +
|
573 |
+
'</div>' +
|
574 |
+
'</div>'
|
575 |
+
|
576 |
+
// The previewer is just an empty box for the generated HTML to go into
|
577 |
+
, previewer: '<div id="epiceditor-preview"></div>'
|
578 |
+
, editor: '<!doctype HTML>'
|
579 |
+
};
|
580 |
+
|
581 |
+
// Write an iframe and then select it for the editor
|
582 |
+
iframeElement = document.createElement('iframe');
|
583 |
+
_applyAttrs(iframeElement, {
|
584 |
+
scrolling: 'no',
|
585 |
+
frameborder: 0,
|
586 |
+
id: self._instanceId
|
587 |
+
});
|
588 |
+
|
589 |
+
|
590 |
+
self.element.appendChild(iframeElement);
|
591 |
+
|
592 |
+
// Because browsers add things like invisible padding and margins and stuff
|
593 |
+
// to iframes, we need to set manually set the height so that the height
|
594 |
+
// doesn't keep increasing (by 2px?) every time reflow() is called.
|
595 |
+
// FIXME: Figure out how to fix this without setting this
|
596 |
+
self.element.style.height = self.element.offsetHeight + 'px';
|
597 |
+
|
598 |
+
// Store a reference to the iframeElement itself
|
599 |
+
self.iframeElement = iframeElement;
|
600 |
+
|
601 |
+
// Grab the innards of the iframe (returns the document.body)
|
602 |
+
// TODO: Change self.iframe to self.iframeDocument
|
603 |
+
self.iframe = _getIframeInnards(iframeElement);
|
604 |
+
self.iframe.open();
|
605 |
+
self.iframe.write(_HtmlTemplates.chrome);
|
606 |
+
|
607 |
+
// Now that we got the innards of the iframe, we can grab the other iframes
|
608 |
+
self.editorIframe = self.iframe.getElementById('epiceditor-editor-frame')
|
609 |
+
self.previewerIframe = self.iframe.getElementById('epiceditor-previewer-frame');
|
610 |
+
|
611 |
+
// Setup the editor iframe
|
612 |
+
self.editorIframeDocument = _getIframeInnards(self.editorIframe);
|
613 |
+
self.editorIframeDocument.open();
|
614 |
+
// Need something for... you guessed it, Firefox
|
615 |
+
self.editorIframeDocument.write(_HtmlTemplates.editor);
|
616 |
+
self.editorIframeDocument.close();
|
617 |
+
|
618 |
+
// Setup the previewer iframe
|
619 |
+
self.previewerIframeDocument = _getIframeInnards(self.previewerIframe);
|
620 |
+
self.previewerIframeDocument.open();
|
621 |
+
self.previewerIframeDocument.write(_HtmlTemplates.previewer);
|
622 |
+
|
623 |
+
// Base tag is added so that links will open a new tab and not inside of the iframes
|
624 |
+
baseTag = self.previewerIframeDocument.createElement('base');
|
625 |
+
baseTag.target = '_blank';
|
626 |
+
self.previewerIframeDocument.getElementsByTagName('head')[0].appendChild(baseTag);
|
627 |
+
|
628 |
+
self.previewerIframeDocument.close();
|
629 |
+
|
630 |
+
self.reflow();
|
631 |
+
|
632 |
+
// Insert Base Stylesheet
|
633 |
+
_insertCSSLink(self.settings.theme.base, self.iframe, 'theme');
|
634 |
+
|
635 |
+
// Insert Editor Stylesheet
|
636 |
+
_insertCSSLink(self.settings.theme.editor, self.editorIframeDocument, 'theme');
|
637 |
+
|
638 |
+
// Insert Previewer Stylesheet
|
639 |
+
_insertCSSLink(self.settings.theme.preview, self.previewerIframeDocument, 'theme');
|
640 |
+
|
641 |
+
// Add a relative style to the overall wrapper to keep CSS relative to the editor
|
642 |
+
self.iframe.getElementById('epiceditor-wrapper').style.position = 'relative';
|
643 |
+
|
644 |
+
// Set the position to relative so we hide them with left: -999999px
|
645 |
+
self.editorIframe.style.position = 'absolute';
|
646 |
+
self.previewerIframe.style.position = 'absolute';
|
647 |
+
|
648 |
+
// Now grab the editor and previewer for later use
|
649 |
+
self.editor = self.editorIframeDocument.body;
|
650 |
+
self.previewer = self.previewerIframeDocument.getElementById('epiceditor-preview');
|
651 |
+
|
652 |
+
self.editor.contentEditable = true;
|
653 |
+
|
654 |
+
// Firefox's <body> gets all fucked up so, to be sure, we need to hardcode it
|
655 |
+
self.iframe.body.style.height = this.element.offsetHeight + 'px';
|
656 |
+
|
657 |
+
// Should actually check what mode it's in!
|
658 |
+
self.previewerIframe.style.left = '-999999px';
|
659 |
+
|
660 |
+
// Keep long lines from being longer than the editor
|
661 |
+
this.editorIframeDocument.body.style.wordWrap = 'break-word';
|
662 |
+
|
663 |
+
// FIXME figure out why it needs +2 px
|
664 |
+
if (_isIE() > -1) {
|
665 |
+
this.previewer.style.height = parseInt(_getStyle(this.previewer, 'height'), 10) + 2;
|
666 |
+
}
|
667 |
+
|
668 |
+
// If there is a file to be opened with that filename and it has content...
|
669 |
+
this.open(self.settings.file.name);
|
670 |
+
|
671 |
+
if (self.settings.focusOnLoad) {
|
672 |
+
// We need to wait until all three iframes are done loading by waiting until the parent
|
673 |
+
// iframe's ready state == complete, then we can focus on the contenteditable
|
674 |
+
self.iframe.addEventListener('readystatechange', function () {
|
675 |
+
if (self.iframe.readyState == 'complete') {
|
676 |
+
self.focus();
|
677 |
+
}
|
678 |
+
});
|
679 |
+
}
|
680 |
+
|
681 |
+
// Because IE scrolls the whole window to hash links, we need our own
|
682 |
+
// method of scrolling the iframe to an ID from clicking a hash
|
683 |
+
self.previewerIframeDocument.addEventListener('click', function (e) {
|
684 |
+
var el = e.target
|
685 |
+
, body = self.previewerIframeDocument.body;
|
686 |
+
if (el.nodeName == 'A') {
|
687 |
+
// Make sure the link is a hash and the link is local to the iframe
|
688 |
+
if (el.hash && el.hostname == window.location.hostname) {
|
689 |
+
// Prevent the whole window from scrolling
|
690 |
+
e.preventDefault();
|
691 |
+
// Prevent opening a new window
|
692 |
+
el.target = '_self';
|
693 |
+
// Scroll to the matching element, if an element exists
|
694 |
+
if (body.querySelector(el.hash)) {
|
695 |
+
body.scrollTop = body.querySelector(el.hash).offsetTop;
|
696 |
+
}
|
697 |
+
}
|
698 |
+
}
|
699 |
+
});
|
700 |
+
|
701 |
+
utilBtns = self.iframe.getElementById('epiceditor-utilbar');
|
702 |
+
|
703 |
+
// TODO: Move into fullscreen setup function (_setupFullscreen)
|
704 |
+
_elementStates = {}
|
705 |
+
self._goFullscreen = function (el, callback) {
|
706 |
+
callback = callback || function () {};
|
707 |
+
var wait = 0;
|
708 |
+
this._fixScrollbars('auto');
|
709 |
+
|
710 |
+
if (self.is('fullscreen')) {
|
711 |
+
self._exitFullscreen(el, callback);
|
712 |
+
return;
|
713 |
+
}
|
714 |
+
|
715 |
+
if (nativeFs) {
|
716 |
+
if (nativeFsWebkit) {
|
717 |
+
el.webkitRequestFullScreen();
|
718 |
+
wait = 750;
|
719 |
+
}
|
720 |
+
else if (nativeFsMoz) {
|
721 |
+
el.mozRequestFullScreen();
|
722 |
+
}
|
723 |
+
else if (nativeFsW3C) {
|
724 |
+
el.requestFullscreen();
|
725 |
+
}
|
726 |
+
}
|
727 |
+
|
728 |
+
_isInEdit = self.is('edit');
|
729 |
+
|
730 |
+
|
731 |
+
// Why does this need to be in a randomly "750"ms setTimeout? WebKit's
|
732 |
+
// implementation of fullscreen seem to trigger the webkitfullscreenchange
|
733 |
+
// event _after_ everything is done. Instead, it triggers _during_ the
|
734 |
+
// transition. This means calculations of what's half, 100%, etc are wrong
|
735 |
+
// so to combat this we throw down the hammer with a setTimeout and wait
|
736 |
+
// to trigger our calculation code.
|
737 |
+
// See: https://code.google.com/p/chromium/issues/detail?id=181116
|
738 |
+
setTimeout(function () {
|
739 |
+
// Set the state of EE in fullscreen
|
740 |
+
// We set edit and preview to true also because they're visible
|
741 |
+
// we might want to allow fullscreen edit mode without preview (like a "zen" mode)
|
742 |
+
self._eeState.fullscreen = true;
|
743 |
+
self._eeState.edit = true;
|
744 |
+
self._eeState.preview = true;
|
745 |
+
|
746 |
+
// Cache calculations
|
747 |
+
var windowInnerWidth = window.innerWidth
|
748 |
+
, windowInnerHeight = window.innerHeight
|
749 |
+
, windowOuterWidth = window.outerWidth
|
750 |
+
, windowOuterHeight = window.outerHeight;
|
751 |
+
|
752 |
+
// Without this the scrollbars will get hidden when scrolled to the bottom in faux fullscreen (see #66)
|
753 |
+
if (!nativeFs) {
|
754 |
+
windowOuterHeight = window.innerHeight;
|
755 |
+
}
|
756 |
+
|
757 |
+
// This MUST come first because the editor is 100% width so if we change the width of the iframe or wrapper
|
758 |
+
// the editor's width wont be the same as before
|
759 |
+
_elementStates.editorIframe = _saveStyleState(self.editorIframe, 'save', {
|
760 |
+
'width': windowOuterWidth / 2 + 'px'
|
761 |
+
, 'height': windowOuterHeight + 'px'
|
762 |
+
, 'float': 'left' // Most browsers
|
763 |
+
, 'cssFloat': 'left' // FF
|
764 |
+
, 'styleFloat': 'left' // Older IEs
|
765 |
+
, 'display': 'block'
|
766 |
+
, 'position': 'static'
|
767 |
+
, 'left': ''
|
768 |
+
});
|
769 |
+
|
770 |
+
// the previewer
|
771 |
+
_elementStates.previewerIframe = _saveStyleState(self.previewerIframe, 'save', {
|
772 |
+
'width': windowOuterWidth / 2 + 'px'
|
773 |
+
, 'height': windowOuterHeight + 'px'
|
774 |
+
, 'float': 'right' // Most browsers
|
775 |
+
, 'cssFloat': 'right' // FF
|
776 |
+
, 'styleFloat': 'right' // Older IEs
|
777 |
+
, 'display': 'block'
|
778 |
+
, 'position': 'static'
|
779 |
+
, 'left': ''
|
780 |
+
});
|
781 |
+
|
782 |
+
// Setup the containing element CSS for fullscreen
|
783 |
+
_elementStates.element = _saveStyleState(self.element, 'save', {
|
784 |
+
'position': 'fixed'
|
785 |
+
, 'top': '0'
|
786 |
+
, 'left': '0'
|
787 |
+
, 'width': '100%'
|
788 |
+
, 'z-index': '9999' // Most browsers
|
789 |
+
, 'zIndex': '9999' // Firefox
|
790 |
+
, 'border': 'none'
|
791 |
+
, 'margin': '0'
|
792 |
+
// Should use the base styles background!
|
793 |
+
, 'background': _getStyle(self.editor, 'background-color') // Try to hide the site below
|
794 |
+
, 'height': windowInnerHeight + 'px'
|
795 |
+
});
|
796 |
+
|
797 |
+
// The iframe element
|
798 |
+
_elementStates.iframeElement = _saveStyleState(self.iframeElement, 'save', {
|
799 |
+
'width': windowOuterWidth + 'px'
|
800 |
+
, 'height': windowInnerHeight + 'px'
|
801 |
+
});
|
802 |
+
|
803 |
+
// ...Oh, and hide the buttons and prevent scrolling
|
804 |
+
utilBtns.style.visibility = 'hidden';
|
805 |
+
|
806 |
+
if (!nativeFs) {
|
807 |
+
document.body.style.overflow = 'hidden';
|
808 |
+
}
|
809 |
+
|
810 |
+
self.preview();
|
811 |
+
|
812 |
+
self.focus();
|
813 |
+
|
814 |
+
self.emit('fullscreenenter');
|
815 |
+
|
816 |
+
callback.call(self);
|
817 |
+
}, wait);
|
818 |
+
|
819 |
+
};
|
820 |
+
|
821 |
+
self._exitFullscreen = function (el, callback) {
|
822 |
+
callback = callback || function () {};
|
823 |
+
this._fixScrollbars();
|
824 |
+
|
825 |
+
_saveStyleState(self.element, 'apply', _elementStates.element);
|
826 |
+
_saveStyleState(self.iframeElement, 'apply', _elementStates.iframeElement);
|
827 |
+
_saveStyleState(self.editorIframe, 'apply', _elementStates.editorIframe);
|
828 |
+
_saveStyleState(self.previewerIframe, 'apply', _elementStates.previewerIframe);
|
829 |
+
|
830 |
+
// We want to always revert back to the original styles in the CSS so,
|
831 |
+
// if it's a fluid width container it will expand on resize and not get
|
832 |
+
// stuck at a specific width after closing fullscreen.
|
833 |
+
self.element.style.width = self._eeState.reflowWidth ? self._eeState.reflowWidth : '';
|
834 |
+
self.element.style.height = self._eeState.reflowHeight ? self._eeState.reflowHeight : '';
|
835 |
+
|
836 |
+
utilBtns.style.visibility = 'visible';
|
837 |
+
|
838 |
+
// Put the editor back in the right state
|
839 |
+
// TODO: This is ugly... how do we make this nicer?
|
840 |
+
// setting fullscreen to false here prevents the
|
841 |
+
// native fs callback from calling this function again
|
842 |
+
self._eeState.fullscreen = false;
|
843 |
+
|
844 |
+
if (!nativeFs) {
|
845 |
+
document.body.style.overflow = 'auto';
|
846 |
+
}
|
847 |
+
else {
|
848 |
+
if (nativeFsWebkit) {
|
849 |
+
document.webkitCancelFullScreen();
|
850 |
+
}
|
851 |
+
else if (nativeFsMoz) {
|
852 |
+
document.mozCancelFullScreen();
|
853 |
+
}
|
854 |
+
else if (nativeFsW3C) {
|
855 |
+
document.exitFullscreen();
|
856 |
+
}
|
857 |
+
}
|
858 |
+
|
859 |
+
if (_isInEdit) {
|
860 |
+
self.edit();
|
861 |
+
}
|
862 |
+
else {
|
863 |
+
self.preview();
|
864 |
+
}
|
865 |
+
|
866 |
+
self.reflow();
|
867 |
+
|
868 |
+
self.emit('fullscreenexit');
|
869 |
+
|
870 |
+
callback.call(self);
|
871 |
+
};
|
872 |
+
|
873 |
+
// This setups up live previews by triggering preview() IF in fullscreen on keyup
|
874 |
+
self.editor.addEventListener('keyup', function () {
|
875 |
+
if (keypressTimer) {
|
876 |
+
window.clearTimeout(keypressTimer);
|
877 |
+
}
|
878 |
+
keypressTimer = window.setTimeout(function () {
|
879 |
+
if (self.is('fullscreen')) {
|
880 |
+
self.preview();
|
881 |
+
}
|
882 |
+
}, 250);
|
883 |
+
});
|
884 |
+
|
885 |
+
fsElement = self.iframeElement;
|
886 |
+
|
887 |
+
// Sets up the onclick event on utility buttons
|
888 |
+
utilBtns.addEventListener('click', function (e) {
|
889 |
+
var targetClass = e.target.className;
|
890 |
+
if (targetClass.indexOf('epiceditor-toggle-preview-btn') > -1) {
|
891 |
+
self.preview();
|
892 |
+
}
|
893 |
+
else if (targetClass.indexOf('epiceditor-toggle-edit-btn') > -1) {
|
894 |
+
self.edit();
|
895 |
+
}
|
896 |
+
else if (targetClass.indexOf('epiceditor-fullscreen-btn') > -1) {
|
897 |
+
self._goFullscreen(fsElement);
|
898 |
+
}
|
899 |
+
});
|
900 |
+
|
901 |
+
// Sets up the NATIVE fullscreen editor/previewer for WebKit
|
902 |
+
if (nativeFsWebkit) {
|
903 |
+
document.addEventListener('webkitfullscreenchange', function () {
|
904 |
+
if (!document.webkitIsFullScreen && self._eeState.fullscreen) {
|
905 |
+
self._exitFullscreen(fsElement);
|
906 |
+
}
|
907 |
+
}, false);
|
908 |
+
}
|
909 |
+
else if (nativeFsMoz) {
|
910 |
+
document.addEventListener('mozfullscreenchange', function () {
|
911 |
+
if (!document.mozFullScreen && self._eeState.fullscreen) {
|
912 |
+
self._exitFullscreen(fsElement);
|
913 |
+
}
|
914 |
+
}, false);
|
915 |
+
}
|
916 |
+
else if (nativeFsW3C) {
|
917 |
+
document.addEventListener('fullscreenchange', function () {
|
918 |
+
if (document.fullscreenElement == null && self._eeState.fullscreen) {
|
919 |
+
self._exitFullscreen(fsElement);
|
920 |
+
}
|
921 |
+
}, false);
|
922 |
+
}
|
923 |
+
|
924 |
+
// TODO: Move utilBar stuff into a utilBar setup function (_setupUtilBar)
|
925 |
+
utilBar = self.iframe.getElementById('epiceditor-utilbar');
|
926 |
+
|
927 |
+
// Hide it at first until they move their mouse
|
928 |
+
if (self.settings.button.bar !== true) {
|
929 |
+
utilBar.style.display = 'none';
|
930 |
+
}
|
931 |
+
|
932 |
+
utilBar.addEventListener('mouseover', function () {
|
933 |
+
if (utilBarTimer) {
|
934 |
+
clearTimeout(utilBarTimer);
|
935 |
+
}
|
936 |
+
});
|
937 |
+
|
938 |
+
function utilBarHandler(e) {
|
939 |
+
if (self.settings.button.bar !== "auto") {
|
940 |
+
return;
|
941 |
+
}
|
942 |
+
// Here we check if the mouse has moves more than 5px in any direction before triggering the mousemove code
|
943 |
+
// we do this for 2 reasons:
|
944 |
+
// 1. On Mac OS X lion when you scroll and it does the iOS like "jump" when it hits the top/bottom of the page itll fire off
|
945 |
+
// a mousemove of a few pixels depending on how hard you scroll
|
946 |
+
// 2. We give a slight buffer to the user in case he barely touches his touchpad or mouse and not trigger the UI
|
947 |
+
if (Math.abs(mousePos.y - e.pageY) >= 5 || Math.abs(mousePos.x - e.pageX) >= 5) {
|
948 |
+
utilBar.style.display = 'block';
|
949 |
+
// if we have a timer already running, kill it out
|
950 |
+
if (utilBarTimer) {
|
951 |
+
clearTimeout(utilBarTimer);
|
952 |
+
}
|
953 |
+
|
954 |
+
// begin a new timer that hides our object after 1000 ms
|
955 |
+
utilBarTimer = window.setTimeout(function () {
|
956 |
+
utilBar.style.display = 'none';
|
957 |
+
}, 1000);
|
958 |
+
}
|
959 |
+
mousePos = { y: e.pageY, x: e.pageX };
|
960 |
+
}
|
961 |
+
|
962 |
+
// Add keyboard shortcuts for convenience.
|
963 |
+
function shortcutHandler(e) {
|
964 |
+
if (e.keyCode == self.settings.shortcut.modifier) { isMod = true } // check for modifier press(default is alt key), save to var
|
965 |
+
if (e.keyCode == 17) { isCtrl = true } // check for ctrl/cmnd press, in order to catch ctrl/cmnd + s
|
966 |
+
|
967 |
+
// Check for alt+p and make sure were not in fullscreen - default shortcut to switch to preview
|
968 |
+
if (isMod === true && e.keyCode == self.settings.shortcut.preview && !self.is('fullscreen')) {
|
969 |
+
e.preventDefault();
|
970 |
+
if (self.is('edit') && self._previewEnabled) {
|
971 |
+
self.preview();
|
972 |
+
}
|
973 |
+
else if (self._editEnabled) {
|
974 |
+
self.edit();
|
975 |
+
}
|
976 |
+
}
|
977 |
+
// Check for alt+f - default shortcut to make editor fullscreen
|
978 |
+
if (isMod === true && e.keyCode == self.settings.shortcut.fullscreen && self._fullscreenEnabled) {
|
979 |
+
e.preventDefault();
|
980 |
+
self._goFullscreen(fsElement);
|
981 |
+
}
|
982 |
+
|
983 |
+
// Set the modifier key to false once *any* key combo is completed
|
984 |
+
// or else, on Windows, hitting the alt key will lock the isMod state to true (ticket #133)
|
985 |
+
if (isMod === true && e.keyCode !== self.settings.shortcut.modifier) {
|
986 |
+
isMod = false;
|
987 |
+
}
|
988 |
+
|
989 |
+
// When a user presses "esc", revert everything!
|
990 |
+
if (e.keyCode == 27 && self.is('fullscreen')) {
|
991 |
+
self._exitFullscreen(fsElement);
|
992 |
+
}
|
993 |
+
|
994 |
+
// Check for ctrl + s (since a lot of people do it out of habit) and make it do nothing
|
995 |
+
if (isCtrl === true && e.keyCode == 83) {
|
996 |
+
self.save();
|
997 |
+
e.preventDefault();
|
998 |
+
isCtrl = false;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
// Do the same for Mac now (metaKey == cmd).
|
1002 |
+
if (e.metaKey && e.keyCode == 83) {
|
1003 |
+
self.save();
|
1004 |
+
e.preventDefault();
|
1005 |
+
}
|
1006 |
+
|
1007 |
+
}
|
1008 |
+
|
1009 |
+
function shortcutUpHandler(e) {
|
1010 |
+
if (e.keyCode == self.settings.shortcut.modifier) { isMod = false }
|
1011 |
+
if (e.keyCode == 17) { isCtrl = false }
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
function pasteHandler(e) {
|
1015 |
+
var content;
|
1016 |
+
if (e.clipboardData) {
|
1017 |
+
//FF 22, Webkit, "standards"
|
1018 |
+
e.preventDefault();
|
1019 |
+
content = e.clipboardData.getData("text/plain");
|
1020 |
+
self.editorIframeDocument.execCommand("insertText", false, content);
|
1021 |
+
}
|
1022 |
+
else if (window.clipboardData) {
|
1023 |
+
//IE, "nasty"
|
1024 |
+
e.preventDefault();
|
1025 |
+
content = window.clipboardData.getData("Text");
|
1026 |
+
content = content.replace(/</g, '<');
|
1027 |
+
content = content.replace(/>/g, '>');
|
1028 |
+
content = content.replace(/\n/g, '<br>');
|
1029 |
+
content = content.replace(/\r/g, ''); //fuck you, ie!
|
1030 |
+
content = content.replace(/<br>\s/g, '<br> ')
|
1031 |
+
content = content.replace(/\s\s\s/g, ' ')
|
1032 |
+
content = content.replace(/\s\s/g, ' ')
|
1033 |
+
self.editorIframeDocument.selection.createRange().pasteHTML(content);
|
1034 |
+
}
|
1035 |
+
}
|
1036 |
+
|
1037 |
+
// Hide and show the util bar based on mouse movements
|
1038 |
+
eventableIframes = [self.previewerIframeDocument, self.editorIframeDocument];
|
1039 |
+
|
1040 |
+
for (i = 0; i < eventableIframes.length; i++) {
|
1041 |
+
eventableIframes[i].addEventListener('mousemove', function (e) {
|
1042 |
+
utilBarHandler(e);
|
1043 |
+
});
|
1044 |
+
eventableIframes[i].addEventListener('scroll', function (e) {
|
1045 |
+
utilBarHandler(e);
|
1046 |
+
});
|
1047 |
+
eventableIframes[i].addEventListener('keyup', function (e) {
|
1048 |
+
shortcutUpHandler(e);
|
1049 |
+
});
|
1050 |
+
eventableIframes[i].addEventListener('keydown', function (e) {
|
1051 |
+
shortcutHandler(e);
|
1052 |
+
});
|
1053 |
+
eventableIframes[i].addEventListener('paste', function (e) {
|
1054 |
+
pasteHandler(e);
|
1055 |
+
});
|
1056 |
+
}
|
1057 |
+
|
1058 |
+
// Save the document every 100ms by default
|
1059 |
+
// TODO: Move into autosave setup function (_setupAutoSave)
|
1060 |
+
if (self.settings.file.autoSave) {
|
1061 |
+
self._saveIntervalTimer = window.setInterval(function () {
|
1062 |
+
if (!self._canSave) {
|
1063 |
+
return;
|
1064 |
+
}
|
1065 |
+
self.save(false, true);
|
1066 |
+
}, self.settings.file.autoSave);
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
// Update a textarea automatically if a textarea is given so you don't need
|
1070 |
+
// AJAX to submit a form and instead fall back to normal form behavior
|
1071 |
+
if (self.settings.textarea) {
|
1072 |
+
self._setupTextareaSync();
|
1073 |
+
}
|
1074 |
+
|
1075 |
+
window.addEventListener('resize', function () {
|
1076 |
+
// If NOT webkit, and in fullscreen, we need to account for browser resizing
|
1077 |
+
// we don't care about webkit because you can't resize in webkit's fullscreen
|
1078 |
+
if (self.is('fullscreen')) {
|
1079 |
+
_applyStyles(self.iframeElement, {
|
1080 |
+
'width': window.outerWidth + 'px'
|
1081 |
+
, 'height': window.innerHeight + 'px'
|
1082 |
+
});
|
1083 |
+
|
1084 |
+
_applyStyles(self.element, {
|
1085 |
+
'height': window.innerHeight + 'px'
|
1086 |
+
});
|
1087 |
+
|
1088 |
+
_applyStyles(self.previewerIframe, {
|
1089 |
+
'width': window.outerWidth / 2 + 'px'
|
1090 |
+
, 'height': window.innerHeight + 'px'
|
1091 |
+
});
|
1092 |
+
|
1093 |
+
_applyStyles(self.editorIframe, {
|
1094 |
+
'width': window.outerWidth / 2 + 'px'
|
1095 |
+
, 'height': window.innerHeight + 'px'
|
1096 |
+
});
|
1097 |
+
}
|
1098 |
+
// Makes the editor support fluid width when not in fullscreen mode
|
1099 |
+
else if (!self.is('fullscreen')) {
|
1100 |
+
self.reflow();
|
1101 |
+
}
|
1102 |
+
});
|
1103 |
+
|
1104 |
+
// Set states before flipping edit and preview modes
|
1105 |
+
self._eeState.loaded = true;
|
1106 |
+
self._eeState.unloaded = false;
|
1107 |
+
|
1108 |
+
if (self.is('preview')) {
|
1109 |
+
self.preview();
|
1110 |
+
}
|
1111 |
+
else {
|
1112 |
+
self.edit();
|
1113 |
+
}
|
1114 |
+
|
1115 |
+
self.iframe.close();
|
1116 |
+
self._eeState.startup = false;
|
1117 |
+
|
1118 |
+
if (self.settings.autogrow) {
|
1119 |
+
self._fixScrollbars();
|
1120 |
+
|
1121 |
+
boundAutogrow = function () {
|
1122 |
+
setTimeout(function () {
|
1123 |
+
self._autogrow();
|
1124 |
+
}, 1);
|
1125 |
+
};
|
1126 |
+
|
1127 |
+
//for if autosave is disabled or very slow
|
1128 |
+
['keydown', 'keyup', 'paste', 'cut'].forEach(function (ev) {
|
1129 |
+
self.getElement('editor').addEventListener(ev, boundAutogrow);
|
1130 |
+
});
|
1131 |
+
|
1132 |
+
self.on('__update', boundAutogrow);
|
1133 |
+
self.on('edit', function () {
|
1134 |
+
setTimeout(boundAutogrow, 50)
|
1135 |
+
});
|
1136 |
+
self.on('preview', function () {
|
1137 |
+
setTimeout(boundAutogrow, 50)
|
1138 |
+
});
|
1139 |
+
|
1140 |
+
//for browsers that have rendering delays
|
1141 |
+
setTimeout(boundAutogrow, 50);
|
1142 |
+
boundAutogrow();
|
1143 |
+
}
|
1144 |
+
|
1145 |
+
// The callback and call are the same thing, but different ways to access them
|
1146 |
+
callback.call(this);
|
1147 |
+
this.emit('load');
|
1148 |
+
return this;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
EpicEditor.prototype._setupTextareaSync = function () {
|
1152 |
+
var self = this
|
1153 |
+
, _syncTextarea;
|
1154 |
+
|
1155 |
+
// Even if autoSave is false, we want to make sure to keep the textarea synced
|
1156 |
+
// with the editor's content. One bad thing about this tho is that we're
|
1157 |
+
// creating two timers now in some configurations. We keep the textarea synced
|
1158 |
+
// by saving and opening the textarea content from the draft file storage.
|
1159 |
+
self._textareaSaveTimer = window.setInterval(function () {
|
1160 |
+
if (!self._canSave) {
|
1161 |
+
return;
|
1162 |
+
}
|
1163 |
+
self.save(true);
|
1164 |
+
}, 100);
|
1165 |
+
|
1166 |
+
_syncTextarea = function () {
|
1167 |
+
// TODO: Figure out root cause for having to do this ||.
|
1168 |
+
// This only happens for draft files. Probably has something to do with
|
1169 |
+
// the fact draft files haven't been saved by the time this is called.
|
1170 |
+
// TODO: Add test for this case.
|
1171 |
+
// Get the file.name each time as it can change. DO NOT save this to a
|
1172 |
+
// var outside of this closure or the editor will stop syncing when the
|
1173 |
+
// file is changed with importFile or open.
|
1174 |
+
self._textareaElement.value = self.exportFile(self.settings.file.name, 'text', true) || self.settings.file.defaultContent;
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
if (typeof self.settings.textarea == 'string') {
|
1178 |
+
self._textareaElement = document.getElementById(self.settings.textarea);
|
1179 |
+
}
|
1180 |
+
else if (typeof self.settings.textarea == 'object') {
|
1181 |
+
self._textareaElement = self.settings.textarea;
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
// On page load, if there's content in the textarea that means one of two
|
1185 |
+
// different things:
|
1186 |
+
//
|
1187 |
+
// 1. The editor didn't load and the user was writing in the textarea and
|
1188 |
+
// now he refreshed the page or the JS loaded and the textarea now has
|
1189 |
+
// content. If this is the case the user probably expects his content is
|
1190 |
+
// moved into the editor and not lose what he typed.
|
1191 |
+
//
|
1192 |
+
// 2. The developer put content in the textarea from some server side
|
1193 |
+
// code. In this case, the textarea will take precedence.
|
1194 |
+
//
|
1195 |
+
// If the developer wants drafts to be recoverable they should check if
|
1196 |
+
// the local file in localStorage's modified date is newer than the server.
|
1197 |
+
if (self._textareaElement.value !== '') {
|
1198 |
+
self.importFile(self.settings.file.name, self._textareaElement.value);
|
1199 |
+
|
1200 |
+
// manually save draft after import so there is no delay between the
|
1201 |
+
// import and exporting in _syncTextarea. Without this, _syncTextarea
|
1202 |
+
// will pull the saved data from localStorage which will be <=100ms old.
|
1203 |
+
self.save(true);
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
// Update the textarea on load and pull from drafts
|
1207 |
+
_syncTextarea();
|
1208 |
+
|
1209 |
+
// Make sure to keep it updated
|
1210 |
+
self.on('__update', _syncTextarea);
|
1211 |
+
self.on('__create', _syncTextarea);
|
1212 |
+
self.on('__save', _syncTextarea);
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
/**
|
1216 |
+
* Will NOT focus the editor if the editor is still starting up AND
|
1217 |
+
* focusOnLoad is set to false. This allows you to place this in code that
|
1218 |
+
* gets fired during .load() without worrying about it overriding the user's
|
1219 |
+
* option. For example use cases see preview() and edit().
|
1220 |
+
* @returns {undefined}
|
1221 |
+
*/
|
1222 |
+
|
1223 |
+
// Prevent focus when the user sets focusOnLoad to false by checking if the
|
1224 |
+
// editor is starting up AND if focusOnLoad is true
|
1225 |
+
EpicEditor.prototype._focusExceptOnLoad = function () {
|
1226 |
+
var self = this;
|
1227 |
+
if ((self._eeState.startup && self.settings.focusOnLoad) || !self._eeState.startup) {
|
1228 |
+
self.focus();
|
1229 |
+
}
|
1230 |
+
}
|
1231 |
+
|
1232 |
+
/**
|
1233 |
+
* Will remove the editor, but not offline files
|
1234 |
+
* @returns {object} EpicEditor will be returned
|
1235 |
+
*/
|
1236 |
+
EpicEditor.prototype.unload = function (callback) {
|
1237 |
+
|
1238 |
+
// Make sure the editor isn't already unloaded.
|
1239 |
+
if (this.is('unloaded')) {
|
1240 |
+
throw new Error('Editor isn\'t loaded');
|
1241 |
+
}
|
1242 |
+
|
1243 |
+
var self = this
|
1244 |
+
, editor = window.parent.document.getElementById(self._instanceId);
|
1245 |
+
|
1246 |
+
editor.parentNode.removeChild(editor);
|
1247 |
+
self._eeState.loaded = false;
|
1248 |
+
self._eeState.unloaded = true;
|
1249 |
+
callback = callback || function () {};
|
1250 |
+
|
1251 |
+
if (self.settings.textarea) {
|
1252 |
+
self.removeListener('__update');
|
1253 |
+
}
|
1254 |
+
|
1255 |
+
if (self._saveIntervalTimer) {
|
1256 |
+
window.clearInterval(self._saveIntervalTimer);
|
1257 |
+
}
|
1258 |
+
if (self._textareaSaveTimer) {
|
1259 |
+
window.clearInterval(self._textareaSaveTimer);
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
callback.call(this);
|
1263 |
+
self.emit('unload');
|
1264 |
+
return self;
|
1265 |
+
}
|
1266 |
+
|
1267 |
+
/**
|
1268 |
+
* reflow allows you to dynamically re-fit the editor in the parent without
|
1269 |
+
* having to unload and then reload the editor again.
|
1270 |
+
*
|
1271 |
+
* reflow will also emit a `reflow` event and will return the new dimensions.
|
1272 |
+
* If it's called without params it'll return the new width and height and if
|
1273 |
+
* it's called with just width or just height it'll just return the width or
|
1274 |
+
* height. It's returned as an object like: { width: '100px', height: '1px' }
|
1275 |
+
*
|
1276 |
+
* @param {string|null} kind Can either be 'width' or 'height' or null
|
1277 |
+
* if null, both the height and width will be resized
|
1278 |
+
* @param {function} callback A function to fire after the reflow is finished.
|
1279 |
+
* Will return the width / height in an obj as the first param of the callback.
|
1280 |
+
* @returns {object} EpicEditor will be returned
|
1281 |
+
*/
|
1282 |
+
EpicEditor.prototype.reflow = function (kind, callback) {
|
1283 |
+
var self = this
|
1284 |
+
, widthDiff = _outerWidth(self.element) - self.element.offsetWidth
|
1285 |
+
, heightDiff = _outerHeight(self.element) - self.element.offsetHeight
|
1286 |
+
, elements = [self.iframeElement, self.editorIframe, self.previewerIframe]
|
1287 |
+
, eventData = {}
|
1288 |
+
, newWidth
|
1289 |
+
, newHeight;
|
1290 |
+
|
1291 |
+
if (typeof kind == 'function') {
|
1292 |
+
callback = kind;
|
1293 |
+
kind = null;
|
1294 |
+
}
|
1295 |
+
|
1296 |
+
if (!callback) {
|
1297 |
+
callback = function () {};
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
for (var x = 0; x < elements.length; x++) {
|
1301 |
+
if (!kind || kind == 'width') {
|
1302 |
+
newWidth = self.element.offsetWidth - widthDiff + 'px';
|
1303 |
+
elements[x].style.width = newWidth;
|
1304 |
+
self._eeState.reflowWidth = newWidth;
|
1305 |
+
eventData.width = newWidth;
|
1306 |
+
}
|
1307 |
+
if (!kind || kind == 'height') {
|
1308 |
+
newHeight = self.element.offsetHeight - heightDiff + 'px';
|
1309 |
+
elements[x].style.height = newHeight;
|
1310 |
+
self._eeState.reflowHeight = newHeight
|
1311 |
+
eventData.height = newHeight;
|
1312 |
+
}
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
self.emit('reflow', eventData);
|
1316 |
+
callback.call(this, eventData);
|
1317 |
+
return self;
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
/**
|
1321 |
+
* Will take the markdown and generate a preview view based on the theme
|
1322 |
+
* @returns {object} EpicEditor will be returned
|
1323 |
+
*/
|
1324 |
+
EpicEditor.prototype.preview = function () {
|
1325 |
+
var self = this
|
1326 |
+
, x
|
1327 |
+
, theme = self.settings.theme.preview
|
1328 |
+
, anchors;
|
1329 |
+
|
1330 |
+
_replaceClass(self.getElement('wrapper'), 'epiceditor-edit-mode', 'epiceditor-preview-mode');
|
1331 |
+
|
1332 |
+
// Check if no CSS theme link exists
|
1333 |
+
if (!self.previewerIframeDocument.getElementById('theme')) {
|
1334 |
+
_insertCSSLink(theme, self.previewerIframeDocument, 'theme');
|
1335 |
+
}
|
1336 |
+
else if (self.previewerIframeDocument.getElementById('theme').name !== theme) {
|
1337 |
+
self.previewerIframeDocument.getElementById('theme').href = theme;
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
// Save a preview draft since it might not be saved to the real file yet
|
1341 |
+
self.save(true);
|
1342 |
+
|
1343 |
+
// Add the generated draft HTML into the previewer
|
1344 |
+
self.previewer.innerHTML = self.exportFile(null, 'html', true);
|
1345 |
+
|
1346 |
+
// Hide the editor and display the previewer
|
1347 |
+
if (!self.is('fullscreen')) {
|
1348 |
+
self.editorIframe.style.left = '-999999px';
|
1349 |
+
self.previewerIframe.style.left = '';
|
1350 |
+
self._eeState.preview = true;
|
1351 |
+
self._eeState.edit = false;
|
1352 |
+
self._focusExceptOnLoad();
|
1353 |
+
}
|
1354 |
+
|
1355 |
+
self.emit('preview');
|
1356 |
+
return self;
|
1357 |
+
}
|
1358 |
+
|
1359 |
+
/**
|
1360 |
+
* Helper to focus on the editor iframe. Will figure out which iframe to
|
1361 |
+
* focus on based on which one is active and will handle the cross browser
|
1362 |
+
* issues with focusing on the iframe vs the document body.
|
1363 |
+
* @returns {object} EpicEditor will be returned
|
1364 |
+
*/
|
1365 |
+
EpicEditor.prototype.focus = function (pageload) {
|
1366 |
+
var self = this
|
1367 |
+
, isPreview = self.is('preview')
|
1368 |
+
, focusElement = isPreview ? self.previewerIframeDocument.body
|
1369 |
+
: self.editorIframeDocument.body;
|
1370 |
+
|
1371 |
+
if (_isFirefox() && isPreview) {
|
1372 |
+
focusElement = self.previewerIframe;
|
1373 |
+
}
|
1374 |
+
|
1375 |
+
focusElement.focus();
|
1376 |
+
return this;
|
1377 |
+
}
|
1378 |
+
|
1379 |
+
/**
|
1380 |
+
* Puts the editor into fullscreen mode
|
1381 |
+
* @returns {object} EpicEditor will be returned
|
1382 |
+
*/
|
1383 |
+
EpicEditor.prototype.enterFullscreen = function (callback) {
|
1384 |
+
callback = callback || function () {};
|
1385 |
+
if (this.is('fullscreen')) {
|
1386 |
+
callback.call(this);
|
1387 |
+
return this;
|
1388 |
+
}
|
1389 |
+
this._goFullscreen(this.iframeElement, callback);
|
1390 |
+
return this;
|
1391 |
+
}
|
1392 |
+
|
1393 |
+
/**
|
1394 |
+
* Closes fullscreen mode if opened
|
1395 |
+
* @returns {object} EpicEditor will be returned
|
1396 |
+
*/
|
1397 |
+
EpicEditor.prototype.exitFullscreen = function (callback) {
|
1398 |
+
callback = callback || function () {};
|
1399 |
+
if (!this.is('fullscreen')) {
|
1400 |
+
callback.call(this);
|
1401 |
+
return this;
|
1402 |
+
}
|
1403 |
+
this._exitFullscreen(this.iframeElement, callback);
|
1404 |
+
return this;
|
1405 |
+
}
|
1406 |
+
|
1407 |
+
/**
|
1408 |
+
* Hides the preview and shows the editor again
|
1409 |
+
* @returns {object} EpicEditor will be returned
|
1410 |
+
*/
|
1411 |
+
EpicEditor.prototype.edit = function () {
|
1412 |
+
var self = this;
|
1413 |
+
_replaceClass(self.getElement('wrapper'), 'epiceditor-preview-mode', 'epiceditor-edit-mode');
|
1414 |
+
self._eeState.preview = false;
|
1415 |
+
self._eeState.edit = true;
|
1416 |
+
self.editorIframe.style.left = '';
|
1417 |
+
self.previewerIframe.style.left = '-999999px';
|
1418 |
+
self._focusExceptOnLoad();
|
1419 |
+
self.emit('edit');
|
1420 |
+
return this;
|
1421 |
+
}
|
1422 |
+
|
1423 |
+
/**
|
1424 |
+
* Grabs a specificed HTML node. Use it as a shortcut to getting the iframe contents
|
1425 |
+
* @param {String} name The name of the node (can be document, body, editor, previewer, or wrapper)
|
1426 |
+
* @returns {Object|Null}
|
1427 |
+
*/
|
1428 |
+
EpicEditor.prototype.getElement = function (name) {
|
1429 |
+
var available = {
|
1430 |
+
"container": this.element
|
1431 |
+
, "wrapper": this.iframe.getElementById('epiceditor-wrapper')
|
1432 |
+
, "wrapperIframe": this.iframeElement
|
1433 |
+
, "editor": this.editorIframeDocument
|
1434 |
+
, "editorIframe": this.editorIframe
|
1435 |
+
, "previewer": this.previewerIframeDocument
|
1436 |
+
, "previewerIframe": this.previewerIframe
|
1437 |
+
}
|
1438 |
+
|
1439 |
+
// Check that the given string is a possible option and verify the editor isn't unloaded
|
1440 |
+
// without this, you'd be given a reference to an object that no longer exists in the DOM
|
1441 |
+
if (!available[name] || this.is('unloaded')) {
|
1442 |
+
return null;
|
1443 |
+
}
|
1444 |
+
else {
|
1445 |
+
return available[name];
|
1446 |
+
}
|
1447 |
+
}
|
1448 |
+
|
1449 |
+
/**
|
1450 |
+
* Returns a boolean of each "state" of the editor. For example "editor.is('loaded')" // returns true/false
|
1451 |
+
* @param {String} what the state you want to check for
|
1452 |
+
* @returns {Boolean}
|
1453 |
+
*/
|
1454 |
+
EpicEditor.prototype.is = function (what) {
|
1455 |
+
var self = this;
|
1456 |
+
switch (what) {
|
1457 |
+
case 'loaded':
|
1458 |
+
return self._eeState.loaded;
|
1459 |
+
case 'unloaded':
|
1460 |
+
return self._eeState.unloaded
|
1461 |
+
case 'preview':
|
1462 |
+
return self._eeState.preview
|
1463 |
+
case 'edit':
|
1464 |
+
return self._eeState.edit;
|
1465 |
+
case 'fullscreen':
|
1466 |
+
return self._eeState.fullscreen;
|
1467 |
+
// TODO: This "works", but the tests are saying otherwise. Come back to this
|
1468 |
+
// and figure out how to fix it.
|
1469 |
+
// case 'focused':
|
1470 |
+
// return document.activeElement == self.iframeElement;
|
1471 |
+
default:
|
1472 |
+
return false;
|
1473 |
+
}
|
1474 |
+
}
|
1475 |
+
|
1476 |
+
/**
|
1477 |
+
* Opens a file
|
1478 |
+
* @param {string} name The name of the file you want to open
|
1479 |
+
* @returns {object} EpicEditor will be returned
|
1480 |
+
*/
|
1481 |
+
EpicEditor.prototype.open = function (name) {
|
1482 |
+
var self = this
|
1483 |
+
, defaultContent = self.settings.file.defaultContent
|
1484 |
+
, fileObj;
|
1485 |
+
name = name || self.settings.file.name;
|
1486 |
+
self.settings.file.name = name;
|
1487 |
+
if (this._storage[self.settings.localStorageName]) {
|
1488 |
+
fileObj = self.exportFile(name);
|
1489 |
+
if (fileObj !== undefined) {
|
1490 |
+
_setText(self.editor, fileObj);
|
1491 |
+
self.emit('read');
|
1492 |
+
}
|
1493 |
+
else {
|
1494 |
+
_setText(self.editor, defaultContent);
|
1495 |
+
self.save(); // ensure a save
|
1496 |
+
self.emit('create');
|
1497 |
+
}
|
1498 |
+
self.previewer.innerHTML = self.exportFile(null, 'html');
|
1499 |
+
self.emit('open');
|
1500 |
+
}
|
1501 |
+
return this;
|
1502 |
+
}
|
1503 |
+
|
1504 |
+
/**
|
1505 |
+
* Saves content for offline use
|
1506 |
+
* @returns {object} EpicEditor will be returned
|
1507 |
+
*/
|
1508 |
+
EpicEditor.prototype.save = function (_isPreviewDraft, _isAuto) {
|
1509 |
+
var self = this
|
1510 |
+
, storage
|
1511 |
+
, isUpdate = false
|
1512 |
+
, isNew = false
|
1513 |
+
, file = self.settings.file.name
|
1514 |
+
, previewDraftName = ''
|
1515 |
+
, data = this._storage[previewDraftName + self.settings.localStorageName]
|
1516 |
+
, content = _getText(this.editor);
|
1517 |
+
|
1518 |
+
if (_isPreviewDraft) {
|
1519 |
+
previewDraftName = self._previewDraftLocation;
|
1520 |
+
}
|
1521 |
+
|
1522 |
+
// This could have been false but since we're manually saving
|
1523 |
+
// we know it's save to start autoSaving again
|
1524 |
+
this._canSave = true;
|
1525 |
+
|
1526 |
+
// Guard against storage being wiped out without EpicEditor knowing
|
1527 |
+
// TODO: Emit saving error - storage seems to have been wiped
|
1528 |
+
if (data) {
|
1529 |
+
storage = JSON.parse(this._storage[previewDraftName + self.settings.localStorageName]);
|
1530 |
+
|
1531 |
+
// If the file doesn't exist we need to create it
|
1532 |
+
if (storage[file] === undefined) {
|
1533 |
+
storage[file] = self._defaultFileSchema();
|
1534 |
+
isNew = true;
|
1535 |
+
}
|
1536 |
+
|
1537 |
+
// If it does, we need to check if the content is different and
|
1538 |
+
// if it is, send the update event and update the timestamp
|
1539 |
+
else if (content !== storage[file].content) {
|
1540 |
+
storage[file].modified = new Date();
|
1541 |
+
isUpdate = true;
|
1542 |
+
}
|
1543 |
+
//don't bother autosaving if the content hasn't actually changed
|
1544 |
+
else if (_isAuto) {
|
1545 |
+
return;
|
1546 |
+
}
|
1547 |
+
|
1548 |
+
storage[file].content = content;
|
1549 |
+
this._storage[previewDraftName + self.settings.localStorageName] = JSON.stringify(storage);
|
1550 |
+
|
1551 |
+
// If it's a new file, send a create event as well as a private one for
|
1552 |
+
// use internally.
|
1553 |
+
if (isNew) {
|
1554 |
+
self.emit('create');
|
1555 |
+
self.emit('__create');
|
1556 |
+
}
|
1557 |
+
|
1558 |
+
// After the content is actually changed, emit update so it emits the
|
1559 |
+
// updated content. Also send a private event for interal use.
|
1560 |
+
if (isUpdate) {
|
1561 |
+
self.emit('update');
|
1562 |
+
self.emit('__update');
|
1563 |
+
}
|
1564 |
+
|
1565 |
+
if (_isAuto) {
|
1566 |
+
this.emit('autosave');
|
1567 |
+
}
|
1568 |
+
else if (!_isPreviewDraft) {
|
1569 |
+
this.emit('save');
|
1570 |
+
self.emit('__save');
|
1571 |
+
}
|
1572 |
+
}
|
1573 |
+
|
1574 |
+
return this;
|
1575 |
+
}
|
1576 |
+
|
1577 |
+
/**
|
1578 |
+
* Removes a page
|
1579 |
+
* @param {string} name The name of the file you want to remove from localStorage
|
1580 |
+
* @returns {object} EpicEditor will be returned
|
1581 |
+
*/
|
1582 |
+
EpicEditor.prototype.remove = function (name) {
|
1583 |
+
var self = this
|
1584 |
+
, s;
|
1585 |
+
name = name || self.settings.file.name;
|
1586 |
+
|
1587 |
+
// If you're trying to delete a page you have open, block saving
|
1588 |
+
if (name == self.settings.file.name) {
|
1589 |
+
self._canSave = false;
|
1590 |
+
}
|
1591 |
+
|
1592 |
+
s = JSON.parse(this._storage[self.settings.localStorageName]);
|
1593 |
+
delete s[name];
|
1594 |
+
this._storage[self.settings.localStorageName] = JSON.stringify(s);
|
1595 |
+
this.emit('remove');
|
1596 |
+
return this;
|
1597 |
+
};
|
1598 |
+
|
1599 |
+
/**
|
1600 |
+
* Renames a file
|
1601 |
+
* @param {string} oldName The old file name
|
1602 |
+
* @param {string} newName The new file name
|
1603 |
+
* @returns {object} EpicEditor will be returned
|
1604 |
+
*/
|
1605 |
+
EpicEditor.prototype.rename = function (oldName, newName) {
|
1606 |
+
var self = this
|
1607 |
+
, s = JSON.parse(this._storage[self.settings.localStorageName]);
|
1608 |
+
s[newName] = s[oldName];
|
1609 |
+
delete s[oldName];
|
1610 |
+
this._storage[self.settings.localStorageName] = JSON.stringify(s);
|
1611 |
+
self.open(newName);
|
1612 |
+
return this;
|
1613 |
+
};
|
1614 |
+
|
1615 |
+
/**
|
1616 |
+
* Imports a file and it's contents and opens it
|
1617 |
+
* @param {string} name The name of the file you want to import (will overwrite existing files!)
|
1618 |
+
* @param {string} content Content of the file you want to import
|
1619 |
+
* @param {string} kind The kind of file you want to import (TBI)
|
1620 |
+
* @param {object} meta Meta data you want to save with your file.
|
1621 |
+
* @returns {object} EpicEditor will be returned
|
1622 |
+
*/
|
1623 |
+
EpicEditor.prototype.importFile = function (name, content, kind, meta) {
|
1624 |
+
var self = this;
|
1625 |
+
|
1626 |
+
name = name || self.settings.file.name;
|
1627 |
+
content = content || '';
|
1628 |
+
kind = kind || 'md';
|
1629 |
+
meta = meta || {};
|
1630 |
+
|
1631 |
+
// Set our current file to the new file and update the content
|
1632 |
+
self.settings.file.name = name;
|
1633 |
+
_setText(self.editor, content);
|
1634 |
+
|
1635 |
+
self.save();
|
1636 |
+
|
1637 |
+
if (self.is('fullscreen')) {
|
1638 |
+
self.preview();
|
1639 |
+
}
|
1640 |
+
|
1641 |
+
//firefox has trouble with importing and working out the size right away
|
1642 |
+
if (self.settings.autogrow) {
|
1643 |
+
setTimeout(function () {
|
1644 |
+
self._autogrow();
|
1645 |
+
}, 50);
|
1646 |
+
}
|
1647 |
+
|
1648 |
+
return this;
|
1649 |
+
};
|
1650 |
+
|
1651 |
+
/**
|
1652 |
+
* Gets the local filestore
|
1653 |
+
* @param {string} name Name of the file in the store
|
1654 |
+
* @returns {object|undefined} the local filestore, or a specific file in the store, if a name is given
|
1655 |
+
*/
|
1656 |
+
EpicEditor.prototype._getFileStore = function (name, _isPreviewDraft) {
|
1657 |
+
var previewDraftName = ''
|
1658 |
+
, store;
|
1659 |
+
if (_isPreviewDraft) {
|
1660 |
+
previewDraftName = this._previewDraftLocation;
|
1661 |
+
}
|
1662 |
+
store = JSON.parse(this._storage[previewDraftName + this.settings.localStorageName]);
|
1663 |
+
if (name) {
|
1664 |
+
return store[name];
|
1665 |
+
}
|
1666 |
+
else {
|
1667 |
+
return store;
|
1668 |
+
}
|
1669 |
+
}
|
1670 |
+
|
1671 |
+
/**
|
1672 |
+
* Exports a file as a string in a supported format
|
1673 |
+
* @param {string} name Name of the file you want to export (case sensitive)
|
1674 |
+
* @param {string} kind Kind of file you want the content in (currently supports html and text, default is the format the browser "wants")
|
1675 |
+
* @returns {string|undefined} The content of the file in the content given or undefined if it doesn't exist
|
1676 |
+
*/
|
1677 |
+
EpicEditor.prototype.exportFile = function (name, kind, _isPreviewDraft) {
|
1678 |
+
var self = this
|
1679 |
+
, file
|
1680 |
+
, content;
|
1681 |
+
|
1682 |
+
name = name || self.settings.file.name;
|
1683 |
+
kind = kind || 'text';
|
1684 |
+
|
1685 |
+
file = self._getFileStore(name, _isPreviewDraft);
|
1686 |
+
|
1687 |
+
// If the file doesn't exist just return early with undefined
|
1688 |
+
if (file === undefined) {
|
1689 |
+
return;
|
1690 |
+
}
|
1691 |
+
|
1692 |
+
content = file.content;
|
1693 |
+
|
1694 |
+
switch (kind) {
|
1695 |
+
case 'html':
|
1696 |
+
content = _sanitizeRawContent(content);
|
1697 |
+
return self.settings.parser(content);
|
1698 |
+
case 'text':
|
1699 |
+
return _sanitizeRawContent(content);
|
1700 |
+
case 'json':
|
1701 |
+
file.content = _sanitizeRawContent(file.content);
|
1702 |
+
return JSON.stringify(file);
|
1703 |
+
case 'raw':
|
1704 |
+
return content;
|
1705 |
+
default:
|
1706 |
+
return content;
|
1707 |
+
}
|
1708 |
+
}
|
1709 |
+
|
1710 |
+
/**
|
1711 |
+
* Gets the contents and metadata for files
|
1712 |
+
* @param {string} name Name of the file whose data you want (case sensitive)
|
1713 |
+
* @param {boolean} excludeContent whether the contents of files should be excluded
|
1714 |
+
* @returns {object} An object with the names and data of every file, or just the data of one file if a name was given
|
1715 |
+
*/
|
1716 |
+
EpicEditor.prototype.getFiles = function (name, excludeContent) {
|
1717 |
+
var file
|
1718 |
+
, data = this._getFileStore(name);
|
1719 |
+
|
1720 |
+
if (name) {
|
1721 |
+
if (data !== undefined) {
|
1722 |
+
if (excludeContent) {
|
1723 |
+
delete data.content;
|
1724 |
+
}
|
1725 |
+
else {
|
1726 |
+
data.content = _sanitizeRawContent(data.content);
|
1727 |
+
}
|
1728 |
+
}
|
1729 |
+
return data;
|
1730 |
+
}
|
1731 |
+
else {
|
1732 |
+
for (file in data) {
|
1733 |
+
if (data.hasOwnProperty(file)) {
|
1734 |
+
if (excludeContent) {
|
1735 |
+
delete data[file].content;
|
1736 |
+
}
|
1737 |
+
else {
|
1738 |
+
data[file].content = _sanitizeRawContent(data[file].content);
|
1739 |
+
}
|
1740 |
+
}
|
1741 |
+
}
|
1742 |
+
return data;
|
1743 |
+
}
|
1744 |
+
}
|
1745 |
+
|
1746 |
+
// EVENTS
|
1747 |
+
// TODO: Support for namespacing events like "preview.foo"
|
1748 |
+
/**
|
1749 |
+
* Sets up an event handler for a specified event
|
1750 |
+
* @param {string} ev The event name
|
1751 |
+
* @param {function} handler The callback to run when the event fires
|
1752 |
+
* @returns {object} EpicEditor will be returned
|
1753 |
+
*/
|
1754 |
+
EpicEditor.prototype.on = function (ev, handler) {
|
1755 |
+
var self = this;
|
1756 |
+
if (!this.events[ev]) {
|
1757 |
+
this.events[ev] = [];
|
1758 |
+
}
|
1759 |
+
this.events[ev].push(handler);
|
1760 |
+
return self;
|
1761 |
+
};
|
1762 |
+
|
1763 |
+
/**
|
1764 |
+
* This will emit or "trigger" an event specified
|
1765 |
+
* @param {string} ev The event name
|
1766 |
+
* @param {any} data Any data you want to pass into the callback
|
1767 |
+
* @returns {object} EpicEditor will be returned
|
1768 |
+
*/
|
1769 |
+
EpicEditor.prototype.emit = function (ev, data) {
|
1770 |
+
var self = this
|
1771 |
+
, x;
|
1772 |
+
|
1773 |
+
data = data || self.getFiles(self.settings.file.name);
|
1774 |
+
|
1775 |
+
if (!this.events[ev]) {
|
1776 |
+
return;
|
1777 |
+
}
|
1778 |
+
|
1779 |
+
function invokeHandler(handler) {
|
1780 |
+
handler.call(self, data);
|
1781 |
+
}
|
1782 |
+
|
1783 |
+
for (x = 0; x < self.events[ev].length; x++) {
|
1784 |
+
invokeHandler(self.events[ev][x]);
|
1785 |
+
}
|
1786 |
+
|
1787 |
+
return self;
|
1788 |
+
};
|
1789 |
+
|
1790 |
+
/**
|
1791 |
+
* Will remove any listeners added from EpicEditor.on()
|
1792 |
+
* @param {string} ev The event name
|
1793 |
+
* @param {function} handler Handler to remove
|
1794 |
+
* @returns {object} EpicEditor will be returned
|
1795 |
+
*/
|
1796 |
+
EpicEditor.prototype.removeListener = function (ev, handler) {
|
1797 |
+
var self = this;
|
1798 |
+
if (!handler) {
|
1799 |
+
this.events[ev] = [];
|
1800 |
+
return self;
|
1801 |
+
}
|
1802 |
+
if (!this.events[ev]) {
|
1803 |
+
return self;
|
1804 |
+
}
|
1805 |
+
// Otherwise a handler and event exist, so take care of it
|
1806 |
+
this.events[ev].splice(this.events[ev].indexOf(handler), 1);
|
1807 |
+
return self;
|
1808 |
+
}
|
1809 |
+
|
1810 |
+
/**
|
1811 |
+
* Handles autogrowing the editor
|
1812 |
+
*/
|
1813 |
+
EpicEditor.prototype._autogrow = function () {
|
1814 |
+
var editorHeight
|
1815 |
+
, newHeight
|
1816 |
+
, minHeight
|
1817 |
+
, maxHeight
|
1818 |
+
, el
|
1819 |
+
, style
|
1820 |
+
, maxedOut = false;
|
1821 |
+
|
1822 |
+
//autogrow in fullscreen is nonsensical
|
1823 |
+
if (!this.is('fullscreen')) {
|
1824 |
+
if (this.is('edit')) {
|
1825 |
+
el = this.getElement('editor').documentElement;
|
1826 |
+
}
|
1827 |
+
else {
|
1828 |
+
el = this.getElement('previewer').documentElement;
|
1829 |
+
}
|
1830 |
+
|
1831 |
+
editorHeight = _outerHeight(el);
|
1832 |
+
newHeight = editorHeight;
|
1833 |
+
|
1834 |
+
//handle minimum
|
1835 |
+
minHeight = this.settings.autogrow.minHeight;
|
1836 |
+
if (typeof minHeight === 'function') {
|
1837 |
+
minHeight = minHeight(this);
|
1838 |
+
}
|
1839 |
+
|
1840 |
+
if (minHeight && newHeight < minHeight) {
|
1841 |
+
newHeight = minHeight;
|
1842 |
+
}
|
1843 |
+
|
1844 |
+
//handle maximum
|
1845 |
+
maxHeight = this.settings.autogrow.maxHeight;
|
1846 |
+
if (typeof maxHeight === 'function') {
|
1847 |
+
maxHeight = maxHeight(this);
|
1848 |
+
}
|
1849 |
+
|
1850 |
+
if (maxHeight && newHeight > maxHeight) {
|
1851 |
+
newHeight = maxHeight;
|
1852 |
+
maxedOut = true;
|
1853 |
+
}
|
1854 |
+
|
1855 |
+
if (maxedOut) {
|
1856 |
+
this._fixScrollbars('auto');
|
1857 |
+
} else {
|
1858 |
+
this._fixScrollbars('hidden');
|
1859 |
+
}
|
1860 |
+
|
1861 |
+
//actual resize
|
1862 |
+
if (newHeight != this.oldHeight) {
|
1863 |
+
this.getElement('container').style.height = newHeight + 'px';
|
1864 |
+
this.reflow();
|
1865 |
+
if (this.settings.autogrow.scroll) {
|
1866 |
+
window.scrollBy(0, newHeight - this.oldHeight);
|
1867 |
+
}
|
1868 |
+
this.oldHeight = newHeight;
|
1869 |
+
}
|
1870 |
+
}
|
1871 |
+
}
|
1872 |
+
|
1873 |
+
/**
|
1874 |
+
* Shows or hides scrollbars based on the autogrow setting
|
1875 |
+
* @param {string} forceSetting a value to force the overflow to
|
1876 |
+
*/
|
1877 |
+
EpicEditor.prototype._fixScrollbars = function (forceSetting) {
|
1878 |
+
var setting;
|
1879 |
+
if (this.settings.autogrow) {
|
1880 |
+
setting = 'hidden';
|
1881 |
+
}
|
1882 |
+
else {
|
1883 |
+
setting = 'auto';
|
1884 |
+
}
|
1885 |
+
setting = forceSetting || setting;
|
1886 |
+
this.getElement('editor').documentElement.style.overflow = setting;
|
1887 |
+
this.getElement('previewer').documentElement.style.overflow = setting;
|
1888 |
+
}
|
1889 |
+
|
1890 |
+
EpicEditor.version = '0.2.2';
|
1891 |
+
|
1892 |
+
// Used to store information to be shared across editors
|
1893 |
+
EpicEditor._data = {};
|
1894 |
+
|
1895 |
+
window.EpicEditor = EpicEditor;
|
1896 |
+
})(window);
|
js/markdown/adminhtml/filereader.js
ADDED
@@ -0,0 +1,446 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
FileReader.js - v0.9
|
3 |
+
A lightweight wrapper for common FileReader usage.
|
4 |
+
Copyright 2012 Brian Grinstead - MIT License.
|
5 |
+
See http://github.com/bgrins/filereader.js for documentation.
|
6 |
+
*/
|
7 |
+
|
8 |
+
(function (window, document) {
|
9 |
+
|
10 |
+
var FileReader = window.FileReader;
|
11 |
+
var FileReaderSyncSupport = false;
|
12 |
+
var workerScript = "self.addEventListener('message', function(e) { var data=e.data; try { var reader = new FileReaderSync; postMessage({ result: reader[data.readAs](data.file), extra: data.extra, file: data.file})} catch(e){ postMessage({ result:'error', extra:data.extra, file:data.file}); } }, false);";
|
13 |
+
var syncDetectionScript = "self.addEventListener('message', function(e) { postMessage(!!FileReaderSync); }, false);";
|
14 |
+
var fileReaderEvents = ['loadstart', 'progress', 'load', 'abort', 'error', 'loadend'];
|
15 |
+
|
16 |
+
var FileReaderJS = window.FileReaderJS = {
|
17 |
+
enabled: false,
|
18 |
+
setupInput: setupInput,
|
19 |
+
setupDrop: setupDrop,
|
20 |
+
setupClipboard: setupClipboard,
|
21 |
+
sync: false,
|
22 |
+
output: [],
|
23 |
+
opts: {
|
24 |
+
dragClass: "drag",
|
25 |
+
accept: false,
|
26 |
+
readAsDefault: 'BinaryString',
|
27 |
+
readAsMap: {
|
28 |
+
'image/*': 'DataURL',
|
29 |
+
'text/*': 'Text'
|
30 |
+
},
|
31 |
+
on: {
|
32 |
+
loadstart: noop,
|
33 |
+
progress: noop,
|
34 |
+
load: noop,
|
35 |
+
abort: noop,
|
36 |
+
error: noop,
|
37 |
+
loadend: noop,
|
38 |
+
skip: noop,
|
39 |
+
groupstart: noop,
|
40 |
+
groupend: noop,
|
41 |
+
beforestart: noop
|
42 |
+
}
|
43 |
+
}
|
44 |
+
};
|
45 |
+
|
46 |
+
// Setup jQuery plugin (if available)
|
47 |
+
if (typeof(jQuery) !== "undefined") {
|
48 |
+
jQuery.fn.fileReaderJS = function (opts) {
|
49 |
+
return this.each(function () {
|
50 |
+
if ($(this).is("input")) {
|
51 |
+
setupInput(this, opts);
|
52 |
+
}
|
53 |
+
else {
|
54 |
+
setupDrop(this, opts);
|
55 |
+
}
|
56 |
+
});
|
57 |
+
};
|
58 |
+
|
59 |
+
jQuery.fn.fileClipboard = function (opts) {
|
60 |
+
return this.each(function () {
|
61 |
+
setupClipboard(this, opts);
|
62 |
+
});
|
63 |
+
};
|
64 |
+
}
|
65 |
+
|
66 |
+
// Not all browsers support the FileReader interface. Return with the enabled bit = false.
|
67 |
+
if (!FileReader) {
|
68 |
+
return;
|
69 |
+
}
|
70 |
+
|
71 |
+
// WorkerHelper is a little wrapper for generating web workers from strings
|
72 |
+
var WorkerHelper = (function () {
|
73 |
+
|
74 |
+
var URL = window.URL || window.webkitURL;
|
75 |
+
var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
|
76 |
+
|
77 |
+
// May need to get just the URL in case it is needed for things beyond just creating a worker.
|
78 |
+
function getURL(script) {
|
79 |
+
if (window.Worker && BlobBuilder && URL) {
|
80 |
+
var bb = new BlobBuilder();
|
81 |
+
bb.append(script);
|
82 |
+
return URL.createObjectURL(bb.getBlob());
|
83 |
+
}
|
84 |
+
|
85 |
+
return null;
|
86 |
+
}
|
87 |
+
|
88 |
+
// If there is no need to revoke a URL later, or do anything fancy then just return the worker.
|
89 |
+
function getWorker(script, onmessage) {
|
90 |
+
var url = getURL(script);
|
91 |
+
if (url) {
|
92 |
+
var worker = new Worker(url);
|
93 |
+
worker.onmessage = onmessage;
|
94 |
+
return worker;
|
95 |
+
}
|
96 |
+
|
97 |
+
return null;
|
98 |
+
}
|
99 |
+
|
100 |
+
return {
|
101 |
+
getURL: getURL,
|
102 |
+
getWorker: getWorker
|
103 |
+
};
|
104 |
+
|
105 |
+
})();
|
106 |
+
|
107 |
+
// setupClipboard: bind to clipboard events (intended for document.body)
|
108 |
+
function setupClipboard(element, opts) {
|
109 |
+
|
110 |
+
if (!FileReaderJS.enabled) {
|
111 |
+
return;
|
112 |
+
}
|
113 |
+
var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
|
114 |
+
|
115 |
+
element.addEventListener("paste", onpaste, false);
|
116 |
+
|
117 |
+
function onpaste(e) {
|
118 |
+
var files = [];
|
119 |
+
var clipboardData = e.clipboardData || {};
|
120 |
+
var items = clipboardData.items || [];
|
121 |
+
|
122 |
+
for (var i = 0; i < items.length; i++) {
|
123 |
+
var file = items[i].getAsFile();
|
124 |
+
|
125 |
+
if (file) {
|
126 |
+
|
127 |
+
// Create a fake file name for images from clipboard, since this data doesn't get sent
|
128 |
+
var matches = new RegExp("/\(.*\)").exec(file.type);
|
129 |
+
if (!file.name && matches) {
|
130 |
+
var extension = matches[1];
|
131 |
+
file.name = "clipboard" + i + "." + extension;
|
132 |
+
}
|
133 |
+
|
134 |
+
files.push(file);
|
135 |
+
}
|
136 |
+
}
|
137 |
+
|
138 |
+
if (files.length) {
|
139 |
+
processFileList(e, files, instanceOptions);
|
140 |
+
e.preventDefault();
|
141 |
+
e.stopPropagation();
|
142 |
+
}
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
// setupInput: bind the 'change' event to an input[type=file]
|
147 |
+
function setupInput(input, opts) {
|
148 |
+
|
149 |
+
if (!FileReaderJS.enabled) {
|
150 |
+
return;
|
151 |
+
}
|
152 |
+
var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
|
153 |
+
|
154 |
+
input.addEventListener("change", inputChange, false);
|
155 |
+
input.addEventListener("drop", inputDrop, false);
|
156 |
+
|
157 |
+
function inputChange(e) {
|
158 |
+
processFileList(e, input.files, instanceOptions);
|
159 |
+
}
|
160 |
+
|
161 |
+
function inputDrop(e) {
|
162 |
+
e.stopPropagation();
|
163 |
+
e.preventDefault();
|
164 |
+
processFileList(e, e.dataTransfer.files, instanceOptions);
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
// setupDrop: bind the 'drop' event for a DOM element
|
169 |
+
function setupDrop(dropbox, opts) {
|
170 |
+
|
171 |
+
if (!FileReaderJS.enabled) {
|
172 |
+
return;
|
173 |
+
}
|
174 |
+
var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
|
175 |
+
var dragClass = instanceOptions.dragClass;
|
176 |
+
var initializedOnBody = false;
|
177 |
+
|
178 |
+
// Bind drag events to the dropbox to add the class while dragging, and accept the drop data transfer.
|
179 |
+
dropbox.addEventListener("dragenter", onlyWithFiles(dragenter), false);
|
180 |
+
dropbox.addEventListener("dragleave", onlyWithFiles(dragleave), false);
|
181 |
+
dropbox.addEventListener("dragover", onlyWithFiles(dragover), false);
|
182 |
+
dropbox.addEventListener("drop", onlyWithFiles(drop), false);
|
183 |
+
|
184 |
+
// Bind to body to prevent the dropbox events from firing when it was initialized on the page.
|
185 |
+
document.body.addEventListener("dragstart", bodydragstart, true);
|
186 |
+
document.body.addEventListener("dragend", bodydragend, true);
|
187 |
+
document.body.addEventListener("drop", bodydrop, false);
|
188 |
+
|
189 |
+
function bodydragend(e) {
|
190 |
+
initializedOnBody = false;
|
191 |
+
}
|
192 |
+
|
193 |
+
function bodydragstart(e) {
|
194 |
+
initializedOnBody = true;
|
195 |
+
}
|
196 |
+
|
197 |
+
function bodydrop(e) {
|
198 |
+
if (e.dataTransfer.files && e.dataTransfer.files.length) {
|
199 |
+
e.stopPropagation();
|
200 |
+
e.preventDefault();
|
201 |
+
}
|
202 |
+
}
|
203 |
+
|
204 |
+
function onlyWithFiles(fn) {
|
205 |
+
return function () {
|
206 |
+
if (!initializedOnBody) {
|
207 |
+
fn.apply(this, arguments);
|
208 |
+
}
|
209 |
+
};
|
210 |
+
}
|
211 |
+
|
212 |
+
function drop(e) {
|
213 |
+
e.stopPropagation();
|
214 |
+
e.preventDefault();
|
215 |
+
if (dragClass) {
|
216 |
+
removeClass(dropbox, dragClass);
|
217 |
+
}
|
218 |
+
processFileList(e, e.dataTransfer.files, instanceOptions);
|
219 |
+
}
|
220 |
+
|
221 |
+
function dragenter(e) {
|
222 |
+
e.stopPropagation();
|
223 |
+
e.preventDefault();
|
224 |
+
if (dragClass) {
|
225 |
+
addClass(dropbox, dragClass);
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
function dragleave(e) {
|
230 |
+
if (dragClass) {
|
231 |
+
removeClass(dropbox, dragClass);
|
232 |
+
}
|
233 |
+
}
|
234 |
+
|
235 |
+
function dragover(e) {
|
236 |
+
e.stopPropagation();
|
237 |
+
e.preventDefault();
|
238 |
+
if (dragClass) {
|
239 |
+
addClass(dropbox, dragClass);
|
240 |
+
}
|
241 |
+
}
|
242 |
+
}
|
243 |
+
|
244 |
+
// setupCustomFileProperties: modify the file object with extra properties
|
245 |
+
function setupCustomFileProperties(files, groupID) {
|
246 |
+
for (var i = 0; i < files.length; i++) {
|
247 |
+
var file = files[i];
|
248 |
+
file.extra = {
|
249 |
+
nameNoExtension: file.name.substring(0, file.name.lastIndexOf('.')),
|
250 |
+
extension: file.name.substring(file.name.lastIndexOf('.') + 1),
|
251 |
+
fileID: i,
|
252 |
+
uniqueID: getUniqueID(),
|
253 |
+
groupID: groupID,
|
254 |
+
prettySize: prettySize(file.size)
|
255 |
+
};
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
// getReadAsMethod: return method name for 'readAs*' - http://www.w3.org/TR/FileAPI/#reading-a-file
|
260 |
+
function getReadAsMethod(type, readAsMap, readAsDefault) {
|
261 |
+
for (var r in readAsMap) {
|
262 |
+
if (type.match(new RegExp(r))) {
|
263 |
+
return 'readAs' + readAsMap[r];
|
264 |
+
}
|
265 |
+
}
|
266 |
+
return 'readAs' + readAsDefault;
|
267 |
+
}
|
268 |
+
|
269 |
+
// processFileList: read the files with FileReader, send off custom events.
|
270 |
+
function processFileList(e, files, opts) {
|
271 |
+
|
272 |
+
var filesLeft = files.length;
|
273 |
+
var group = {
|
274 |
+
groupID: getGroupID(),
|
275 |
+
files: files,
|
276 |
+
started: new Date()
|
277 |
+
};
|
278 |
+
|
279 |
+
function groupEnd() {
|
280 |
+
group.ended = new Date();
|
281 |
+
opts.on.groupend(group);
|
282 |
+
}
|
283 |
+
|
284 |
+
function groupFileDone() {
|
285 |
+
if (--filesLeft === 0) {
|
286 |
+
groupEnd();
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
FileReaderJS.output.push(group);
|
291 |
+
setupCustomFileProperties(files, group.groupID);
|
292 |
+
|
293 |
+
opts.on.groupstart(group);
|
294 |
+
|
295 |
+
// No files in group - end immediately
|
296 |
+
if (!files.length) {
|
297 |
+
groupEnd();
|
298 |
+
return;
|
299 |
+
}
|
300 |
+
|
301 |
+
var sync = FileReaderJS.sync && FileReaderSyncSupport;
|
302 |
+
var syncWorker;
|
303 |
+
|
304 |
+
// Only initialize the synchronous worker if the option is enabled - to prevent the overhead
|
305 |
+
if (sync) {
|
306 |
+
syncWorker = WorkerHelper.getWorker(workerScript, function (e) {
|
307 |
+
var file = e.data.file;
|
308 |
+
var result = e.data.result;
|
309 |
+
|
310 |
+
// Workers seem to lose the custom property on the file object.
|
311 |
+
if (!file.extra) {
|
312 |
+
file.extra = e.data.extra;
|
313 |
+
}
|
314 |
+
|
315 |
+
file.extra.ended = new Date();
|
316 |
+
|
317 |
+
// Call error or load event depending on success of the read from the worker.
|
318 |
+
opts.on[result === "error" ? "error" : "load"]({ target: { result: result } }, file);
|
319 |
+
groupFileDone();
|
320 |
+
|
321 |
+
});
|
322 |
+
}
|
323 |
+
|
324 |
+
Array.prototype.forEach.call(files, function (file) {
|
325 |
+
|
326 |
+
file.extra.started = new Date();
|
327 |
+
|
328 |
+
if (opts.accept && !file.type.match(new RegExp(opts.accept))) {
|
329 |
+
opts.on.skip(file);
|
330 |
+
groupFileDone();
|
331 |
+
return;
|
332 |
+
}
|
333 |
+
|
334 |
+
if (opts.on.beforestart(file) === false) {
|
335 |
+
opts.on.skip(file);
|
336 |
+
groupFileDone();
|
337 |
+
return;
|
338 |
+
}
|
339 |
+
|
340 |
+
var readAs = getReadAsMethod(file.type, opts.readAsMap, opts.readAsDefault);
|
341 |
+
|
342 |
+
if (sync && syncWorker) {
|
343 |
+
syncWorker.postMessage({
|
344 |
+
file: file,
|
345 |
+
extra: file.extra,
|
346 |
+
readAs: readAs
|
347 |
+
});
|
348 |
+
}
|
349 |
+
else {
|
350 |
+
|
351 |
+
var reader = new FileReader();
|
352 |
+
reader.originalEvent = e;
|
353 |
+
|
354 |
+
fileReaderEvents.forEach(function (eventName) {
|
355 |
+
reader['on' + eventName] = function (e) {
|
356 |
+
if (eventName == 'load' || eventName == 'error') {
|
357 |
+
file.extra.ended = new Date();
|
358 |
+
}
|
359 |
+
opts.on[eventName](e, file);
|
360 |
+
if (eventName == 'loadend') {
|
361 |
+
groupFileDone();
|
362 |
+
}
|
363 |
+
};
|
364 |
+
});
|
365 |
+
|
366 |
+
reader[readAs](file);
|
367 |
+
}
|
368 |
+
});
|
369 |
+
}
|
370 |
+
|
371 |
+
// checkFileReaderSyncSupport: Create a temporary worker and see if FileReaderSync exists
|
372 |
+
function checkFileReaderSyncSupport() {
|
373 |
+
var worker = WorkerHelper.getWorker(syncDetectionScript, function (e) {
|
374 |
+
FileReaderSyncSupport = e.data;
|
375 |
+
});
|
376 |
+
|
377 |
+
if (worker) {
|
378 |
+
worker.postMessage({});
|
379 |
+
}
|
380 |
+
}
|
381 |
+
|
382 |
+
// noop: do nothing
|
383 |
+
function noop() {
|
384 |
+
|
385 |
+
}
|
386 |
+
|
387 |
+
// extend: used to make deep copies of options object
|
388 |
+
function extend(destination, source) {
|
389 |
+
for (var property in source) {
|
390 |
+
if (source[property] && source[property].constructor &&
|
391 |
+
source[property].constructor === Object) {
|
392 |
+
destination[property] = destination[property] || {};
|
393 |
+
arguments.callee(destination[property], source[property]);
|
394 |
+
}
|
395 |
+
else {
|
396 |
+
destination[property] = source[property];
|
397 |
+
}
|
398 |
+
}
|
399 |
+
return destination;
|
400 |
+
}
|
401 |
+
|
402 |
+
// hasClass: does an element have the css class?
|
403 |
+
function hasClass(el, name) {
|
404 |
+
return new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)").test(el.className);
|
405 |
+
}
|
406 |
+
|
407 |
+
// addClass: add the css class for the element.
|
408 |
+
function addClass(el, name) {
|
409 |
+
if (!hasClass(el, name)) {
|
410 |
+
el.className = el.className ? [el.className, name].join(' ') : name;
|
411 |
+
}
|
412 |
+
}
|
413 |
+
|
414 |
+
// removeClass: remove the css class from the element.
|
415 |
+
function removeClass(el, name) {
|
416 |
+
if (hasClass(el, name)) {
|
417 |
+
var c = el.className;
|
418 |
+
el.className = c.replace(new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)", "g"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
419 |
+
}
|
420 |
+
}
|
421 |
+
|
422 |
+
// prettySize: convert bytes to a more readable string.
|
423 |
+
function prettySize(bytes) {
|
424 |
+
var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB'];
|
425 |
+
var e = Math.floor(Math.log(bytes) / Math.log(1024));
|
426 |
+
return (bytes / Math.pow(1024, Math.floor(e))).toFixed(2) + " " + s[e];
|
427 |
+
}
|
428 |
+
|
429 |
+
// getGroupID: generate a unique int ID for groups.
|
430 |
+
var getGroupID = (function (id) {
|
431 |
+
return function () {
|
432 |
+
return id++;
|
433 |
+
};
|
434 |
+
})(0);
|
435 |
+
|
436 |
+
// getUniqueID: generate a unique int ID for files
|
437 |
+
var getUniqueID = (function (id) {
|
438 |
+
return function () {
|
439 |
+
return id++;
|
440 |
+
};
|
441 |
+
})(0);
|
442 |
+
|
443 |
+
// The interface is supported, bind the FileReaderJS callbacks
|
444 |
+
FileReaderJS.enabled = true;
|
445 |
+
|
446 |
+
})(this, document);
|
js/markdown/adminhtml/highlight.pack.js
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
/* https://github.com/isagalaev/highlight.js */
|
2 |
+
var hljs=new function(){function l(o){return o.replace(/&/gm,"&").replace(/</gm,"<").replace(/>/gm,">")}function b(p){for(var o=p.firstChild;o;o=o.nextSibling){if(o.nodeName=="CODE"){return o}if(!(o.nodeType==3&&o.nodeValue.match(/\s+/))){break}}}function h(p,o){return Array.prototype.map.call(p.childNodes,function(q){if(q.nodeType==3){return o?q.nodeValue.replace(/\n/g,""):q.nodeValue}if(q.nodeName=="BR"){return"\n"}return h(q,o)}).join("")}function a(q){var p=(q.className+" "+q.parentNode.className).split(/\s+/);p=p.map(function(r){return r.replace(/^language-/,"")});for(var o=0;o<p.length;o++){if(e[p[o]]||p[o]=="no-highlight"){return p[o]}}}function c(q){var o=[];(function p(r,s){for(var t=r.firstChild;t;t=t.nextSibling){if(t.nodeType==3){s+=t.nodeValue.length}else{if(t.nodeName=="BR"){s+=1}else{if(t.nodeType==1){o.push({event:"start",offset:s,node:t});s=p(t,s);o.push({event:"stop",offset:s,node:t})}}}}return s})(q,0);return o}function j(x,v,w){var p=0;var y="";var r=[];function t(){if(x.length&&v.length){if(x[0].offset!=v[0].offset){return(x[0].offset<v[0].offset)?x:v}else{return v[0].event=="start"?x:v}}else{return x.length?x:v}}function s(A){function z(B){return" "+B.nodeName+'="'+l(B.value)+'"'}return"<"+A.nodeName+Array.prototype.map.call(A.attributes,z).join("")+">"}while(x.length||v.length){var u=t().splice(0,1)[0];y+=l(w.substr(p,u.offset-p));p=u.offset;if(u.event=="start"){y+=s(u.node);r.push(u.node)}else{if(u.event=="stop"){var o,q=r.length;do{q--;o=r[q];y+=("</"+o.nodeName.toLowerCase()+">")}while(o!=u.node);r.splice(q,1);while(q<r.length){y+=s(r[q]);q++}}}}return y+l(w.substr(p))}function f(q){function o(s,r){return RegExp(s,"m"+(q.cI?"i":"")+(r?"g":""))}function p(y,w){if(y.compiled){return}y.compiled=true;var s=[];if(y.k){var r={};function z(A,t){t.split(" ").forEach(function(B){var C=B.split("|");r[C[0]]=[A,C[1]?Number(C[1]):1];s.push(C[0])})}y.lR=o(y.l||hljs.IR,true);if(typeof y.k=="string"){z("keyword",y.k)}else{for(var x in y.k){if(!y.k.hasOwnProperty(x)){continue}z(x,y.k[x])}}y.k=r}if(w){if(y.bWK){y.b="\\b("+s.join("|")+")\\s"}y.bR=o(y.b?y.b:"\\B|\\b");if(!y.e&&!y.eW){y.e="\\B|\\b"}if(y.e){y.eR=o(y.e)}y.tE=y.e||"";if(y.eW&&w.tE){y.tE+=(y.e?"|":"")+w.tE}}if(y.i){y.iR=o(y.i)}if(y.r===undefined){y.r=1}if(!y.c){y.c=[]}for(var v=0;v<y.c.length;v++){if(y.c[v]=="self"){y.c[v]=y}p(y.c[v],y)}if(y.starts){p(y.starts,w)}var u=[];for(var v=0;v<y.c.length;v++){u.push(y.c[v].b)}if(y.tE){u.push(y.tE)}if(y.i){u.push(y.i)}y.t=u.length?o(u.join("|"),true):{exec:function(t){return null}}}p(q)}function d(D,E){function o(r,M){for(var L=0;L<M.c.length;L++){var K=M.c[L].bR.exec(r);if(K&&K.index==0){return M.c[L]}}}function s(K,r){if(K.e&&K.eR.test(r)){return K}if(K.eW){return s(K.parent,r)}}function t(r,K){return K.i&&K.iR.test(r)}function y(L,r){var K=F.cI?r[0].toLowerCase():r[0];return L.k.hasOwnProperty(K)&&L.k[K]}function G(){var K=l(w);if(!A.k){return K}var r="";var N=0;A.lR.lastIndex=0;var L=A.lR.exec(K);while(L){r+=K.substr(N,L.index-N);var M=y(A,L);if(M){v+=M[1];r+='<span class="'+M[0]+'">'+L[0]+"</span>"}else{r+=L[0]}N=A.lR.lastIndex;L=A.lR.exec(K)}return r+K.substr(N)}function z(){if(A.sL&&!e[A.sL]){return l(w)}var r=A.sL?d(A.sL,w):g(w);if(A.r>0){v+=r.keyword_count;B+=r.r}return'<span class="'+r.language+'">'+r.value+"</span>"}function J(){return A.sL!==undefined?z():G()}function I(L,r){var K=L.cN?'<span class="'+L.cN+'">':"";if(L.rB){x+=K;w=""}else{if(L.eB){x+=l(r)+K;w=""}else{x+=K;w=r}}A=Object.create(L,{parent:{value:A}});B+=L.r}function C(K,r){w+=K;if(r===undefined){x+=J();return 0}var L=o(r,A);if(L){x+=J();I(L,r);return L.rB?0:r.length}var M=s(A,r);if(M){if(!(M.rE||M.eE)){w+=r}x+=J();do{if(A.cN){x+="</span>"}A=A.parent}while(A!=M.parent);if(M.eE){x+=l(r)}w="";if(M.starts){I(M.starts,"")}return M.rE?0:r.length}if(t(r,A)){throw"Illegal"}w+=r;return r.length||1}var F=e[D];f(F);var A=F;var w="";var B=0;var v=0;var x="";try{var u,q,p=0;while(true){A.t.lastIndex=p;u=A.t.exec(E);if(!u){break}q=C(E.substr(p,u.index-p),u[0]);p=u.index+q}C(E.substr(p));return{r:B,keyword_count:v,value:x,language:D}}catch(H){if(H=="Illegal"){return{r:0,keyword_count:0,value:l(E)}}else{throw H}}}function g(s){var o={keyword_count:0,r:0,value:l(s)};var q=o;for(var p in e){if(!e.hasOwnProperty(p)){continue}var r=d(p,s);r.language=p;if(r.keyword_count+r.r>q.keyword_count+q.r){q=r}if(r.keyword_count+r.r>o.keyword_count+o.r){q=o;o=r}}if(q.language){o.second_best=q}return o}function i(q,p,o){if(p){q=q.replace(/^((<[^>]+>|\t)+)/gm,function(r,v,u,t){return v.replace(/\t/g,p)})}if(o){q=q.replace(/\n/g,"<br>")}return q}function m(r,u,p){var v=h(r,p);var t=a(r);if(t=="no-highlight"){return}var w=t?d(t,v):g(v);t=w.language;var o=c(r);if(o.length){var q=document.createElement("pre");q.innerHTML=w.value;w.value=j(o,c(q),v)}w.value=i(w.value,u,p);var s=r.className;if(!s.match("(\\s|^)(language-)?"+t+"(\\s|$)")){s=s?(s+" "+t):t}r.innerHTML=w.value;r.className=s;r.result={language:t,kw:w.keyword_count,re:w.r};if(w.second_best){r.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function n(){if(n.called){return}n.called=true;Array.prototype.map.call(document.getElementsByTagName("pre"),b).filter(Boolean).forEach(function(o){m(o,hljs.tabReplace)})}function k(){window.addEventListener("DOMContentLoaded",n,false);window.addEventListener("load",n,false)}var e={};this.LANGUAGES=e;this.highlight=d;this.highlightAuto=g;this.fixMarkup=i;this.highlightBlock=m;this.initHighlighting=n;this.initHighlightingOnLoad=k;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)";this.BNR="\\b(0b[01]+)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\[\\s\\S]",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.BNM={cN:"number",b:this.BNR,r:0};this.inherit=function(q,r){var o={};for(var p in q){o[p]=q[p]}if(r){for(var p in r){o[p]=r[p]}}return o}}();hljs.LANGUAGES.xml=function(a){var c="[A-Za-z0-9\\._:-]+";var b={eW:true,c:[{cN:"attribute",b:c,r:0},{b:'="',rB:true,e:'"',c:[{cN:"value",b:'"',eW:true}]},{b:"='",rB:true,e:"'",c:[{cN:"value",b:"'",eW:true}]},{b:"=",c:[{cN:"value",b:"[^\\s/>]+"}]}]};return{cI:true,c:[{cN:"pi",b:"<\\?",e:"\\?>",r:10},{cN:"doctype",b:"<!DOCTYPE",e:">",r:10,c:[{b:"\\[",e:"\\]"}]},{cN:"comment",b:"<!--",e:"-->",r:10},{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"<style(?=\\s|>|$)",e:">",k:{title:"style"},c:[b],starts:{e:"</style>",rE:true,sL:"css"}},{cN:"tag",b:"<script(?=\\s|>|$)",e:">",k:{title:"script"},c:[b],starts:{e:"<\/script>",rE:true,sL:"javascript"}},{b:"<%",e:"%>",sL:"vbscript"},{cN:"tag",b:"</?",e:"/?>",c:[{cN:"title",b:"[^ />]+"},b]}]}}(hljs);hljs.LANGUAGES.markdown=function(a){return{c:[{cN:"header",b:"^#{1,3}",e:"$"},{cN:"header",b:"^.+?\\n[=-]{2,}$"},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",b:"\\*.+?\\*"},{cN:"emphasis",b:"_.+?_",r:0},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",b:"`.+?`"},{cN:"code",b:"^ ",e:"$",r:0},{cN:"horizontal_rule",b:"^-{3,}",e:"$"},{b:"\\[.+?\\]\\(.+?\\)",rB:true,c:[{cN:"link_label",b:"\\[.+\\]"},{cN:"link_url",b:"\\(",e:"\\)",eB:true,eE:true}]}]}}(hljs);
|
js/markdown/adminhtml/highlight/styles/xcode.css
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
|
3 |
+
XCode style (c) Angel Garcia <angelgarcia.mail@gmail.com>
|
4 |
+
|
5 |
+
*/
|
6 |
+
|
7 |
+
pre code {
|
8 |
+
display: block; padding: 0.5em;
|
9 |
+
background: #fff; color: black;
|
10 |
+
}
|
11 |
+
|
12 |
+
pre .comment,
|
13 |
+
pre .template_comment,
|
14 |
+
pre .javadoc,
|
15 |
+
pre .comment * {
|
16 |
+
color: rgb(0,106,0);
|
17 |
+
}
|
18 |
+
|
19 |
+
pre .keyword,
|
20 |
+
pre .literal,
|
21 |
+
pre .nginx .title {
|
22 |
+
color: rgb(170,13,145);
|
23 |
+
}
|
24 |
+
pre .method,
|
25 |
+
pre .list .title,
|
26 |
+
pre .tag .title,
|
27 |
+
pre .setting .value,
|
28 |
+
pre .winutils,
|
29 |
+
pre .tex .command,
|
30 |
+
pre .http .title,
|
31 |
+
pre .request,
|
32 |
+
pre .status {
|
33 |
+
color: #008;
|
34 |
+
}
|
35 |
+
|
36 |
+
pre .envvar,
|
37 |
+
pre .tex .special {
|
38 |
+
color: #660;
|
39 |
+
}
|
40 |
+
|
41 |
+
pre .string {
|
42 |
+
color: rgb(196,26,22);
|
43 |
+
}
|
44 |
+
pre .tag .value,
|
45 |
+
pre .cdata,
|
46 |
+
pre .filter .argument,
|
47 |
+
pre .attr_selector,
|
48 |
+
pre .apache .cbracket,
|
49 |
+
pre .date,
|
50 |
+
pre .regexp {
|
51 |
+
color: #080;
|
52 |
+
}
|
53 |
+
|
54 |
+
pre .sub .identifier,
|
55 |
+
pre .pi,
|
56 |
+
pre .tag,
|
57 |
+
pre .tag .keyword,
|
58 |
+
pre .decorator,
|
59 |
+
pre .ini .title,
|
60 |
+
pre .shebang,
|
61 |
+
pre .prompt,
|
62 |
+
pre .hexcolor,
|
63 |
+
pre .rules .value,
|
64 |
+
pre .css .value .number,
|
65 |
+
pre .symbol,
|
66 |
+
pre .symbol .string,
|
67 |
+
pre .number,
|
68 |
+
pre .css .function,
|
69 |
+
pre .clojure .title,
|
70 |
+
pre .clojure .built_in {
|
71 |
+
color: rgb(28,0,207);
|
72 |
+
}
|
73 |
+
|
74 |
+
pre .class .title,
|
75 |
+
pre .haskell .type,
|
76 |
+
pre .smalltalk .class,
|
77 |
+
pre .javadoctag,
|
78 |
+
pre .yardoctag,
|
79 |
+
pre .phpdoc,
|
80 |
+
pre .typename,
|
81 |
+
pre .tag .attribute,
|
82 |
+
pre .doctype,
|
83 |
+
pre .class .id,
|
84 |
+
pre .built_in,
|
85 |
+
pre .setting,
|
86 |
+
pre .params,
|
87 |
+
pre .clojure .attribute {
|
88 |
+
color: rgb(92,38,153);
|
89 |
+
}
|
90 |
+
|
91 |
+
pre .variable {
|
92 |
+
color: rgb(63,110,116);
|
93 |
+
}
|
94 |
+
pre .css .tag,
|
95 |
+
pre .rules .property,
|
96 |
+
pre .pseudo,
|
97 |
+
pre .subst {
|
98 |
+
color: #000;
|
99 |
+
}
|
100 |
+
|
101 |
+
pre .css .class, pre .css .id {
|
102 |
+
color: #9B703F;
|
103 |
+
}
|
104 |
+
|
105 |
+
pre .value .important {
|
106 |
+
color: #ff7700;
|
107 |
+
font-weight: bold;
|
108 |
+
}
|
109 |
+
|
110 |
+
pre .rules .keyword {
|
111 |
+
color: #C5AF75;
|
112 |
+
}
|
113 |
+
|
114 |
+
pre .annotation,
|
115 |
+
pre .apache .sqbracket,
|
116 |
+
pre .nginx .built_in {
|
117 |
+
color: #9B859D;
|
118 |
+
}
|
119 |
+
|
120 |
+
pre .preprocessor,
|
121 |
+
pre .preprocessor * {
|
122 |
+
color: rgb(100,56,32);
|
123 |
+
}
|
124 |
+
|
125 |
+
pre .tex .formula {
|
126 |
+
background-color: #EEE;
|
127 |
+
font-style: italic;
|
128 |
+
}
|
129 |
+
|
130 |
+
pre .diff .header,
|
131 |
+
pre .chunk {
|
132 |
+
color: #808080;
|
133 |
+
font-weight: bold;
|
134 |
+
}
|
135 |
+
|
136 |
+
pre .diff .change {
|
137 |
+
background-color: #BCCFF9;
|
138 |
+
}
|
139 |
+
|
140 |
+
pre .addition {
|
141 |
+
background-color: #BAEEBA;
|
142 |
+
}
|
143 |
+
|
144 |
+
pre .deletion {
|
145 |
+
background-color: #FFC8BD;
|
146 |
+
}
|
147 |
+
|
148 |
+
pre .comment .yardoctag {
|
149 |
+
font-weight: bold;
|
150 |
+
}
|
151 |
+
|
152 |
+
pre .method .id {
|
153 |
+
color: #000;
|
154 |
+
}
|
js/markdown/adminhtml/markdown.js
ADDED
@@ -0,0 +1,715 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* @category SchumacherFM_Markdown
|
3 |
+
* @package JavaScript
|
4 |
+
* @author Cyrill at Schumacher dot fm / @SchumacherFM
|
5 |
+
* @copyright Copyright (c)
|
6 |
+
*/
|
7 |
+
/*global $,marked,varienGlobalEvents,Ajax,hljs,FileReaderJS,Event,encode_base64,reMarked*/
|
8 |
+
;
|
9 |
+
(function () {
|
10 |
+
'use strict';
|
11 |
+
var
|
12 |
+
_markDownGlobalConfig = {},
|
13 |
+
epicEditorInstances = {},
|
14 |
+
EPIC_EDITOR_PREFIX = 'epiceditor_EE_',
|
15 |
+
isViewMarkdownSourceHtml = false,
|
16 |
+
_initializedFileReaderContainer = {},
|
17 |
+
_textAreaCurrentCaretObject = {}, // set by the onClick event
|
18 |
+
_toggleMarkdownSourceOriginalMarkdown = '';
|
19 |
+
|
20 |
+
/**
|
21 |
+
*
|
22 |
+
* @param str string
|
23 |
+
* @returns boolean|string
|
24 |
+
* @private
|
25 |
+
*/
|
26 |
+
function _checkHttp(str) {
|
27 |
+
|
28 |
+
if (!str || false === str || str.indexOf('http') === -1) {
|
29 |
+
return false;
|
30 |
+
}
|
31 |
+
return str;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* inits the global md config
|
36 |
+
* @returns bool
|
37 |
+
* @private
|
38 |
+
*/
|
39 |
+
function _initGlobalConfig() {
|
40 |
+
|
41 |
+
var config = JSON.parse($('markdownGlobalConfig').readAttribute('data-config') || '{}');
|
42 |
+
if (config.dt === undefined) {
|
43 |
+
return console.log('Markdown Global Config not found. General error!');
|
44 |
+
}
|
45 |
+
|
46 |
+
_markDownGlobalConfig = {
|
47 |
+
tag: decodeURIComponent(config.dt),
|
48 |
+
uploadUrl: _checkHttp(config.fuu || false),
|
49 |
+
mediaBaseUrl: _checkHttp(config.phi || false),
|
50 |
+
extraRendererUrl: _checkHttp(config.eru || false),
|
51 |
+
eeLoadOnClick: config.eeloc || false,
|
52 |
+
reMarkedCfg: decodeURIComponent(config.rmc || '{}').evalJSON(true)
|
53 |
+
};
|
54 |
+
return true;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
*
|
59 |
+
* @param variable mixed
|
60 |
+
* @returns {boolean}
|
61 |
+
* @private
|
62 |
+
*/
|
63 |
+
function _isObject(variable) {
|
64 |
+
return Object.prototype.toString.call(variable) === '[object Object]';
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
*
|
69 |
+
* @param variable mixed
|
70 |
+
* @returns {boolean}
|
71 |
+
* @private
|
72 |
+
*/
|
73 |
+
function _isFunction(variable) {
|
74 |
+
return Object.prototype.toString.call(variable) === '[object Function]';
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
*
|
79 |
+
* @returns {boolean}
|
80 |
+
* @private
|
81 |
+
*/
|
82 |
+
function _isEpicEditorEnabled() {
|
83 |
+
return window.EpicEditor !== undefined;
|
84 |
+
}
|
85 |
+
|
86 |
+
/**
|
87 |
+
*
|
88 |
+
* @returns {boolean}
|
89 |
+
* @private
|
90 |
+
*/
|
91 |
+
function _isFileReaderEnabled() {
|
92 |
+
return window.FileReader !== undefined;
|
93 |
+
}
|
94 |
+
|
95 |
+
function mdExternalUrl(url) {
|
96 |
+
window.open(url);
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
*
|
101 |
+
* @param textareaId
|
102 |
+
*/
|
103 |
+
function toggleMarkdown(textareaId) {
|
104 |
+
|
105 |
+
|
106 |
+
if ($(textareaId).value.indexOf(_markDownGlobalConfig.tag) === -1) {
|
107 |
+
|
108 |
+
var instance = epicEditorInstances[textareaId] || false;
|
109 |
+
if (instance && instance.is('loaded')) {
|
110 |
+
instance.getElement('editor').body.innerHTML = _markDownGlobalConfig.tag + "<br>\n" + instance.getElement('editor').body.innerHTML;
|
111 |
+
} else {
|
112 |
+
$(textareaId).value = _markDownGlobalConfig.tag + "\n" + $(textareaId).value;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
alert('Markdown enabled with tag: "' + _markDownGlobalConfig.tag + '"');
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Shows the generated source html code
|
120 |
+
* @param object element
|
121 |
+
* @param string textAreaId
|
122 |
+
* @returns uninteresting
|
123 |
+
*/
|
124 |
+
function toggleMarkdownSource(element, textAreaId) {
|
125 |
+
var _loadEpic = false,
|
126 |
+
_instance,
|
127 |
+
$textAreaId = $(textAreaId);
|
128 |
+
|
129 |
+
if (true === isViewMarkdownSourceHtml) {
|
130 |
+
isViewMarkdownSourceHtml = false;
|
131 |
+
element.removeClassName('success');
|
132 |
+
|
133 |
+
// restore original markdown, if not it is lost
|
134 |
+
if (_toggleMarkdownSourceOriginalMarkdown.length > 10) {
|
135 |
+
$textAreaId.writeAttribute('readonly', false);
|
136 |
+
$textAreaId.value = _toggleMarkdownSourceOriginalMarkdown;
|
137 |
+
_toggleMarkdownSourceOriginalMarkdown = '';
|
138 |
+
}
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
|
142 |
+
if (_markDownGlobalConfig.tag !== '' && $textAreaId.value.indexOf(_markDownGlobalConfig.tag) === -1) {
|
143 |
+
alert('Markdown not found');
|
144 |
+
return false;
|
145 |
+
}
|
146 |
+
|
147 |
+
_instance = epicEditorInstances[textAreaId] || false;
|
148 |
+
_loadEpic = _isEpicEditorEnabled() && (false === _instance || (false !== _instance && _instance.is('unloaded')));
|
149 |
+
|
150 |
+
if (true === _loadEpic) {
|
151 |
+
toggleEpicEditor(element, textAreaId);
|
152 |
+
_instance = epicEditorInstances[textAreaId] || false;
|
153 |
+
}
|
154 |
+
|
155 |
+
isViewMarkdownSourceHtml = true;
|
156 |
+
element.addClassName('success');
|
157 |
+
|
158 |
+
if (_instance && _isObject(_instance)) {
|
159 |
+
_instance.preview();
|
160 |
+
} else {
|
161 |
+
_toggleMarkdownSourceOriginalMarkdown = $textAreaId.value;
|
162 |
+
// no cache available oroginal MD is lost.
|
163 |
+
$textAreaId.value = _parserDefault(_toggleMarkdownSourceOriginalMarkdown, $textAreaId);
|
164 |
+
$textAreaId.writeAttribute('readonly', true);
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
*
|
170 |
+
* @param string content
|
171 |
+
* @returns {promise.Promise}
|
172 |
+
* @private
|
173 |
+
*/
|
174 |
+
function _mdExtraRender(content) {
|
175 |
+
|
176 |
+
var p = new promise.Promise(),
|
177 |
+
ar = new Ajax.Request(_markDownGlobalConfig.extraRendererUrl, {
|
178 |
+
onSuccess: function (response) {
|
179 |
+
p.done(null, response.responseText);
|
180 |
+
},
|
181 |
+
method: 'post',
|
182 |
+
parameters: {
|
183 |
+
'content': content
|
184 |
+
}
|
185 |
+
});
|
186 |
+
|
187 |
+
return p;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* so rendering via markdown extra works only if there is one textarea field on the page
|
192 |
+
* which creates one instance ... this limitation is due to the promise -> then() ... maybe there are better ways
|
193 |
+
* fallback is marked()
|
194 |
+
* @private
|
195 |
+
*/
|
196 |
+
function _getEpicEditorActiveInstance() {
|
197 |
+
|
198 |
+
if (Object.keys(epicEditorInstances).length !== 1) {
|
199 |
+
return false;
|
200 |
+
}
|
201 |
+
|
202 |
+
var keys = Object.keys(epicEditorInstances),
|
203 |
+
oneKey = keys[0];
|
204 |
+
|
205 |
+
return epicEditorInstances[oneKey];
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
*
|
210 |
+
* @param string htmlString
|
211 |
+
* @returns string
|
212 |
+
* @private
|
213 |
+
*/
|
214 |
+
function _highlight(htmlString) {
|
215 |
+
if (true === isViewMarkdownSourceHtml) {
|
216 |
+
htmlString = '<pre class="hljs">' + hljs.highlight('xml', htmlString).value + '</pre>';
|
217 |
+
}
|
218 |
+
return htmlString;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
*
|
223 |
+
* @param content string
|
224 |
+
* @returns string
|
225 |
+
* @private
|
226 |
+
*/
|
227 |
+
function _parserBefore(content) {
|
228 |
+
var imgUrl = '',
|
229 |
+
mediaRegex = /\{\{media\s+url="([^"]+)"\s*\}\}/i,
|
230 |
+
matches = null;
|
231 |
+
|
232 |
+
if (_markDownGlobalConfig.tag !== '') {
|
233 |
+
content = content.replace(_markDownGlobalConfig.tag, '');
|
234 |
+
}
|
235 |
+
|
236 |
+
if (false !== _markDownGlobalConfig.mediaBaseUrl) {
|
237 |
+
while (mediaRegex.test(content)) {
|
238 |
+
matches = mediaRegex.exec(content);
|
239 |
+
if (null !== matches && matches[1] !== undefined) {
|
240 |
+
imgUrl = _markDownGlobalConfig.mediaBaseUrl + matches[1];
|
241 |
+
content = content.replace(matches[0], imgUrl);
|
242 |
+
}
|
243 |
+
}
|
244 |
+
}
|
245 |
+
return content;
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
*
|
250 |
+
* default parsing without syntax highlightning
|
251 |
+
*
|
252 |
+
* @param string content
|
253 |
+
* @param object $textArea
|
254 |
+
* @returns string
|
255 |
+
* @private
|
256 |
+
*/
|
257 |
+
function _parserDefault(content, $textArea) {
|
258 |
+
var pContent = {};
|
259 |
+
|
260 |
+
if (content.length > 10 && _markDownGlobalConfig.extraRendererUrl) {
|
261 |
+
pContent = _mdExtraRender(content);
|
262 |
+
pContent.then(function (error, html) {
|
263 |
+
$textArea.value = html;
|
264 |
+
});
|
265 |
+
return '<h3>Preview will be available shortly ...</h3>';
|
266 |
+
}
|
267 |
+
return marked(_parserBefore(content));
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* todo replace {{media url=""}} with a dummy preview image, otherwise loading errors will occur
|
272 |
+
* also test that in product and categorie desc fields
|
273 |
+
* @param string content
|
274 |
+
* @param object $textArea
|
275 |
+
* @returns string
|
276 |
+
* @private
|
277 |
+
*/
|
278 |
+
function _parserEpicEditor(content, $textArea) {
|
279 |
+
var currentActiveInstance = _getEpicEditorActiveInstance(),
|
280 |
+
pContent = {};
|
281 |
+
|
282 |
+
if (content.length > 10 && _markDownGlobalConfig.extraRendererUrl) {
|
283 |
+
pContent = _mdExtraRender(content);
|
284 |
+
pContent.then(function (error, html) {
|
285 |
+
if (currentActiveInstance && currentActiveInstance.is('loaded')) {
|
286 |
+
currentActiveInstance.getElement('previewer').body.innerHTML = _highlight(html);
|
287 |
+
} else {
|
288 |
+
$textArea.value = html;
|
289 |
+
}
|
290 |
+
});
|
291 |
+
return _highlight('<h3>Preview will be available shortly ...</h3>');
|
292 |
+
}
|
293 |
+
|
294 |
+
return _highlight(marked(_parserBefore(content)));
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
*
|
299 |
+
* @returns {{container: null, textarea: null, basePath: string, clientSideStorage: boolean, parser: Function, localStorageName: string, useNativeFullscreen: boolean, file: {name: string, defaultContent: string, autoSave: number}, theme: {base: string, preview: string, editor: string}, button: {preview: boolean, fullscreen: boolean, bar: string}, focusOnLoad: boolean, shortcut: {modifier: number, fullscreen: number, preview: number}, string: {togglePreview: string, toggleEdit: string, toggleFullscreen: string}, autogrow: {minHeight: number, maxHeight: number, scroll: boolean}}}
|
300 |
+
* @private
|
301 |
+
*/
|
302 |
+
function _getDefaultEpicEditorOptions() {
|
303 |
+
return {
|
304 |
+
container: null,
|
305 |
+
textarea: null,
|
306 |
+
basePath: null, // will be set via Mage Helper
|
307 |
+
clientSideStorage: true,
|
308 |
+
parser: _parserEpicEditor,
|
309 |
+
localStorageName: 'epiceditor',
|
310 |
+
useNativeFullscreen: true,
|
311 |
+
file: {
|
312 |
+
name: 'epiceditor',
|
313 |
+
defaultContent: '',
|
314 |
+
autoSave: 100
|
315 |
+
},
|
316 |
+
theme: {
|
317 |
+
base: 'themes/base/epiceditor.css',
|
318 |
+
preview: 'themes/preview/githubNxcode.css',
|
319 |
+
editor: 'themes/editor/epic-light.css'
|
320 |
+
},
|
321 |
+
button: {
|
322 |
+
preview: true,
|
323 |
+
fullscreen: true,
|
324 |
+
bar: "show"
|
325 |
+
},
|
326 |
+
focusOnLoad: false,
|
327 |
+
shortcut: {
|
328 |
+
modifier: 18,
|
329 |
+
fullscreen: 70,
|
330 |
+
preview: 80
|
331 |
+
},
|
332 |
+
string: {
|
333 |
+
togglePreview: 'Toggle Preview Mode',
|
334 |
+
toggleEdit: 'Toggle Edit Mode',
|
335 |
+
toggleFullscreen: 'Enter Fullscreen'
|
336 |
+
},
|
337 |
+
autogrow: {
|
338 |
+
minHeight: 400,
|
339 |
+
maxHeight: 700,
|
340 |
+
scroll: true
|
341 |
+
}
|
342 |
+
};
|
343 |
+
}
|
344 |
+
|
345 |
+
/**
|
346 |
+
*
|
347 |
+
* @param event
|
348 |
+
* @param element
|
349 |
+
* @private
|
350 |
+
*/
|
351 |
+
function _createEpicEditorInstances(event, element) {
|
352 |
+
|
353 |
+
if (element === null || element === undefined) {
|
354 |
+
throw 'Wysiwyg only bug ...';
|
355 |
+
}
|
356 |
+
|
357 |
+
var
|
358 |
+
epicHtmlId = EPIC_EDITOR_PREFIX + (element.id || ''),
|
359 |
+
$epicHtmlId = $(epicHtmlId),
|
360 |
+
textAreaId = element.id || '',
|
361 |
+
editorOptions = _getDefaultEpicEditorOptions(),
|
362 |
+
instanceId = textAreaId,
|
363 |
+
epicEditorInstance = {},
|
364 |
+
userConfig = {};
|
365 |
+
|
366 |
+
if (!epicEditorInstances[instanceId]) {
|
367 |
+
userConfig = decodeURIComponent($epicHtmlId.readAttribute('data-config') || '{}').evalJSON(true);
|
368 |
+
|
369 |
+
Object.extend(editorOptions, userConfig);
|
370 |
+
editorOptions.container = epicHtmlId;
|
371 |
+
editorOptions.textarea = textAreaId;
|
372 |
+
editorOptions.localStorageName = textAreaId;
|
373 |
+
|
374 |
+
element.hide();
|
375 |
+
epicEditorInstance = new window.EpicEditor(editorOptions);
|
376 |
+
epicEditorInstance
|
377 |
+
.on('load', function () {
|
378 |
+
$epicHtmlId.setStyle({
|
379 |
+
display: 'block',
|
380 |
+
height: parseInt(editorOptions.autogrow.maxHeight || 700, 10) + 'px'
|
381 |
+
});
|
382 |
+
epicEditorInstance.reflow();
|
383 |
+
})
|
384 |
+
.on('unload', function () {
|
385 |
+
$epicHtmlId.setStyle({
|
386 |
+
display: 'none'
|
387 |
+
});
|
388 |
+
});
|
389 |
+
epicEditorInstances[instanceId] = epicEditorInstance.load();
|
390 |
+
}
|
391 |
+
}
|
392 |
+
|
393 |
+
/**
|
394 |
+
*
|
395 |
+
* @param element this
|
396 |
+
* @param textAreaId string
|
397 |
+
* @return false
|
398 |
+
*/
|
399 |
+
function toggleEpicEditor(element, textAreaId) {
|
400 |
+
|
401 |
+
var
|
402 |
+
instanceId = textAreaId,
|
403 |
+
instance = epicEditorInstances[instanceId] || false;
|
404 |
+
|
405 |
+
if (false === instance) {
|
406 |
+
_createEpicEditorInstances(null, $(textAreaId));
|
407 |
+
element.addClassName('success');
|
408 |
+
return false;
|
409 |
+
}
|
410 |
+
|
411 |
+
if (instance.is('loaded')) {
|
412 |
+
instance.unload();
|
413 |
+
$(textAreaId).show();
|
414 |
+
element.removeClassName('success');
|
415 |
+
} else {
|
416 |
+
$(textAreaId).hide();
|
417 |
+
instance.load();
|
418 |
+
element.addClassName('success');
|
419 |
+
}
|
420 |
+
return false;
|
421 |
+
}
|
422 |
+
|
423 |
+
/**
|
424 |
+
*
|
425 |
+
* @param fileUrl
|
426 |
+
* @returns {boolean}
|
427 |
+
* @private
|
428 |
+
*/
|
429 |
+
function _fileReaderAddImageToMarkdown(fileUrl) {
|
430 |
+
|
431 |
+
var
|
432 |
+
mdTpl = ' ![Alt_Text](' + fileUrl + ' "Logo_Title_Text") ',
|
433 |
+
prefix = _textAreaCurrentCaretObject.value.substring(0, _textAreaCurrentCaretObject.selectionEnd),
|
434 |
+
suffix = _textAreaCurrentCaretObject.value.substring(_textAreaCurrentCaretObject.selectionEnd);
|
435 |
+
|
436 |
+
_textAreaCurrentCaretObject.value = prefix + mdTpl + suffix;
|
437 |
+
prefix = '';
|
438 |
+
suffix = '';
|
439 |
+
return true;
|
440 |
+
}
|
441 |
+
|
442 |
+
/**
|
443 |
+
*
|
444 |
+
* @param target event.target
|
445 |
+
* @private
|
446 |
+
*/
|
447 |
+
function _createFileReaderInstance(target) {
|
448 |
+
|
449 |
+
if (encode_base64 === undefined) {
|
450 |
+
return console.log('FileReader not available because method encode_base64() is missing!');
|
451 |
+
}
|
452 |
+
|
453 |
+
if (false === _markDownGlobalConfig.uploadUrl) {
|
454 |
+
return console.log('FileReader upload url not available!');
|
455 |
+
}
|
456 |
+
|
457 |
+
var opts = {
|
458 |
+
dragClass: 'fReaderDrag',
|
459 |
+
accept: 'image/*',
|
460 |
+
readAsMap: {
|
461 |
+
'image/*': 'BinaryString'
|
462 |
+
},
|
463 |
+
readAsDefault: 'BinaryString',
|
464 |
+
on: {
|
465 |
+
load: function (e, file) {
|
466 |
+
|
467 |
+
var ar = new Ajax.Request(_markDownGlobalConfig.uploadUrl, {
|
468 |
+
onSuccess: function (response) {
|
469 |
+
var result = JSON.parse(response.responseText);
|
470 |
+
if (result && _isObject(result)) {
|
471 |
+
if (result.err === false) {
|
472 |
+
return _fileReaderAddImageToMarkdown(result.fileUrl);
|
473 |
+
}
|
474 |
+
if (result.err === true) {
|
475 |
+
alert('An error occurred:\n' + result.msg);
|
476 |
+
}
|
477 |
+
} else {
|
478 |
+
alert('An error occurred after uploading. No JSON found ...');
|
479 |
+
}
|
480 |
+
return false;
|
481 |
+
},
|
482 |
+
method: 'post',
|
483 |
+
parameters: {
|
484 |
+
'binaryData': encode_base64(e.target.result),
|
485 |
+
'file': JSON.stringify(file)
|
486 |
+
}
|
487 |
+
});
|
488 |
+
|
489 |
+
},
|
490 |
+
error: function (e, file) {
|
491 |
+
// Native ProgressEvent
|
492 |
+
alert('An error occurred. Please see console.log');
|
493 |
+
return console.log('error: ', e, file);
|
494 |
+
},
|
495 |
+
skip: function (e, file) {
|
496 |
+
return console.log('File format is not supported', file);
|
497 |
+
}
|
498 |
+
}
|
499 |
+
};
|
500 |
+
|
501 |
+
FileReaderJS.setupDrop(target, opts);
|
502 |
+
_initializedFileReaderContainer[target.id] = true;
|
503 |
+
}
|
504 |
+
|
505 |
+
/**
|
506 |
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/FileReader
|
507 |
+
* @param _epicEditorInstance window.EpicEditor loaded
|
508 |
+
* @private
|
509 |
+
*/
|
510 |
+
function _createFileReader(event) {
|
511 |
+
var target = event.target || event.srcElement;
|
512 |
+
|
513 |
+
_textAreaCurrentCaretObject = target;
|
514 |
+
|
515 |
+
// check if already initialized
|
516 |
+
if (_initializedFileReaderContainer[target.id] === undefined) {
|
517 |
+
_createFileReaderInstance(target);
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
/**
|
522 |
+
*
|
523 |
+
* @returns {reMarked}
|
524 |
+
* @private
|
525 |
+
*/
|
526 |
+
function _getReMarked() {
|
527 |
+
var options = {
|
528 |
+
link_list: false, // render links as references, create link list as appendix
|
529 |
+
h1_setext: true, // underline h1 headers
|
530 |
+
h2_setext: true, // underline h2 headers
|
531 |
+
h_atx_suf: false, // header suffixes (###)
|
532 |
+
gfm_code: false, // gfm code blocks (```)
|
533 |
+
li_bullet: "*", // list item bullet style
|
534 |
+
hr_char: "-", // hr style
|
535 |
+
indnt_str: " ", // indentation string
|
536 |
+
bold_char: "*", // char used for strong
|
537 |
+
emph_char: "_", // char used for em
|
538 |
+
gfm_del: true, // ~~strikeout~~ for <del>strikeout</del>
|
539 |
+
gfm_tbls: false, // markdown-extra tables @SchumacherFM: if true the error on line 518 in remarked.js :-(
|
540 |
+
tbl_edges: false, // show side edges on tables
|
541 |
+
hash_lnks: false, // anchors w/hash hrefs as links
|
542 |
+
br_only: false // avoid using " " as line break indicator
|
543 |
+
};
|
544 |
+
Object.extend(options, _markDownGlobalConfig.reMarkedCfg);
|
545 |
+
return new reMarked(options);
|
546 |
+
}
|
547 |
+
|
548 |
+
/**
|
549 |
+
* renders html to markdown
|
550 |
+
* @param textAreaId string
|
551 |
+
*/
|
552 |
+
function htmlToMarkDown(element, textAreaId) {
|
553 |
+
var html = $(textAreaId).value || '';
|
554 |
+
|
555 |
+
var _instance = epicEditorInstances[textAreaId] || false;
|
556 |
+
var _loadedEpic = _isEpicEditorEnabled() && false !== _instance && _instance.is('loaded');
|
557 |
+
if (true === _loadedEpic) {
|
558 |
+
toggleEpicEditor(element, textAreaId);
|
559 |
+
}
|
560 |
+
|
561 |
+
|
562 |
+
if (_markDownGlobalConfig.tag !== '' && html.indexOf(_markDownGlobalConfig.tag) === -1) {
|
563 |
+
$(textAreaId).value = _markDownGlobalConfig.tag + '\n' + _getReMarked().render(html);
|
564 |
+
}
|
565 |
+
if (_markDownGlobalConfig.tag === '') {
|
566 |
+
$(textAreaId).value = _getReMarked().render(html);
|
567 |
+
}
|
568 |
+
}
|
569 |
+
|
570 |
+
/**
|
571 |
+
* loads the filereader, epiceditor
|
572 |
+
*/
|
573 |
+
function _mdInitialize() {
|
574 |
+
_initGlobalConfig();
|
575 |
+
var parentElementIds = ['product_edit_form', 'edit_form', 'category-edit-container', 'email_template_edit_form'];
|
576 |
+
if (varienGlobalEvents) {
|
577 |
+
varienGlobalEvents.fireEvent('mdLoadForms', parentElementIds);
|
578 |
+
}
|
579 |
+
|
580 |
+
// loading multiple instances on one page
|
581 |
+
// only works with event delegation due category edit page ...
|
582 |
+
// fire event for customization varienGlobalEvents.attachEventHandler('showTab', function (e) {...}
|
583 |
+
parentElementIds.forEach(function (elementId) {
|
584 |
+
var $elementId = $(elementId);
|
585 |
+
if ($elementId) {
|
586 |
+
// some things are only possible with event delegation ...
|
587 |
+
if (true === _isEpicEditorEnabled() && true === _markDownGlobalConfig.eeLoadOnClick) {
|
588 |
+
$elementId.on('click', 'textarea.initEpicEditor', _createEpicEditorInstances);
|
589 |
+
}
|
590 |
+
if (true === _isFileReaderEnabled()) {
|
591 |
+
$elementId.on('click', 'textarea.initFileReader', _createFileReader);
|
592 |
+
}
|
593 |
+
|
594 |
+
}
|
595 |
+
});
|
596 |
+
}
|
597 |
+
|
598 |
+
this.mdExternalUrl = mdExternalUrl;
|
599 |
+
this.toggleMarkdown = toggleMarkdown;
|
600 |
+
this.toggleEpicEditor = toggleEpicEditor;
|
601 |
+
this.toggleMarkdownSource = toggleMarkdownSource;
|
602 |
+
this.htmlToMarkDown = htmlToMarkDown;
|
603 |
+
|
604 |
+
document.observe('dom:loaded', _mdInitialize);
|
605 |
+
|
606 |
+
}).
|
607 |
+
call(function () {
|
608 |
+
return this || (typeof window !== 'undefined' ? window : global);
|
609 |
+
}());
|
610 |
+
|
611 |
+
/*
|
612 |
+
* Copyright 2012-2013 (c) Pierre Duquesne <stackp@online.fr>
|
613 |
+
* Licensed under the New BSD License.
|
614 |
+
* https://github.com/stackp/promisejs
|
615 |
+
* https://raw.github.com/stackp/promisejs/master/promise.js
|
616 |
+
* modified by @SchumacherFM
|
617 |
+
*/
|
618 |
+
|
619 |
+
(function (exports) {
|
620 |
+
'use strict';
|
621 |
+
|
622 |
+
function Promise() {
|
623 |
+
this._callbacks = [];
|
624 |
+
}
|
625 |
+
|
626 |
+
Promise.prototype.then = function (func, context) {
|
627 |
+
var p;
|
628 |
+
if (this._isdone) {
|
629 |
+
p = func.apply(context, this.result);
|
630 |
+
} else {
|
631 |
+
p = new Promise();
|
632 |
+
this._callbacks.push(function () {
|
633 |
+
var res = func.apply(context, arguments);
|
634 |
+
if (res && _isFunction(res.then))
|
635 |
+
res.then(p.done, p);
|
636 |
+
});
|
637 |
+
}
|
638 |
+
return p;
|
639 |
+
};
|
640 |
+
|
641 |
+
Promise.prototype.done = function () {
|
642 |
+
this.result = arguments;
|
643 |
+
this._isdone = true;
|
644 |
+
for (var i = 0; i < this._callbacks.length; i++) {
|
645 |
+
this._callbacks[i].apply(null, arguments);
|
646 |
+
}
|
647 |
+
this._callbacks = [];
|
648 |
+
};
|
649 |
+
|
650 |
+
function join(promises) {
|
651 |
+
var p = new Promise();
|
652 |
+
var results = [];
|
653 |
+
|
654 |
+
if (!promises || !promises.length) {
|
655 |
+
p.done(results);
|
656 |
+
return p;
|
657 |
+
}
|
658 |
+
|
659 |
+
var numdone = 0;
|
660 |
+
var total = promises.length;
|
661 |
+
|
662 |
+
function notifier(i) {
|
663 |
+
return function () {
|
664 |
+
numdone += 1;
|
665 |
+
results[i] = Array.prototype.slice.call(arguments);
|
666 |
+
if (numdone === total) {
|
667 |
+
p.done(results);
|
668 |
+
}
|
669 |
+
};
|
670 |
+
}
|
671 |
+
|
672 |
+
for (var i = 0; i < total; i++) {
|
673 |
+
promises[i].then(notifier(i));
|
674 |
+
}
|
675 |
+
|
676 |
+
return p;
|
677 |
+
}
|
678 |
+
|
679 |
+
function chain(funcs, args) {
|
680 |
+
var p = new Promise();
|
681 |
+
if (funcs.length === 0) {
|
682 |
+
p.done.apply(p, args);
|
683 |
+
} else {
|
684 |
+
funcs[0].apply(null, args).then(function () {
|
685 |
+
funcs.splice(0, 1);
|
686 |
+
chain(funcs, arguments).then(function () {
|
687 |
+
p.done.apply(p, arguments);
|
688 |
+
});
|
689 |
+
});
|
690 |
+
}
|
691 |
+
return p;
|
692 |
+
}
|
693 |
+
|
694 |
+
|
695 |
+
var promise = {
|
696 |
+
Promise: Promise,
|
697 |
+
join: join,
|
698 |
+
chain: chain,
|
699 |
+
|
700 |
+
/* Error codes */
|
701 |
+
ENOXHR: 1,
|
702 |
+
ETIMEOUT: 2
|
703 |
+
|
704 |
+
};
|
705 |
+
|
706 |
+
if (typeof define === 'function' && define.amd) {
|
707 |
+
/* AMD support */
|
708 |
+
define(function () {
|
709 |
+
return promise;
|
710 |
+
});
|
711 |
+
} else {
|
712 |
+
exports.promise = promise;
|
713 |
+
}
|
714 |
+
|
715 |
+
})(this);
|
js/markdown/adminhtml/marked.js
ADDED
@@ -0,0 +1,1165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* marked - a markdown parser
|
3 |
+
* Copyright (c) 2011-2013, Christopher Jeffrey. (MIT Licensed)
|
4 |
+
* https://github.com/chjj/marked
|
5 |
+
*/
|
6 |
+
|
7 |
+
;(function() {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Block-Level Grammar
|
11 |
+
*/
|
12 |
+
|
13 |
+
var block = {
|
14 |
+
newline: /^\n+/,
|
15 |
+
code: /^( {4}[^\n]+\n*)+/,
|
16 |
+
fences: noop,
|
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*$)/,
|
24 |
+
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
|
25 |
+
table: noop,
|
26 |
+
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
|
27 |
+
text: /^[^\n]+/
|
28 |
+
};
|
29 |
+
|
30 |
+
block.bullet = /(?:[*+-]|\d+\.)/;
|
31 |
+
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
|
32 |
+
block.item = replace(block.item, 'gm')
|
33 |
+
(/bull/g, block.bullet)
|
34 |
+
();
|
35 |
+
|
36 |
+
block.list = replace(block.list)
|
37 |
+
(/bull/g, block.bullet)
|
38 |
+
('hr', /\n+(?=(?: *[-*_]){3,} *(?:\n+|$))/)
|
39 |
+
();
|
40 |
+
|
41 |
+
block._tag = '(?!(?:'
|
42 |
+
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
|
43 |
+
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
|
44 |
+
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|@)\\b';
|
45 |
+
|
46 |
+
block.html = replace(block.html)
|
47 |
+
('comment', /<!--[\s\S]*?-->/)
|
48 |
+
('closed', /<(tag)[\s\S]+?<\/\1>/)
|
49 |
+
('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
|
50 |
+
(/tag/g, block._tag)
|
51 |
+
();
|
52 |
+
|
53 |
+
block.paragraph = replace(block.paragraph)
|
54 |
+
('hr', block.hr)
|
55 |
+
('heading', block.heading)
|
56 |
+
('lheading', block.lheading)
|
57 |
+
('blockquote', block.blockquote)
|
58 |
+
('tag', '<' + block._tag)
|
59 |
+
('def', block.def)
|
60 |
+
();
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Normal Block Grammar
|
64 |
+
*/
|
65 |
+
|
66 |
+
block.normal = merge({}, block);
|
67 |
+
|
68 |
+
/**
|
69 |
+
* GFM Block Grammar
|
70 |
+
*/
|
71 |
+
|
72 |
+
block.gfm = merge({}, block.normal, {
|
73 |
+
fences: /^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,
|
74 |
+
paragraph: /^/
|
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 |
+
/**
|
84 |
+
* GFM + Tables Block Grammar
|
85 |
+
*/
|
86 |
+
|
87 |
+
block.tables = merge({}, block.gfm, {
|
88 |
+
nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
|
89 |
+
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
|
90 |
+
});
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Block Lexer
|
94 |
+
*/
|
95 |
+
|
96 |
+
function Lexer(options) {
|
97 |
+
this.tokens = [];
|
98 |
+
this.tokens.links = {};
|
99 |
+
this.options = options || marked.defaults;
|
100 |
+
this.rules = block.normal;
|
101 |
+
|
102 |
+
if (this.options.gfm) {
|
103 |
+
if (this.options.tables) {
|
104 |
+
this.rules = block.tables;
|
105 |
+
} else {
|
106 |
+
this.rules = block.gfm;
|
107 |
+
}
|
108 |
+
}
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Expose Block Rules
|
113 |
+
*/
|
114 |
+
|
115 |
+
Lexer.rules = block;
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Static Lex Method
|
119 |
+
*/
|
120 |
+
|
121 |
+
Lexer.lex = function(src, options) {
|
122 |
+
var lexer = new Lexer(options);
|
123 |
+
return lexer.lex(src);
|
124 |
+
};
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Preprocessing
|
128 |
+
*/
|
129 |
+
|
130 |
+
Lexer.prototype.lex = function(src) {
|
131 |
+
src = src
|
132 |
+
.replace(/\r\n|\r/g, '\n')
|
133 |
+
.replace(/\t/g, ' ')
|
134 |
+
.replace(/\u00a0/g, ' ')
|
135 |
+
.replace(/\u2424/g, '\n');
|
136 |
+
|
137 |
+
return this.token(src, true);
|
138 |
+
};
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Lexing
|
142 |
+
*/
|
143 |
+
|
144 |
+
Lexer.prototype.token = function(src, top) {
|
145 |
+
var src = src.replace(/^ +$/gm, '')
|
146 |
+
, next
|
147 |
+
, loose
|
148 |
+
, cap
|
149 |
+
, bull
|
150 |
+
, b
|
151 |
+
, item
|
152 |
+
, space
|
153 |
+
, i
|
154 |
+
, l;
|
155 |
+
|
156 |
+
while (src) {
|
157 |
+
// newline
|
158 |
+
if (cap = this.rules.newline.exec(src)) {
|
159 |
+
src = src.substring(cap[0].length);
|
160 |
+
if (cap[0].length > 1) {
|
161 |
+
this.tokens.push({
|
162 |
+
type: 'space'
|
163 |
+
});
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
// code
|
168 |
+
if (cap = this.rules.code.exec(src)) {
|
169 |
+
src = src.substring(cap[0].length);
|
170 |
+
cap = cap[0].replace(/^ {4}/gm, '');
|
171 |
+
this.tokens.push({
|
172 |
+
type: 'code',
|
173 |
+
text: !this.options.pedantic
|
174 |
+
? cap.replace(/\n+$/, '')
|
175 |
+
: cap
|
176 |
+
});
|
177 |
+
continue;
|
178 |
+
}
|
179 |
+
|
180 |
+
// fences (gfm)
|
181 |
+
if (cap = this.rules.fences.exec(src)) {
|
182 |
+
src = src.substring(cap[0].length);
|
183 |
+
this.tokens.push({
|
184 |
+
type: 'code',
|
185 |
+
lang: cap[2],
|
186 |
+
text: cap[3]
|
187 |
+
});
|
188 |
+
continue;
|
189 |
+
}
|
190 |
+
|
191 |
+
// heading
|
192 |
+
if (cap = this.rules.heading.exec(src)) {
|
193 |
+
src = src.substring(cap[0].length);
|
194 |
+
this.tokens.push({
|
195 |
+
type: 'heading',
|
196 |
+
depth: cap[1].length,
|
197 |
+
text: cap[2]
|
198 |
+
});
|
199 |
+
continue;
|
200 |
+
}
|
201 |
+
|
202 |
+
// table no leading pipe (gfm)
|
203 |
+
if (top && (cap = this.rules.nptable.exec(src))) {
|
204 |
+
src = src.substring(cap[0].length);
|
205 |
+
|
206 |
+
item = {
|
207 |
+
type: 'table',
|
208 |
+
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
|
209 |
+
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
210 |
+
cells: cap[3].replace(/\n$/, '').split('\n')
|
211 |
+
};
|
212 |
+
|
213 |
+
for (i = 0; i < item.align.length; i++) {
|
214 |
+
if (/^ *-+: *$/.test(item.align[i])) {
|
215 |
+
item.align[i] = 'right';
|
216 |
+
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
217 |
+
item.align[i] = 'center';
|
218 |
+
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
219 |
+
item.align[i] = 'left';
|
220 |
+
} else {
|
221 |
+
item.align[i] = null;
|
222 |
+
}
|
223 |
+
}
|
224 |
+
|
225 |
+
for (i = 0; i < item.cells.length; i++) {
|
226 |
+
item.cells[i] = item.cells[i].split(/ *\| */);
|
227 |
+
}
|
228 |
+
|
229 |
+
this.tokens.push(item);
|
230 |
+
|
231 |
+
continue;
|
232 |
+
}
|
233 |
+
|
234 |
+
// lheading
|
235 |
+
if (cap = this.rules.lheading.exec(src)) {
|
236 |
+
src = src.substring(cap[0].length);
|
237 |
+
this.tokens.push({
|
238 |
+
type: 'heading',
|
239 |
+
depth: cap[2] === '=' ? 1 : 2,
|
240 |
+
text: cap[1]
|
241 |
+
});
|
242 |
+
continue;
|
243 |
+
}
|
244 |
+
|
245 |
+
// hr
|
246 |
+
if (cap = this.rules.hr.exec(src)) {
|
247 |
+
src = src.substring(cap[0].length);
|
248 |
+
this.tokens.push({
|
249 |
+
type: 'hr'
|
250 |
+
});
|
251 |
+
continue;
|
252 |
+
}
|
253 |
+
|
254 |
+
// blockquote
|
255 |
+
if (cap = this.rules.blockquote.exec(src)) {
|
256 |
+
src = src.substring(cap[0].length);
|
257 |
+
|
258 |
+
this.tokens.push({
|
259 |
+
type: 'blockquote_start'
|
260 |
+
});
|
261 |
+
|
262 |
+
cap = cap[0].replace(/^ *> ?/gm, '');
|
263 |
+
|
264 |
+
// Pass `top` to keep the current
|
265 |
+
// "toplevel" state. This is exactly
|
266 |
+
// how markdown.pl works.
|
267 |
+
this.token(cap, top);
|
268 |
+
|
269 |
+
this.tokens.push({
|
270 |
+
type: 'blockquote_end'
|
271 |
+
});
|
272 |
+
|
273 |
+
continue;
|
274 |
+
}
|
275 |
+
|
276 |
+
// list
|
277 |
+
if (cap = this.rules.list.exec(src)) {
|
278 |
+
src = src.substring(cap[0].length);
|
279 |
+
bull = cap[2];
|
280 |
+
|
281 |
+
this.tokens.push({
|
282 |
+
type: 'list_start',
|
283 |
+
ordered: bull.length > 1
|
284 |
+
});
|
285 |
+
|
286 |
+
// Get each top-level item.
|
287 |
+
cap = cap[0].match(this.rules.item);
|
288 |
+
|
289 |
+
next = false;
|
290 |
+
l = cap.length;
|
291 |
+
i = 0;
|
292 |
+
|
293 |
+
for (; i < l; i++) {
|
294 |
+
item = cap[i];
|
295 |
+
|
296 |
+
// Remove the list item's bullet
|
297 |
+
// so it is seen as the next token.
|
298 |
+
space = item.length;
|
299 |
+
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
|
300 |
+
|
301 |
+
// Outdent whatever the
|
302 |
+
// list item contains. Hacky.
|
303 |
+
if (~item.indexOf('\n ')) {
|
304 |
+
space -= item.length;
|
305 |
+
item = !this.options.pedantic
|
306 |
+
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
|
307 |
+
: item.replace(/^ {1,4}/gm, '');
|
308 |
+
}
|
309 |
+
|
310 |
+
// Determine whether the next list item belongs here.
|
311 |
+
// Backpedal if it does not belong in this list.
|
312 |
+
if (this.options.smartLists && i !== l - 1) {
|
313 |
+
b = block.bullet.exec(cap[i + 1])[0];
|
314 |
+
if (bull !== b && !(bull.length > 1 && b.length > 1)) {
|
315 |
+
src = cap.slice(i + 1).join('\n') + src;
|
316 |
+
i = l - 1;
|
317 |
+
}
|
318 |
+
}
|
319 |
+
|
320 |
+
// Determine whether item is loose or not.
|
321 |
+
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
|
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 |
+
|
329 |
+
this.tokens.push({
|
330 |
+
type: loose
|
331 |
+
? 'loose_item_start'
|
332 |
+
: 'list_item_start'
|
333 |
+
});
|
334 |
+
|
335 |
+
// Recurse.
|
336 |
+
this.token(item, false);
|
337 |
+
|
338 |
+
this.tokens.push({
|
339 |
+
type: 'list_item_end'
|
340 |
+
});
|
341 |
+
}
|
342 |
+
|
343 |
+
this.tokens.push({
|
344 |
+
type: 'list_end'
|
345 |
+
});
|
346 |
+
|
347 |
+
continue;
|
348 |
+
}
|
349 |
+
|
350 |
+
// html
|
351 |
+
if (cap = this.rules.html.exec(src)) {
|
352 |
+
src = src.substring(cap[0].length);
|
353 |
+
this.tokens.push({
|
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;
|
361 |
+
}
|
362 |
+
|
363 |
+
// def
|
364 |
+
if (top && (cap = this.rules.def.exec(src))) {
|
365 |
+
src = src.substring(cap[0].length);
|
366 |
+
this.tokens.links[cap[1].toLowerCase()] = {
|
367 |
+
href: cap[2],
|
368 |
+
title: cap[3]
|
369 |
+
};
|
370 |
+
continue;
|
371 |
+
}
|
372 |
+
|
373 |
+
// table (gfm)
|
374 |
+
if (top && (cap = this.rules.table.exec(src))) {
|
375 |
+
src = src.substring(cap[0].length);
|
376 |
+
|
377 |
+
item = {
|
378 |
+
type: 'table',
|
379 |
+
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
|
380 |
+
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
|
381 |
+
cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
|
382 |
+
};
|
383 |
+
|
384 |
+
for (i = 0; i < item.align.length; i++) {
|
385 |
+
if (/^ *-+: *$/.test(item.align[i])) {
|
386 |
+
item.align[i] = 'right';
|
387 |
+
} else if (/^ *:-+: *$/.test(item.align[i])) {
|
388 |
+
item.align[i] = 'center';
|
389 |
+
} else if (/^ *:-+ *$/.test(item.align[i])) {
|
390 |
+
item.align[i] = 'left';
|
391 |
+
} else {
|
392 |
+
item.align[i] = null;
|
393 |
+
}
|
394 |
+
}
|
395 |
+
|
396 |
+
for (i = 0; i < item.cells.length; i++) {
|
397 |
+
item.cells[i] = item.cells[i]
|
398 |
+
.replace(/^ *\| *| *\| *$/g, '')
|
399 |
+
.split(/ *\| */);
|
400 |
+
}
|
401 |
+
|
402 |
+
this.tokens.push(item);
|
403 |
+
|
404 |
+
continue;
|
405 |
+
}
|
406 |
+
|
407 |
+
// top-level paragraph
|
408 |
+
if (top && (cap = this.rules.paragraph.exec(src))) {
|
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 |
+
});
|
416 |
+
continue;
|
417 |
+
}
|
418 |
+
|
419 |
+
// text
|
420 |
+
if (cap = this.rules.text.exec(src)) {
|
421 |
+
// Top-level should never reach here.
|
422 |
+
src = src.substring(cap[0].length);
|
423 |
+
this.tokens.push({
|
424 |
+
type: 'text',
|
425 |
+
text: cap[0]
|
426 |
+
});
|
427 |
+
continue;
|
428 |
+
}
|
429 |
+
|
430 |
+
if (src) {
|
431 |
+
throw new
|
432 |
+
Error('Infinite loop on byte: ' + src.charCodeAt(0));
|
433 |
+
}
|
434 |
+
}
|
435 |
+
|
436 |
+
return this.tokens;
|
437 |
+
};
|
438 |
+
|
439 |
+
/**
|
440 |
+
* Inline-Level Grammar
|
441 |
+
*/
|
442 |
+
|
443 |
+
var inline = {
|
444 |
+
escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
|
445 |
+
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
|
446 |
+
url: noop,
|
447 |
+
tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
|
448 |
+
link: /^!?\[(inside)\]\(href\)/,
|
449 |
+
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
|
450 |
+
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
|
451 |
+
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
|
452 |
+
em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
|
453 |
+
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
|
454 |
+
br: /^ {2,}\n(?!\s*$)/,
|
455 |
+
del: noop,
|
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)
|
464 |
+
('href', inline._href)
|
465 |
+
();
|
466 |
+
|
467 |
+
inline.reflink = replace(inline.reflink)
|
468 |
+
('inside', inline._inside)
|
469 |
+
();
|
470 |
+
|
471 |
+
/**
|
472 |
+
* Normal Inline Grammar
|
473 |
+
*/
|
474 |
+
|
475 |
+
inline.normal = merge({}, inline);
|
476 |
+
|
477 |
+
/**
|
478 |
+
* Pedantic Inline Grammar
|
479 |
+
*/
|
480 |
+
|
481 |
+
inline.pedantic = merge({}, inline.normal, {
|
482 |
+
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
|
483 |
+
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
|
484 |
+
});
|
485 |
+
|
486 |
+
/**
|
487 |
+
* GFM Inline Grammar
|
488 |
+
*/
|
489 |
+
|
490 |
+
inline.gfm = merge({}, inline.normal, {
|
491 |
+
escape: replace(inline.escape)('])', '~|])')(),
|
492 |
+
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
|
493 |
+
del: /^~~(?=\S)([\s\S]*?\S)~~/,
|
494 |
+
text: replace(inline.text)
|
495 |
+
(']|', '~]|')
|
496 |
+
('|', '|https?://|')
|
497 |
+
()
|
498 |
+
});
|
499 |
+
|
500 |
+
/**
|
501 |
+
* GFM + Line Breaks Inline Grammar
|
502 |
+
*/
|
503 |
+
|
504 |
+
inline.breaks = merge({}, inline.gfm, {
|
505 |
+
br: replace(inline.br)('{2,}', '*')(),
|
506 |
+
text: replace(inline.gfm.text)('{2,}', '*')()
|
507 |
+
});
|
508 |
+
|
509 |
+
/**
|
510 |
+
* Inline Lexer & Compiler
|
511 |
+
*/
|
512 |
+
|
513 |
+
function InlineLexer(links, options) {
|
514 |
+
this.options = options || marked.defaults;
|
515 |
+
this.links = links;
|
516 |
+
this.rules = inline.normal;
|
517 |
+
|
518 |
+
if (!this.links) {
|
519 |
+
throw new
|
520 |
+
Error('Tokens array requires a `links` property.');
|
521 |
+
}
|
522 |
+
|
523 |
+
if (this.options.gfm) {
|
524 |
+
if (this.options.breaks) {
|
525 |
+
this.rules = inline.breaks;
|
526 |
+
} else {
|
527 |
+
this.rules = inline.gfm;
|
528 |
+
}
|
529 |
+
} else if (this.options.pedantic) {
|
530 |
+
this.rules = inline.pedantic;
|
531 |
+
}
|
532 |
+
}
|
533 |
+
|
534 |
+
/**
|
535 |
+
* Expose Inline Rules
|
536 |
+
*/
|
537 |
+
|
538 |
+
InlineLexer.rules = inline;
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Static Lexing/Compiling Method
|
542 |
+
*/
|
543 |
+
|
544 |
+
InlineLexer.output = function(src, links, options) {
|
545 |
+
var inline = new InlineLexer(links, options);
|
546 |
+
return inline.output(src);
|
547 |
+
};
|
548 |
+
|
549 |
+
/**
|
550 |
+
* Lexing/Compiling
|
551 |
+
*/
|
552 |
+
|
553 |
+
InlineLexer.prototype.output = function(src) {
|
554 |
+
var out = ''
|
555 |
+
, link
|
556 |
+
, text
|
557 |
+
, href
|
558 |
+
, cap;
|
559 |
+
|
560 |
+
while (src) {
|
561 |
+
// escape
|
562 |
+
if (cap = this.rules.escape.exec(src)) {
|
563 |
+
src = src.substring(cap[0].length);
|
564 |
+
out += cap[1];
|
565 |
+
continue;
|
566 |
+
}
|
567 |
+
|
568 |
+
// autolink
|
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;
|
576 |
+
} else {
|
577 |
+
text = escape(cap[1]);
|
578 |
+
href = text;
|
579 |
+
}
|
580 |
+
out += '<a href="'
|
581 |
+
+ href
|
582 |
+
+ '">'
|
583 |
+
+ text
|
584 |
+
+ '</a>';
|
585 |
+
continue;
|
586 |
+
}
|
587 |
+
|
588 |
+
// url (gfm)
|
589 |
+
if (cap = this.rules.url.exec(src)) {
|
590 |
+
src = src.substring(cap[0].length);
|
591 |
+
text = escape(cap[1]);
|
592 |
+
href = text;
|
593 |
+
out += '<a href="'
|
594 |
+
+ href
|
595 |
+
+ '">'
|
596 |
+
+ text
|
597 |
+
+ '</a>';
|
598 |
+
continue;
|
599 |
+
}
|
600 |
+
|
601 |
+
// tag
|
602 |
+
if (cap = this.rules.tag.exec(src)) {
|
603 |
+
src = src.substring(cap[0].length);
|
604 |
+
out += this.options.sanitize
|
605 |
+
? escape(cap[0])
|
606 |
+
: cap[0];
|
607 |
+
continue;
|
608 |
+
}
|
609 |
+
|
610 |
+
// link
|
611 |
+
if (cap = this.rules.link.exec(src)) {
|
612 |
+
src = src.substring(cap[0].length);
|
613 |
+
out += this.outputLink(cap, {
|
614 |
+
href: cap[2],
|
615 |
+
title: cap[3]
|
616 |
+
});
|
617 |
+
continue;
|
618 |
+
}
|
619 |
+
|
620 |
+
// reflink, nolink
|
621 |
+
if ((cap = this.rules.reflink.exec(src))
|
622 |
+
|| (cap = this.rules.nolink.exec(src))) {
|
623 |
+
src = src.substring(cap[0].length);
|
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 |
+
}
|
631 |
+
out += this.outputLink(cap, link);
|
632 |
+
continue;
|
633 |
+
}
|
634 |
+
|
635 |
+
// strong
|
636 |
+
if (cap = this.rules.strong.exec(src)) {
|
637 |
+
src = src.substring(cap[0].length);
|
638 |
+
out += '<strong>'
|
639 |
+
+ this.output(cap[2] || cap[1])
|
640 |
+
+ '</strong>';
|
641 |
+
continue;
|
642 |
+
}
|
643 |
+
|
644 |
+
// em
|
645 |
+
if (cap = this.rules.em.exec(src)) {
|
646 |
+
src = src.substring(cap[0].length);
|
647 |
+
out += '<em>'
|
648 |
+
+ this.output(cap[2] || cap[1])
|
649 |
+
+ '</em>';
|
650 |
+
continue;
|
651 |
+
}
|
652 |
+
|
653 |
+
// code
|
654 |
+
if (cap = this.rules.code.exec(src)) {
|
655 |
+
src = src.substring(cap[0].length);
|
656 |
+
out += '<code>'
|
657 |
+
+ escape(cap[2], true)
|
658 |
+
+ '</code>';
|
659 |
+
continue;
|
660 |
+
}
|
661 |
+
|
662 |
+
// br
|
663 |
+
if (cap = this.rules.br.exec(src)) {
|
664 |
+
src = src.substring(cap[0].length);
|
665 |
+
out += '<br>';
|
666 |
+
continue;
|
667 |
+
}
|
668 |
+
|
669 |
+
// del (gfm)
|
670 |
+
if (cap = this.rules.del.exec(src)) {
|
671 |
+
src = src.substring(cap[0].length);
|
672 |
+
out += '<del>'
|
673 |
+
+ this.output(cap[1])
|
674 |
+
+ '</del>';
|
675 |
+
continue;
|
676 |
+
}
|
677 |
+
|
678 |
+
// text
|
679 |
+
if (cap = this.rules.text.exec(src)) {
|
680 |
+
src = src.substring(cap[0].length);
|
681 |
+
out += escape(this.smartypants(cap[0]));
|
682 |
+
continue;
|
683 |
+
}
|
684 |
+
|
685 |
+
if (src) {
|
686 |
+
throw new
|
687 |
+
Error('Infinite loop on byte: ' + src.charCodeAt(0));
|
688 |
+
}
|
689 |
+
}
|
690 |
+
|
691 |
+
return out;
|
692 |
+
};
|
693 |
+
|
694 |
+
/**
|
695 |
+
* Compile Link
|
696 |
+
*/
|
697 |
+
|
698 |
+
InlineLexer.prototype.outputLink = function(cap, link) {
|
699 |
+
if (cap[0].charAt(0) !== '!') {
|
700 |
+
return '<a href="'
|
701 |
+
+ escape(link.href)
|
702 |
+
+ '"'
|
703 |
+
+ (link.title
|
704 |
+
? ' title="'
|
705 |
+
+ escape(link.title)
|
706 |
+
+ '"'
|
707 |
+
: '')
|
708 |
+
+ '>'
|
709 |
+
+ this.output(cap[1])
|
710 |
+
+ '</a>';
|
711 |
+
} else {
|
712 |
+
return '<img src="'
|
713 |
+
+ escape(link.href)
|
714 |
+
+ '" alt="'
|
715 |
+
+ escape(cap[1])
|
716 |
+
+ '"'
|
717 |
+
+ (link.title
|
718 |
+
? ' title="'
|
719 |
+
+ escape(link.title)
|
720 |
+
+ '"'
|
721 |
+
: '')
|
722 |
+
+ '>';
|
723 |
+
}
|
724 |
+
};
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Smartypants Transformations
|
728 |
+
*/
|
729 |
+
|
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 |
+
|
747 |
+
/**
|
748 |
+
* Mangle Links
|
749 |
+
*/
|
750 |
+
|
751 |
+
InlineLexer.prototype.mangle = function(text) {
|
752 |
+
var out = ''
|
753 |
+
, l = text.length
|
754 |
+
, i = 0
|
755 |
+
, ch;
|
756 |
+
|
757 |
+
for (; i < l; i++) {
|
758 |
+
ch = text.charCodeAt(i);
|
759 |
+
if (Math.random() > 0.5) {
|
760 |
+
ch = 'x' + ch.toString(16);
|
761 |
+
}
|
762 |
+
out += '&#' + ch + ';';
|
763 |
+
}
|
764 |
+
|
765 |
+
return out;
|
766 |
+
};
|
767 |
+
|
768 |
+
/**
|
769 |
+
* Parsing & Compiling
|
770 |
+
*/
|
771 |
+
|
772 |
+
function Parser(options) {
|
773 |
+
this.tokens = [];
|
774 |
+
this.token = null;
|
775 |
+
this.options = options || marked.defaults;
|
776 |
+
}
|
777 |
+
|
778 |
+
/**
|
779 |
+
* Static Parse Method
|
780 |
+
*/
|
781 |
+
|
782 |
+
Parser.parse = function(src, options) {
|
783 |
+
var parser = new Parser(options);
|
784 |
+
return parser.parse(src);
|
785 |
+
};
|
786 |
+
|
787 |
+
/**
|
788 |
+
* Parse Loop
|
789 |
+
*/
|
790 |
+
|
791 |
+
Parser.prototype.parse = function(src) {
|
792 |
+
this.inline = new InlineLexer(src.links, this.options);
|
793 |
+
this.tokens = src.reverse();
|
794 |
+
|
795 |
+
var out = '';
|
796 |
+
while (this.next()) {
|
797 |
+
out += this.tok();
|
798 |
+
}
|
799 |
+
|
800 |
+
return out;
|
801 |
+
};
|
802 |
+
|
803 |
+
/**
|
804 |
+
* Next Token
|
805 |
+
*/
|
806 |
+
|
807 |
+
Parser.prototype.next = function() {
|
808 |
+
return this.token = this.tokens.pop();
|
809 |
+
};
|
810 |
+
|
811 |
+
/**
|
812 |
+
* Preview Next Token
|
813 |
+
*/
|
814 |
+
|
815 |
+
Parser.prototype.peek = function() {
|
816 |
+
return this.tokens[this.tokens.length - 1] || 0;
|
817 |
+
};
|
818 |
+
|
819 |
+
/**
|
820 |
+
* Parse Text Tokens
|
821 |
+
*/
|
822 |
+
|
823 |
+
Parser.prototype.parseText = function() {
|
824 |
+
var body = this.token.text;
|
825 |
+
|
826 |
+
while (this.peek().type === 'text') {
|
827 |
+
body += '\n' + this.next().text;
|
828 |
+
}
|
829 |
+
|
830 |
+
return this.inline.output(body);
|
831 |
+
};
|
832 |
+
|
833 |
+
/**
|
834 |
+
* Parse Current Token
|
835 |
+
*/
|
836 |
+
|
837 |
+
Parser.prototype.tok = function() {
|
838 |
+
switch (this.token.type) {
|
839 |
+
case 'space': {
|
840 |
+
return '';
|
841 |
+
}
|
842 |
+
case 'hr': {
|
843 |
+
return '<hr>\n';
|
844 |
+
}
|
845 |
+
case 'heading': {
|
846 |
+
return '<h'
|
847 |
+
+ this.token.depth
|
848 |
+
+ ' id="'
|
849 |
+
+ this.token.text.toLowerCase().replace(/[^\w]+/g, '-')
|
850 |
+
+ '">'
|
851 |
+
+ this.inline.output(this.token.text)
|
852 |
+
+ '</h'
|
853 |
+
+ this.token.depth
|
854 |
+
+ '>\n';
|
855 |
+
}
|
856 |
+
case 'code': {
|
857 |
+
if (this.options.highlight) {
|
858 |
+
var code = this.options.highlight(this.token.text, this.token.lang);
|
859 |
+
if (code != null && code !== this.token.text) {
|
860 |
+
this.token.escaped = true;
|
861 |
+
this.token.text = code;
|
862 |
+
}
|
863 |
+
}
|
864 |
+
|
865 |
+
if (!this.token.escaped) {
|
866 |
+
this.token.text = escape(this.token.text, true);
|
867 |
+
}
|
868 |
+
|
869 |
+
return '<pre><code'
|
870 |
+
+ (this.token.lang
|
871 |
+
? ' class="'
|
872 |
+
+ this.options.langPrefix
|
873 |
+
+ this.token.lang
|
874 |
+
+ '"'
|
875 |
+
: '')
|
876 |
+
+ '>'
|
877 |
+
+ this.token.text
|
878 |
+
+ '</code></pre>\n';
|
879 |
+
}
|
880 |
+
case 'table': {
|
881 |
+
var body = ''
|
882 |
+
, heading
|
883 |
+
, i
|
884 |
+
, row
|
885 |
+
, cell
|
886 |
+
, j;
|
887 |
+
|
888 |
+
// header
|
889 |
+
body += '<thead>\n<tr>\n';
|
890 |
+
for (i = 0; i < this.token.header.length; i++) {
|
891 |
+
heading = this.inline.output(this.token.header[i]);
|
892 |
+
body += '<th';
|
893 |
+
if (this.token.align[i]) {
|
894 |
+
body += ' style="text-align:' + this.token.align[i] + '"';
|
895 |
+
}
|
896 |
+
body += '>' + heading + '</th>\n';
|
897 |
+
}
|
898 |
+
body += '</tr>\n</thead>\n';
|
899 |
+
|
900 |
+
// body
|
901 |
+
body += '<tbody>\n'
|
902 |
+
for (i = 0; i < this.token.cells.length; i++) {
|
903 |
+
row = this.token.cells[i];
|
904 |
+
body += '<tr>\n';
|
905 |
+
for (j = 0; j < row.length; j++) {
|
906 |
+
cell = this.inline.output(row[j]);
|
907 |
+
body += '<td';
|
908 |
+
if (this.token.align[j]) {
|
909 |
+
body += ' style="text-align:' + this.token.align[j] + '"';
|
910 |
+
}
|
911 |
+
body += '>' + cell + '</td>\n';
|
912 |
+
}
|
913 |
+
body += '</tr>\n';
|
914 |
+
}
|
915 |
+
body += '</tbody>\n';
|
916 |
+
|
917 |
+
return '<table>\n'
|
918 |
+
+ body
|
919 |
+
+ '</table>\n';
|
920 |
+
}
|
921 |
+
case 'blockquote_start': {
|
922 |
+
var body = '';
|
923 |
+
|
924 |
+
while (this.next().type !== 'blockquote_end') {
|
925 |
+
body += this.tok();
|
926 |
+
}
|
927 |
+
|
928 |
+
return '<blockquote>\n'
|
929 |
+
+ body
|
930 |
+
+ '</blockquote>\n';
|
931 |
+
}
|
932 |
+
case 'list_start': {
|
933 |
+
var type = this.token.ordered ? 'ol' : 'ul'
|
934 |
+
, body = '';
|
935 |
+
|
936 |
+
while (this.next().type !== 'list_end') {
|
937 |
+
body += this.tok();
|
938 |
+
}
|
939 |
+
|
940 |
+
return '<'
|
941 |
+
+ type
|
942 |
+
+ '>\n'
|
943 |
+
+ body
|
944 |
+
+ '</'
|
945 |
+
+ type
|
946 |
+
+ '>\n';
|
947 |
+
}
|
948 |
+
case 'list_item_start': {
|
949 |
+
var body = '';
|
950 |
+
|
951 |
+
while (this.next().type !== 'list_item_end') {
|
952 |
+
body += this.token.type === 'text'
|
953 |
+
? this.parseText()
|
954 |
+
: this.tok();
|
955 |
+
}
|
956 |
+
|
957 |
+
return '<li>'
|
958 |
+
+ body
|
959 |
+
+ '</li>\n';
|
960 |
+
}
|
961 |
+
case 'loose_item_start': {
|
962 |
+
var body = '';
|
963 |
+
|
964 |
+
while (this.next().type !== 'list_item_end') {
|
965 |
+
body += this.tok();
|
966 |
+
}
|
967 |
+
|
968 |
+
return '<li>'
|
969 |
+
+ body
|
970 |
+
+ '</li>\n';
|
971 |
+
}
|
972 |
+
case 'html': {
|
973 |
+
return !this.token.pre && !this.options.pedantic
|
974 |
+
? this.inline.output(this.token.text)
|
975 |
+
: this.token.text;
|
976 |
+
}
|
977 |
+
case 'paragraph': {
|
978 |
+
return '<p>'
|
979 |
+
+ this.inline.output(this.token.text)
|
980 |
+
+ '</p>\n';
|
981 |
+
}
|
982 |
+
case 'text': {
|
983 |
+
return '<p>'
|
984 |
+
+ this.parseText()
|
985 |
+
+ '</p>\n';
|
986 |
+
}
|
987 |
+
}
|
988 |
+
};
|
989 |
+
|
990 |
+
/**
|
991 |
+
* Helpers
|
992 |
+
*/
|
993 |
+
|
994 |
+
function escape(html, encode) {
|
995 |
+
return html
|
996 |
+
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
|
997 |
+
.replace(/</g, '<')
|
998 |
+
.replace(/>/g, '>')
|
999 |
+
.replace(/"/g, '"')
|
1000 |
+
.replace(/'/g, ''');
|
1001 |
+
}
|
1002 |
+
|
1003 |
+
function replace(regex, opt) {
|
1004 |
+
regex = regex.source;
|
1005 |
+
opt = opt || '';
|
1006 |
+
return function self(name, val) {
|
1007 |
+
if (!name) return new RegExp(regex, opt);
|
1008 |
+
val = val.source || val;
|
1009 |
+
val = val.replace(/(^|[^\[])\^/g, '$1');
|
1010 |
+
regex = regex.replace(name, val);
|
1011 |
+
return self;
|
1012 |
+
};
|
1013 |
+
}
|
1014 |
+
|
1015 |
+
function noop() {}
|
1016 |
+
noop.exec = noop;
|
1017 |
+
|
1018 |
+
function merge(obj) {
|
1019 |
+
var i = 1
|
1020 |
+
, target
|
1021 |
+
, key;
|
1022 |
+
|
1023 |
+
for (; i < arguments.length; i++) {
|
1024 |
+
target = arguments[i];
|
1025 |
+
for (key in target) {
|
1026 |
+
if (Object.prototype.hasOwnProperty.call(target, key)) {
|
1027 |
+
obj[key] = target[key];
|
1028 |
+
}
|
1029 |
+
}
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
return obj;
|
1033 |
+
}
|
1034 |
+
|
1035 |
+
/**
|
1036 |
+
* Marked
|
1037 |
+
*/
|
1038 |
+
|
1039 |
+
function marked(src, opt, callback) {
|
1040 |
+
if (callback || typeof opt === 'function') {
|
1041 |
+
if (!callback) {
|
1042 |
+
callback = opt;
|
1043 |
+
opt = null;
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
opt = merge({}, marked.defaults, opt || {});
|
1047 |
+
|
1048 |
+
var highlight = opt.highlight
|
1049 |
+
, tokens
|
1050 |
+
, pending
|
1051 |
+
, i = 0;
|
1052 |
+
|
1053 |
+
try {
|
1054 |
+
tokens = Lexer.lex(src, opt)
|
1055 |
+
} catch (e) {
|
1056 |
+
return callback(e);
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
pending = tokens.length;
|
1060 |
+
|
1061 |
+
var done = function() {
|
1062 |
+
var out, err;
|
1063 |
+
|
1064 |
+
try {
|
1065 |
+
out = Parser.parse(tokens, opt);
|
1066 |
+
} catch (e) {
|
1067 |
+
err = e;
|
1068 |
+
}
|
1069 |
+
|
1070 |
+
opt.highlight = highlight;
|
1071 |
+
|
1072 |
+
return err
|
1073 |
+
? callback(err)
|
1074 |
+
: callback(null, out);
|
1075 |
+
};
|
1076 |
+
|
1077 |
+
if (!highlight || highlight.length < 3) {
|
1078 |
+
return done();
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
delete opt.highlight;
|
1082 |
+
|
1083 |
+
if (!pending) return done();
|
1084 |
+
|
1085 |
+
for (; i < tokens.length; i++) {
|
1086 |
+
(function(token) {
|
1087 |
+
if (token.type !== 'code') {
|
1088 |
+
return --pending || done();
|
1089 |
+
}
|
1090 |
+
return highlight(token.text, token.lang, function(err, code) {
|
1091 |
+
if (code == null || code === token.text) {
|
1092 |
+
return --pending || done();
|
1093 |
+
}
|
1094 |
+
token.text = code;
|
1095 |
+
token.escaped = true;
|
1096 |
+
--pending || done();
|
1097 |
+
});
|
1098 |
+
})(tokens[i]);
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
return;
|
1102 |
+
}
|
1103 |
+
try {
|
1104 |
+
if (opt) opt = merge({}, marked.defaults, opt);
|
1105 |
+
return Parser.parse(Lexer.lex(src, opt), opt);
|
1106 |
+
} catch (e) {
|
1107 |
+
e.message += '\nPlease report this to https://github.com/chjj/marked.';
|
1108 |
+
if ((opt || marked.defaults).silent) {
|
1109 |
+
return '<p>An error occured:</p><pre>'
|
1110 |
+
+ escape(e.message + '', true)
|
1111 |
+
+ '</pre>';
|
1112 |
+
}
|
1113 |
+
throw e;
|
1114 |
+
}
|
1115 |
+
}
|
1116 |
+
|
1117 |
+
/**
|
1118 |
+
* Options
|
1119 |
+
*/
|
1120 |
+
|
1121 |
+
marked.options =
|
1122 |
+
marked.setOptions = function(opt) {
|
1123 |
+
merge(marked.defaults, opt);
|
1124 |
+
return marked;
|
1125 |
+
};
|
1126 |
+
|
1127 |
+
marked.defaults = {
|
1128 |
+
gfm: true,
|
1129 |
+
tables: true,
|
1130 |
+
breaks: false,
|
1131 |
+
pedantic: false,
|
1132 |
+
sanitize: false,
|
1133 |
+
smartLists: false,
|
1134 |
+
silent: false,
|
1135 |
+
highlight: null,
|
1136 |
+
langPrefix: 'lang-',
|
1137 |
+
smartypants: false
|
1138 |
+
};
|
1139 |
+
|
1140 |
+
/**
|
1141 |
+
* Expose
|
1142 |
+
*/
|
1143 |
+
|
1144 |
+
marked.Parser = Parser;
|
1145 |
+
marked.parser = Parser.parse;
|
1146 |
+
|
1147 |
+
marked.Lexer = Lexer;
|
1148 |
+
marked.lexer = Lexer.lex;
|
1149 |
+
|
1150 |
+
marked.InlineLexer = InlineLexer;
|
1151 |
+
marked.inlineLexer = InlineLexer.output;
|
1152 |
+
|
1153 |
+
marked.parse = marked;
|
1154 |
+
|
1155 |
+
if (typeof exports === 'object') {
|
1156 |
+
module.exports = marked;
|
1157 |
+
} else if (typeof define === 'function' && define.amd) {
|
1158 |
+
define(function() { return marked; });
|
1159 |
+
} else {
|
1160 |
+
this.marked = marked;
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
}).call(function() {
|
1164 |
+
return this || (typeof window !== 'undefined' ? window : global);
|
1165 |
+
}());
|
js/markdown/adminhtml/reMarked.js
ADDED
@@ -0,0 +1,636 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Copyright (c) 2013, Leon Sorokin
|
3 |
+
* All rights reserved. (MIT Licensed)
|
4 |
+
*
|
5 |
+
* reMarked.js - DOM > markdown
|
6 |
+
*/
|
7 |
+
|
8 |
+
reMarked = function(opts) {
|
9 |
+
|
10 |
+
var links = [];
|
11 |
+
var cfg = {
|
12 |
+
link_list: false, // render links as references, create link list as appendix
|
13 |
+
// link_near: // cite links immediately after blocks
|
14 |
+
h1_setext: true, // underline h1 headers
|
15 |
+
h2_setext: true, // underline h2 headers
|
16 |
+
h_atx_suf: false, // header suffix (###)
|
17 |
+
// h_compact: true, // compact headers (except h1)
|
18 |
+
gfm_code: false, // render code blocks as via ``` delims
|
19 |
+
li_bullet: "*-+"[0], // list item bullet style
|
20 |
+
// list_indnt: // indent top-level lists
|
21 |
+
hr_char: "-_*"[0], // hr style
|
22 |
+
indnt_str: [" ","\t"," "][0], // indentation string
|
23 |
+
bold_char: "*_"[0], // char used for strong
|
24 |
+
emph_char: "*_"[1], // char used for em
|
25 |
+
gfm_del: true, // ~~strikeout~~ for <del>strikeout</del>
|
26 |
+
gfm_tbls: true, // markdown-extra tables
|
27 |
+
tbl_edges: false, // show side edges on tables
|
28 |
+
hash_lnks: false, // anchors w/hash hrefs as links
|
29 |
+
br_only: false, // avoid using " " as line break indicator
|
30 |
+
// comp_style: false, // use getComputedStyle instead of hardcoded tag list to discern block/inline
|
31 |
+
unsup_tags: { // handling of unsupported tags, defined in terms of desired output style. if not listed, output = outerHTML
|
32 |
+
// no output
|
33 |
+
ignore: "script style noscript",
|
34 |
+
// eg: "<tag>some content</tag>"
|
35 |
+
inline: "span sup sub i u b center big",
|
36 |
+
// eg: "\n<tag>\n\tsome content\n</tag>"
|
37 |
+
// block1: "",
|
38 |
+
// eg: "\n\n<tag>\n\tsome content\n</tag>"
|
39 |
+
block2: "div form fieldset dl header footer address article aside figure hgroup section",
|
40 |
+
// eg: "\n<tag>some content</tag>"
|
41 |
+
block1c: "dt dd caption legend figcaption output",
|
42 |
+
// eg: "\n\n<tag>some content</tag>"
|
43 |
+
block2c: "canvas audio video iframe",
|
44 |
+
/* // direct remap of unsuported tags
|
45 |
+
convert: {
|
46 |
+
i: "em",
|
47 |
+
b: "strong"
|
48 |
+
}
|
49 |
+
*/
|
50 |
+
}
|
51 |
+
};
|
52 |
+
|
53 |
+
extend(cfg, opts);
|
54 |
+
|
55 |
+
function extend(a, b) {
|
56 |
+
if (!b) return a;
|
57 |
+
for (var i in a) {
|
58 |
+
if (typeOf(b[i]) == "Object")
|
59 |
+
extend(a[i], b[i]);
|
60 |
+
else if (typeof b[i] !== "undefined")
|
61 |
+
a[i] = b[i];
|
62 |
+
}
|
63 |
+
}
|
64 |
+
|
65 |
+
function typeOf(val) {
|
66 |
+
return Object.prototype.toString.call(val).slice(8,-1);
|
67 |
+
}
|
68 |
+
|
69 |
+
function rep(str, num) {
|
70 |
+
var s = "";
|
71 |
+
while (num-- > 0)
|
72 |
+
s += str;
|
73 |
+
return s;
|
74 |
+
}
|
75 |
+
|
76 |
+
function trim12(str) {
|
77 |
+
var str = str.replace(/^\s\s*/, ''),
|
78 |
+
ws = /\s/,
|
79 |
+
i = str.length;
|
80 |
+
while (ws.test(str.charAt(--i)));
|
81 |
+
return str.slice(0, i + 1);
|
82 |
+
}
|
83 |
+
|
84 |
+
function lpad(targ, padStr, len) {
|
85 |
+
return rep(padStr, len - targ.length) + targ;
|
86 |
+
}
|
87 |
+
|
88 |
+
function rpad(targ, padStr, len) {
|
89 |
+
return targ + rep(padStr, len - targ.length);
|
90 |
+
}
|
91 |
+
|
92 |
+
function otag(tag, e) {
|
93 |
+
if (!tag) return "";
|
94 |
+
|
95 |
+
var buf = "<" + tag;
|
96 |
+
|
97 |
+
for (var attr, i=0, attrs=e.attributes, l=attrs.length; i<l; i++) {
|
98 |
+
attr = attrs.item(i);
|
99 |
+
buf += " " + attr.nodeName + '="' + attr.nodeValue + '"';
|
100 |
+
}
|
101 |
+
|
102 |
+
return buf + ">";
|
103 |
+
}
|
104 |
+
|
105 |
+
function ctag(tag) {
|
106 |
+
if (!tag) return "";
|
107 |
+
return "</" + tag + ">";
|
108 |
+
}
|
109 |
+
|
110 |
+
function pfxLines(txt, pfx) {
|
111 |
+
return txt.replace(/^/gm, pfx);
|
112 |
+
}
|
113 |
+
|
114 |
+
function nodeName(e) {
|
115 |
+
return (e.nodeName == "#text" ? "txt" : e.nodeName).toLowerCase();
|
116 |
+
}
|
117 |
+
|
118 |
+
function wrap(str, opts) {
|
119 |
+
var pre, suf;
|
120 |
+
|
121 |
+
if (opts instanceof Array) {
|
122 |
+
pre = opts[0];
|
123 |
+
suf = opts[1];
|
124 |
+
}
|
125 |
+
else
|
126 |
+
pre = suf = opts;
|
127 |
+
|
128 |
+
pre = pre instanceof Function ? pre.call(this, str) : pre;
|
129 |
+
suf = suf instanceof Function ? suf.call(this, str) : suf;
|
130 |
+
|
131 |
+
return pre + str + suf;
|
132 |
+
}
|
133 |
+
|
134 |
+
// http://stackoverflow.com/a/3819589/973988
|
135 |
+
function outerHTML(node) {
|
136 |
+
// if IE, Chrome take the internal method otherwise build one
|
137 |
+
return node.outerHTML || (
|
138 |
+
function(n){
|
139 |
+
var div = document.createElement('div'), h;
|
140 |
+
div.appendChild( n.cloneNode(true) );
|
141 |
+
h = div.innerHTML;
|
142 |
+
div = null;
|
143 |
+
return h;
|
144 |
+
})(node);
|
145 |
+
}
|
146 |
+
|
147 |
+
this.render = function(ctr) {
|
148 |
+
links = [];
|
149 |
+
|
150 |
+
if (typeof ctr == "string") {
|
151 |
+
var htmlstr = ctr;
|
152 |
+
ctr = document.createElement("div");
|
153 |
+
ctr.innerHTML = htmlstr;
|
154 |
+
}
|
155 |
+
var s = new lib.tag(ctr, null, 0);
|
156 |
+
var re = s.rend().replace(/^[\t ]+\n/gm, "\n");
|
157 |
+
if (cfg.link_list && links.length > 0) {
|
158 |
+
// hack
|
159 |
+
re += "\n\n";
|
160 |
+
var maxlen = 0;
|
161 |
+
// get longest link href with title, TODO: use getAttribute?
|
162 |
+
for (var y in links) {
|
163 |
+
if (!links[y].e.title) continue;
|
164 |
+
var len = links[y].e.href.length;
|
165 |
+
if (len && len > maxlen)
|
166 |
+
maxlen = len;
|
167 |
+
}
|
168 |
+
|
169 |
+
for (var k in links) {
|
170 |
+
var title = links[k].e.title ? rep(" ", (maxlen + 2) - links[k].e.href.length) + '"' + links[k].e.title + '"' : "";
|
171 |
+
re += " [" + (+k+1) + "]: " + (nodeName(links[k].e) == "a" ? links[k].e.href : links[k].e.src) + title + "\n";
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
return re.replace(/^[\t ]+\n/gm, "\n");
|
176 |
+
};
|
177 |
+
|
178 |
+
var lib = {};
|
179 |
+
|
180 |
+
lib.tag = klass({
|
181 |
+
wrap: "",
|
182 |
+
lnPfx: "", // only block
|
183 |
+
lnInd: 0, // only block
|
184 |
+
init: function(e, p, i)
|
185 |
+
{
|
186 |
+
this.e = e;
|
187 |
+
this.p = p;
|
188 |
+
this.i = i;
|
189 |
+
this.c = [];
|
190 |
+
this.tag = nodeName(e);
|
191 |
+
|
192 |
+
this.initK();
|
193 |
+
},
|
194 |
+
|
195 |
+
initK: function()
|
196 |
+
{
|
197 |
+
var i;
|
198 |
+
if (this.e.hasChildNodes()) {
|
199 |
+
// inline elems allowing adjacent whitespace text nodes to be rendered
|
200 |
+
var inlRe = cfg.unsup_tags.inline, n, name;
|
201 |
+
|
202 |
+
for (i in this.e.childNodes) {
|
203 |
+
if (!/\d+/.test(i)) continue;
|
204 |
+
|
205 |
+
n = this.e.childNodes[i];
|
206 |
+
name = nodeName(n);
|
207 |
+
|
208 |
+
// ignored tags
|
209 |
+
if (cfg.unsup_tags.ignore.test(name))
|
210 |
+
continue;
|
211 |
+
|
212 |
+
// empty whitespace handling
|
213 |
+
if (name == "txt" && /^\s+$/.test(n.textContent)) {
|
214 |
+
// ignore if first or last child (trim)
|
215 |
+
if (i == 0 || i == this.e.childNodes.length - 1)
|
216 |
+
continue;
|
217 |
+
|
218 |
+
// only ouput when has an adjacent inline elem
|
219 |
+
var prev = this.e.childNodes[i-1],
|
220 |
+
next = this.e.childNodes[i+1];
|
221 |
+
if (prev && !nodeName(prev).match(inlRe) || next && !nodeName(next).match(inlRe))
|
222 |
+
continue;
|
223 |
+
}
|
224 |
+
|
225 |
+
var wrap = null;
|
226 |
+
|
227 |
+
if (!lib[name]) {
|
228 |
+
var unsup = cfg.unsup_tags;
|
229 |
+
|
230 |
+
if (unsup.inline.test(name))
|
231 |
+
name = "tinl";
|
232 |
+
else if (unsup.block2.test(name))
|
233 |
+
name = "tblk";
|
234 |
+
else if (unsup.block1c.test(name))
|
235 |
+
name = "ctblk";
|
236 |
+
else if (unsup.block2c.test(name)) {
|
237 |
+
name = "ctblk";
|
238 |
+
wrap = ["\n\n", ""];
|
239 |
+
}
|
240 |
+
else
|
241 |
+
name = "rawhtml";
|
242 |
+
}
|
243 |
+
|
244 |
+
var node = new lib[name](n, this, this.c.length);
|
245 |
+
|
246 |
+
if (wrap)
|
247 |
+
node.wrap = wrap;
|
248 |
+
|
249 |
+
if (node instanceof lib.a && n.href || node instanceof lib.img) {
|
250 |
+
node.lnkid = links.length;
|
251 |
+
links.push(node);
|
252 |
+
}
|
253 |
+
|
254 |
+
this.c.push(node);
|
255 |
+
}
|
256 |
+
}
|
257 |
+
},
|
258 |
+
|
259 |
+
rend: function()
|
260 |
+
{
|
261 |
+
return this.rendK().replace(/\n{3,}/gm, "\n\n"); // can screw up pre and code :(
|
262 |
+
},
|
263 |
+
|
264 |
+
rendK: function()
|
265 |
+
{
|
266 |
+
var n, buf = "";
|
267 |
+
for (var i in this.c) {
|
268 |
+
n = this.c[i];
|
269 |
+
|
270 |
+
// @SchumacherFM: added typeof n.rend
|
271 |
+
buf += (n.bef || "") +( typeof n.rend === 'function' ? n.rend() : '' ) + (n.aft || "");
|
272 |
+
}
|
273 |
+
return buf.replace(/^\n+|\n+$/, "");
|
274 |
+
}
|
275 |
+
});
|
276 |
+
|
277 |
+
lib.blk = lib.tag.extend({
|
278 |
+
wrap: ["\n\n", ""],
|
279 |
+
wrapK: null,
|
280 |
+
tagr: false,
|
281 |
+
lnInd: null,
|
282 |
+
init: function(e, p ,i) {
|
283 |
+
this.supr(e,p,i);
|
284 |
+
|
285 |
+
// kids indented
|
286 |
+
if (this.lnInd === null) {
|
287 |
+
if (this.p && this.tagr && this.c[0] instanceof lib.blk)
|
288 |
+
this.lnInd = 4;
|
289 |
+
else
|
290 |
+
this.lnInd = 0;
|
291 |
+
}
|
292 |
+
|
293 |
+
// kids wrapped?
|
294 |
+
if (this.wrapK === null) {
|
295 |
+
if (this.tagr && this.c[0] instanceof lib.blk)
|
296 |
+
this.wrapK = "\n";
|
297 |
+
else
|
298 |
+
this.wrapK = "";
|
299 |
+
}
|
300 |
+
},
|
301 |
+
|
302 |
+
rend: function()
|
303 |
+
{
|
304 |
+
return wrap.call(this, (this.tagr ? otag(this.tag, this.e) : "") + wrap.call(this, pfxLines(pfxLines(this.rendK(), this.lnPfx), rep(" ", this.lnInd)), this.wrapK) + (this.tagr ? ctag(this.tag) : ""), this.wrap);
|
305 |
+
},
|
306 |
+
|
307 |
+
rendK: function()
|
308 |
+
{
|
309 |
+
var kids = this.supr();
|
310 |
+
// remove min uniform leading spaces from block children. marked.js's list outdent algo sometimes leaves these
|
311 |
+
if (this.p instanceof lib.li) {
|
312 |
+
var repl = null, spcs = kids.match(/^[\t ]+/gm);
|
313 |
+
if (!spcs) return kids;
|
314 |
+
for (var i in spcs) {
|
315 |
+
if (repl === null || spcs[i][0].length < repl.length)
|
316 |
+
repl = spcs[i][0];
|
317 |
+
}
|
318 |
+
return kids.replace(new RegExp("^" + repl), "");
|
319 |
+
}
|
320 |
+
return kids;
|
321 |
+
}
|
322 |
+
});
|
323 |
+
|
324 |
+
lib.tblk = lib.blk.extend({tagr: true});
|
325 |
+
|
326 |
+
lib.cblk = lib.blk.extend({wrap: ["\n", ""]});
|
327 |
+
|
328 |
+
lib.ctblk = lib.cblk.extend({tagr: true});
|
329 |
+
|
330 |
+
lib.inl = lib.tag.extend({
|
331 |
+
rend: function()
|
332 |
+
{
|
333 |
+
return wrap.call(this, this.rendK(), this.wrap);
|
334 |
+
}
|
335 |
+
});
|
336 |
+
|
337 |
+
lib.tinl = lib.inl.extend({
|
338 |
+
tagr: true,
|
339 |
+
rend: function()
|
340 |
+
{
|
341 |
+
return otag(this.tag, this.e) + wrap.call(this, this.rendK(), this.wrap) + ctag(this.tag);
|
342 |
+
}
|
343 |
+
});
|
344 |
+
|
345 |
+
lib.p = lib.blk.extend({
|
346 |
+
rendK: function() {
|
347 |
+
return this.supr().replace(/^\s+/gm, "");
|
348 |
+
}
|
349 |
+
});
|
350 |
+
|
351 |
+
lib.list = lib.blk.extend({
|
352 |
+
expn: false,
|
353 |
+
wrap: [function(){return this.p instanceof lib.li ? "\n" : "\n\n";}, ""]
|
354 |
+
});
|
355 |
+
|
356 |
+
lib.ul = lib.list.extend({});
|
357 |
+
|
358 |
+
lib.ol = lib.list.extend({});
|
359 |
+
|
360 |
+
lib.li = lib.cblk.extend({
|
361 |
+
wrap: ["\n", function(kids) {
|
362 |
+
return this.p.expn || kids.match(/\n{2}/gm) ? "\n" : ""; // || this.kids.match(\n)
|
363 |
+
}],
|
364 |
+
wrapK: [function() {
|
365 |
+
return this.p.tag == "ul" ? cfg.li_bullet + " " : (this.i + 1) + ". ";
|
366 |
+
}, ""],
|
367 |
+
rendK: function() {
|
368 |
+
return this.supr().replace(/\n([^\n])/gm, "\n" + cfg.indnt_str + "$1");
|
369 |
+
}
|
370 |
+
});
|
371 |
+
|
372 |
+
lib.hr = lib.blk.extend({
|
373 |
+
wrap: ["\n\n", rep(cfg.hr_char, 3)]
|
374 |
+
});
|
375 |
+
|
376 |
+
lib.h = lib.blk.extend({});
|
377 |
+
|
378 |
+
lib.h_setext = lib.h.extend({});
|
379 |
+
|
380 |
+
cfg.h1_setext && (lib.h1 = lib.h_setext.extend({
|
381 |
+
wrapK: ["", function(kids) {
|
382 |
+
return "\n" + rep("=", kids.length);
|
383 |
+
}]
|
384 |
+
}));
|
385 |
+
|
386 |
+
cfg.h2_setext && (lib.h2 = lib.h_setext.extend({
|
387 |
+
wrapK: ["", function(kids) {
|
388 |
+
return "\n" + rep("-", kids.length);
|
389 |
+
}]
|
390 |
+
}));
|
391 |
+
|
392 |
+
lib.h_atx = lib.h.extend({
|
393 |
+
wrapK: [
|
394 |
+
function(kids) {
|
395 |
+
return rep("#", this.tag[1]) + " ";
|
396 |
+
},
|
397 |
+
function(kids) {
|
398 |
+
return cfg.h_atx_suf ? " " + rep("#", this.tag[1]) : "";
|
399 |
+
}
|
400 |
+
]
|
401 |
+
});
|
402 |
+
!cfg.h1_setext && (lib.h1 = lib.h_atx.extend({}));
|
403 |
+
|
404 |
+
!cfg.h2_setext && (lib.h2 = lib.h_atx.extend({}));
|
405 |
+
|
406 |
+
lib.h3 = lib.h_atx.extend({});
|
407 |
+
|
408 |
+
lib.h4 = lib.h_atx.extend({});
|
409 |
+
|
410 |
+
lib.h5 = lib.h_atx.extend({});
|
411 |
+
|
412 |
+
lib.h6 = lib.h_atx.extend({});
|
413 |
+
|
414 |
+
lib.a = lib.inl.extend({
|
415 |
+
lnkid: null,
|
416 |
+
rend: function() {
|
417 |
+
var kids = this.rendK(),
|
418 |
+
href = this.e.getAttribute("href"),
|
419 |
+
title = this.e.title ? ' "' + this.e.title + '"' : "";
|
420 |
+
|
421 |
+
if (!href || href == kids || href[0] == "#" && !cfg.hash_lnks)
|
422 |
+
return kids;
|
423 |
+
|
424 |
+
if (cfg.link_list)
|
425 |
+
return "[" + kids + "] [" + (this.lnkid + 1) + "]";
|
426 |
+
|
427 |
+
return "[" + kids + "](" + href + title + ")";
|
428 |
+
}
|
429 |
+
});
|
430 |
+
|
431 |
+
// almost identical to links, maybe merge
|
432 |
+
lib.img = lib.inl.extend({
|
433 |
+
lnkid: null,
|
434 |
+
rend: function() {
|
435 |
+
var kids = this.e.alt,
|
436 |
+
src = this.e.getAttribute("src");
|
437 |
+
|
438 |
+
if (cfg.link_list)
|
439 |
+
return "![" + kids + "] [" + (this.lnkid + 1) + "]";
|
440 |
+
|
441 |
+
var title = this.e.title ? ' "'+ this.e.title + '"' : "";
|
442 |
+
|
443 |
+
return "![" + kids + "](" + src + title + ")";
|
444 |
+
}
|
445 |
+
});
|
446 |
+
|
447 |
+
|
448 |
+
lib.em = lib.inl.extend({wrap: cfg.emph_char});
|
449 |
+
|
450 |
+
lib.del = cfg.gfm_del ? lib.inl.extend({wrap: "~~"}) : lib.tinl.extend();
|
451 |
+
|
452 |
+
lib.br = lib.inl.extend({
|
453 |
+
wrap: ["", function() {
|
454 |
+
var end = cfg.br_only ? "<br>" : " ";
|
455 |
+
// br in headers output as html
|
456 |
+
return this.p instanceof lib.h ? "<br>" : end + "\n";
|
457 |
+
}]
|
458 |
+
});
|
459 |
+
|
460 |
+
lib.strong = lib.inl.extend({wrap: rep(cfg.bold_char, 2)});
|
461 |
+
|
462 |
+
lib.blockquote = lib.blk.extend({
|
463 |
+
lnPfx: "> ",
|
464 |
+
rend: function() {
|
465 |
+
return this.supr().replace(/>[ \t]$/gm, ">");
|
466 |
+
}
|
467 |
+
});
|
468 |
+
|
469 |
+
// can render with or without tags
|
470 |
+
lib.pre = lib.blk.extend({
|
471 |
+
tagr: true,
|
472 |
+
wrapK: "\n",
|
473 |
+
lnInd: 0
|
474 |
+
});
|
475 |
+
|
476 |
+
// can morph into inline based on context
|
477 |
+
lib.code = lib.blk.extend({
|
478 |
+
tagr: false,
|
479 |
+
wrap: "",
|
480 |
+
wrapK: function(kids) {
|
481 |
+
return kids.indexOf("`") !== -1 ? "``" : "`"; // esc double backticks
|
482 |
+
},
|
483 |
+
lnInd: 0,
|
484 |
+
init: function(e, p, i) {
|
485 |
+
this.supr(e, p, i);
|
486 |
+
|
487 |
+
if (this.p instanceof lib.pre) {
|
488 |
+
this.p.tagr = false;
|
489 |
+
|
490 |
+
if (cfg.gfm_code) {
|
491 |
+
var cls = this.e.getAttribute("class");
|
492 |
+
cls = (cls || "").split(" ")[0];
|
493 |
+
|
494 |
+
if (cls.indexOf("lang-") === 0) // marked uses "lang-" prefix now
|
495 |
+
cls = cls.substr(5);
|
496 |
+
|
497 |
+
this.wrapK = ["```" + cls + "\n", "\n```"];
|
498 |
+
}
|
499 |
+
else {
|
500 |
+
this.wrapK = "";
|
501 |
+
this.p.lnInd = 4;
|
502 |
+
}
|
503 |
+
}
|
504 |
+
}
|
505 |
+
});
|
506 |
+
|
507 |
+
lib.table = cfg.gfm_tbls ? lib.blk.extend({
|
508 |
+
cols: [],
|
509 |
+
init: function(e, p, i) {
|
510 |
+
this.supr(e, p, i);
|
511 |
+
this.cols = [];
|
512 |
+
},
|
513 |
+
rend: function() {
|
514 |
+
// run prep on all cells to get max col widths
|
515 |
+
for (var tsec in this.c)
|
516 |
+
for (var row in this.c[tsec].c)
|
517 |
+
for (var cell in this.c[tsec].c[row].c)
|
518 |
+
this.c[tsec].c[row].c[cell].prep();
|
519 |
+
|
520 |
+
return this.supr();
|
521 |
+
}
|
522 |
+
}) : lib.tblk.extend();
|
523 |
+
|
524 |
+
lib.thead = cfg.gfm_tbls ? lib.cblk.extend({
|
525 |
+
wrap: ["\n", function(kids) {
|
526 |
+
var buf = "";
|
527 |
+
for (var i in this.p.cols) {
|
528 |
+
var col = this.p.cols[i],
|
529 |
+
al = col.a[0] == "c" ? ":" : " ",
|
530 |
+
ar = col.a[0] == "r" || col.a[0] == "c" ? ":" : " ";
|
531 |
+
|
532 |
+
buf += (i == 0 && cfg.tbl_edges ? "|" : "") + al + rep("-", col.w) + ar + (i < this.p.cols.length-1 || cfg.tbl_edges ? "|" : "");
|
533 |
+
}
|
534 |
+
return "\n" + trim12(buf);
|
535 |
+
}]
|
536 |
+
}) : lib.ctblk.extend();
|
537 |
+
|
538 |
+
lib.tbody = cfg.gfm_tbls ? lib.cblk.extend() : lib.ctblk.extend();
|
539 |
+
|
540 |
+
lib.tfoot = cfg.gfm_tbls ? lib.cblk.extend() : lib.ctblk.extend();
|
541 |
+
|
542 |
+
lib.tr = cfg.gfm_tbls ? lib.cblk.extend({
|
543 |
+
wrapK: [cfg.tbl_edges ? "| " : "", cfg.tbl_edges ? " |" : ""],
|
544 |
+
}) : lib.ctblk.extend();
|
545 |
+
|
546 |
+
lib.th = cfg.gfm_tbls ? lib.inl.extend({
|
547 |
+
guts: null,
|
548 |
+
// TODO: DRY?
|
549 |
+
wrap: [function() {
|
550 |
+
var col = this.p.p.p.cols[this.i],
|
551 |
+
spc = this.i == 0 ? "" : " ",
|
552 |
+
pad, fill = col.w - this.guts.length;
|
553 |
+
|
554 |
+
switch (col.a[0]) {
|
555 |
+
case "r": pad = rep(" ", fill); break;
|
556 |
+
case "c": pad = rep(" ", Math.floor(fill/2)); break;
|
557 |
+
default: pad = "";
|
558 |
+
}
|
559 |
+
|
560 |
+
return spc + pad;
|
561 |
+
}, function() {
|
562 |
+
var col = this.p.p.p.cols[this.i],
|
563 |
+
edg = this.i == this.p.c.length - 1 ? "" : " |",
|
564 |
+
pad, fill = col.w - this.guts.length;
|
565 |
+
|
566 |
+
switch (col.a[0]) {
|
567 |
+
case "r": pad = ""; break;
|
568 |
+
case "c": pad = rep(" ", Math.ceil(fill/2)); break;
|
569 |
+
default: pad = rep(" ", fill);
|
570 |
+
}
|
571 |
+
|
572 |
+
return pad + edg;
|
573 |
+
}],
|
574 |
+
prep: function() {
|
575 |
+
this.guts = this.rendK(); // pre-render
|
576 |
+
this.rendK = function() {return this.guts};
|
577 |
+
|
578 |
+
var cols = this.p.p.p.cols;
|
579 |
+
if (!cols[this.i])
|
580 |
+
cols[this.i] = {w: null, a: ""}; // width and alignment
|
581 |
+
var col = cols[this.i];
|
582 |
+
col.w = Math.max(col.w || 0, this.guts.length);
|
583 |
+
if (this.e.align)
|
584 |
+
col.a = this.e.align;
|
585 |
+
}
|
586 |
+
}) : lib.ctblk.extend();
|
587 |
+
|
588 |
+
lib.td = lib.th.extend();
|
589 |
+
|
590 |
+
lib.txt = lib.inl.extend({
|
591 |
+
initK: function()
|
592 |
+
{
|
593 |
+
this.c = this.e.textContent.split(/^/gm);
|
594 |
+
},
|
595 |
+
rendK: function()
|
596 |
+
{
|
597 |
+
var kids = this.c.join("").replace(/\r/gm, "");
|
598 |
+
|
599 |
+
// this is strange, cause inside of code, inline should not be processed, but is?
|
600 |
+
if (!(this.p instanceof lib.code || this.p instanceof lib.pre)) {
|
601 |
+
kids = kids
|
602 |
+
.replace(/^\s*#/gm,"\\#")
|
603 |
+
.replace(/\*/gm,"\\*");
|
604 |
+
}
|
605 |
+
|
606 |
+
if (this.i == 0)
|
607 |
+
kids = kids.replace(/^\n+/, "");
|
608 |
+
if (this.i == this.p.c.length - 1)
|
609 |
+
kids = kids.replace(/\n+$/, "");
|
610 |
+
|
611 |
+
return kids;
|
612 |
+
}
|
613 |
+
});
|
614 |
+
|
615 |
+
lib.rawhtml = lib.blk.extend({
|
616 |
+
initK: function()
|
617 |
+
{
|
618 |
+
this.guts = outerHTML(this.e);
|
619 |
+
},
|
620 |
+
rendK: function()
|
621 |
+
{
|
622 |
+
return this.guts;
|
623 |
+
}
|
624 |
+
});
|
625 |
+
|
626 |
+
// compile regexes
|
627 |
+
for (var i in cfg.unsup_tags)
|
628 |
+
cfg.unsup_tags[i] = new RegExp("^(?:" + (i == "inline" ? "a|em|strong|img|code|del|" : "") + cfg.unsup_tags[i].replace(/\s/g, "|") + ")$");
|
629 |
+
};
|
630 |
+
|
631 |
+
/*!
|
632 |
+
* klass: a classical JS OOP façade
|
633 |
+
* https://github.com/ded/klass
|
634 |
+
* License MIT (c) Dustin Diaz & Jacob Thornton 2012
|
635 |
+
*/
|
636 |
+
!function(a,b){typeof define=="function"?define(b):typeof module!="undefined"?module.exports=b():this[a]=b()}("klass",function(){function f(a){return j.call(g(a)?a:function(){},a,1)}function g(a){return typeof a===c}function h(a,b,c){return function(){var d=this.supr;this.supr=c[e][a];var f=b.apply(this,arguments);return this.supr=d,f}}function i(a,b,c){for(var f in b)b.hasOwnProperty(f)&&(a[f]=g(b[f])&&g(c[e][f])&&d.test(b[f])?h(f,b[f],c):b[f])}function j(a,b){function c(){}function l(){this.init?this.init.apply(this,arguments):(b||h&&d.apply(this,arguments),j.apply(this,arguments))}c[e]=this[e];var d=this,f=new c,h=g(a),j=h?a:this,k=h?{}:a;return l.methods=function(a){return i(f,a,d),l[e]=f,this},l.methods.call(l,k).prototype.constructor=l,l.extend=arguments.callee,l[e].implement=l.statics=function(a,b){return a=typeof a=="string"?function(){var c={};return c[a]=b,c}():a,i(this,a,d),this},l}var a=this,b=a.klass,c="function",d=/xyz/.test(function(){xyz})?/\bsupr\b/:/.*/,e="prototype";return f.noConflict=function(){return a.klass=b,this},a.klass=f,f});
|
package.xml
CHANGED
@@ -1,30 +1,33 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>markdown</name>
|
4 |
-
<version>
|
5 |
<stability>stable</stability>
|
6 |
-
<license uri="https://github.com/SchumacherFM/Magento-Markdown">
|
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>
|
|
|
|
|
11 |

|
12 |
-
Full
|
13 |
-

|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
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
|
|
|
|
|
24 |
<authors><author><name>Cyrill Schumacher</name><user>cyrills</user><email>cyrill@schumacher.fm</email></author></authors>
|
25 |
-
<date>2013-
|
26 |
-
<time>
|
27 |
-
<contents><target name="magecommunity"><dir name="SchumacherFM"><dir name="Markdown"><dir><dir name="Helper"><file name="Data.php" hash="
|
28 |
<compatible/>
|
29 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
30 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>markdown</name>
|
4 |
+
<version>2.0.0</version>
|
5 |
<stability>stable</stability>
|
6 |
+
<license uri="https://github.com/SchumacherFM/Magento-Markdown">BSD-3-Clause</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>Markdown is a text-to-HTML conversion tool for web writers. Markdown
|
11 |
+
allows you to write using an easy-to-read, easy-to-write plain text
|
12 |
+
format, then convert it to structurally valid XHTML (or HTML).
|
13 |

|
14 |
+
- Full support of Markdown Extra
|
15 |
+
- Renders all CMS pages and all CMS blocks (Mage_Cms_Block_Block and Mage_Cms_Block_Widget_Block)
|
16 |
+
- Renders every transactional email as Markdown (or MD Extra)
|
17 |
+
- Rendering of catalog product and category short and long description fields have to be implemented in the phtml files by yourself.
|
18 |
+
- Integrates the awesome http://epiceditor.com: split fullscreen editing, live previewing, automatic draft saving and offline support.
|
19 |
+
- Drag'n'Drop of images supported in textarea fields. Automatic image uploading integrated (>=
|
20 |
+
IE10, Safari 6.0.2, FX3.6, Chrome 7, Opera 12.02)
|
21 |
+
- Converting of HTML into Markdown. Client side via JavaScript.
|
|
|
22 |

|
23 |
For further information please see the github repository: https://github.com/SchumacherFM/Magento-Markdown</description>
|
24 |
+
<notes>https://github.com/SchumacherFM/Magento-Markdown
|
25 |
+

|
26 |
+
Tons of new features! See the github pages for the version history.</notes>
|
27 |
<authors><author><name>Cyrill Schumacher</name><user>cyrills</user><email>cyrill@schumacher.fm</email></author></authors>
|
28 |
+
<date>2013-10-13</date>
|
29 |
+
<time>07:21:10</time>
|
30 |
+
<contents><target name="magecommunity"><dir name="SchumacherFM"><dir name="Markdown"><dir><dir name="Helper"><file name="Data.php" hash="56a3abd176deb0f2318bd4c6be98f950"/></dir><dir name="Model"><dir name="Editor"><file name="Observer.php" hash="0683e4ed2e97c9efbabea6aad92c1f44"/></dir><dir name="Markdown"><file name="Abstract.php" hash="237784e5f749406fca86e88172cab2ea"/><file name="Interface.php" hash="05df0ecf7a7c6bc09481f213cdc98255"/><file name="Observer.php" hash="2d8d754cf465bb3a85cd826a11074d0a"/><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"><dir name="Adminhtml"><file name="Block.php" hash="efe852cb712631d2bdeb56ed4be02a48"/><file name="EpicEditor.php" hash="ac01b829d5ad29c2c5412ace1448b194"/><file name="LayoutUpdate.php" hash="a01b599ebed057f9a99266cb91441a99"/></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="MarkdownController.php" hash="d8180e18071016883615d8f727a3300e"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="27c358363c32632f51affbecae3a24a0"/><file name="config.xml" hash="5e48b57a0fd5cf6b1665c4696ccadf22"/><file name="system.xml" hash="d31cf185d664c7f3424214ebc5239aaf"/></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="5f073545b849100ed7c1f1ba1685fb4b"/></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="markdown"><dir><dir name="adminhtml"><file name="epiceditor.js" hash="5c29b9d4d25d897ba63e9109ba6e3564"/><file name="filereader.js" hash="3ed749a9b0843d0911b41f8be26364fa"/><dir name="highlight"><dir name="styles"><file name="xcode.css" hash="d99d394b8a22d59c8546f84b683dc648"/></dir></dir><file name="highlight.pack.js" hash="b60b28a732e22d75e690bc32d8606354"/><file name="markdown.js" hash="ac58ac234a377e3b3a4e2cab828268d7"/><file name="marked.js" hash="8af08dcb5d207265f604dce4c250e6ec"/><file name="reMarked.js" hash="9adbec6c65fb488a754103e63b94ad58"/></dir></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="markdown"><file name="mdm.css" hash="19b49b67b9b52b25f5f7d2106cc73892"/></dir><dir name="epiceditor"><dir><dir name="highlight"><dir name="styles"><file name="default.css" hash="05519f4875102535137ef0141f26864b"/><file name="github.css" hash="ca6ea80f87a205fdf919439bad4c27db"/><file name="googlecode.css" hash="a4c13deaf6eeb2858cf7b0b300992cab"/></dir></dir><dir name="themes"><dir name="base"><file name="epiceditor.css" hash="72d9ff0a1296bf28b815d696129bb086"/></dir><dir name="editor"><file name="epic-dark.css" hash="872c9540cedbf5cdf69ca2b0accb3cef"/><file name="epic-light.css" hash="68d9441f297c73180dd83545ee70117a"/></dir><dir name="preview"><file name="bartik.css" hash="a8a3efffd02c3acf6e3dc62ee5e92936"/><file name="github.css" hash="6085b7303f9a3c3cc3d2d8039487bf5d"/><file name="githubNxcode.css" hash="c5639fe4cd88f0416c15892f2f9b90b2"/><file name="preview-dark.css" hash="660b85886b844d592e2c722937b438e1"/></dir></dir></dir></dir></dir></dir></dir></target></contents>
|
31 |
<compatible/>
|
32 |
<dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
|
33 |
</package>
|
skin/adminhtml/default/default/epiceditor/highlight/styles/default.css
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
|
3 |
+
Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
|
4 |
+
|
5 |
+
*/
|
6 |
+
|
7 |
+
pre code {
|
8 |
+
display: block; padding: 0.5em;
|
9 |
+
background: #F0F0F0;
|
10 |
+
}
|
11 |
+
|
12 |
+
pre code,
|
13 |
+
pre .subst,
|
14 |
+
pre .tag .title,
|
15 |
+
pre .lisp .title,
|
16 |
+
pre .clojure .built_in,
|
17 |
+
pre .nginx .title {
|
18 |
+
color: black;
|
19 |
+
}
|
20 |
+
|
21 |
+
pre .string,
|
22 |
+
pre .title,
|
23 |
+
pre .constant,
|
24 |
+
pre .parent,
|
25 |
+
pre .tag .value,
|
26 |
+
pre .rules .value,
|
27 |
+
pre .rules .value .number,
|
28 |
+
pre .preprocessor,
|
29 |
+
pre .ruby .symbol,
|
30 |
+
pre .ruby .symbol .string,
|
31 |
+
pre .aggregate,
|
32 |
+
pre .template_tag,
|
33 |
+
pre .django .variable,
|
34 |
+
pre .smalltalk .class,
|
35 |
+
pre .addition,
|
36 |
+
pre .flow,
|
37 |
+
pre .stream,
|
38 |
+
pre .bash .variable,
|
39 |
+
pre .apache .tag,
|
40 |
+
pre .apache .cbracket,
|
41 |
+
pre .tex .command,
|
42 |
+
pre .tex .special,
|
43 |
+
pre .erlang_repl .function_or_atom,
|
44 |
+
pre .markdown .header {
|
45 |
+
color: #800;
|
46 |
+
}
|
47 |
+
|
48 |
+
pre .comment,
|
49 |
+
pre .annotation,
|
50 |
+
pre .template_comment,
|
51 |
+
pre .diff .header,
|
52 |
+
pre .chunk,
|
53 |
+
pre .markdown .blockquote {
|
54 |
+
color: #888;
|
55 |
+
}
|
56 |
+
|
57 |
+
pre .number,
|
58 |
+
pre .date,
|
59 |
+
pre .regexp,
|
60 |
+
pre .literal,
|
61 |
+
pre .smalltalk .symbol,
|
62 |
+
pre .smalltalk .char,
|
63 |
+
pre .go .constant,
|
64 |
+
pre .change,
|
65 |
+
pre .markdown .bullet,
|
66 |
+
pre .markdown .link_url {
|
67 |
+
color: #080;
|
68 |
+
}
|
69 |
+
|
70 |
+
pre .label,
|
71 |
+
pre .javadoc,
|
72 |
+
pre .ruby .string,
|
73 |
+
pre .decorator,
|
74 |
+
pre .filter .argument,
|
75 |
+
pre .localvars,
|
76 |
+
pre .array,
|
77 |
+
pre .attr_selector,
|
78 |
+
pre .important,
|
79 |
+
pre .pseudo,
|
80 |
+
pre .pi,
|
81 |
+
pre .doctype,
|
82 |
+
pre .deletion,
|
83 |
+
pre .envvar,
|
84 |
+
pre .shebang,
|
85 |
+
pre .apache .sqbracket,
|
86 |
+
pre .nginx .built_in,
|
87 |
+
pre .tex .formula,
|
88 |
+
pre .erlang_repl .reserved,
|
89 |
+
pre .prompt,
|
90 |
+
pre .markdown .link_label,
|
91 |
+
pre .vhdl .attribute,
|
92 |
+
pre .clojure .attribute,
|
93 |
+
pre .coffeescript .property {
|
94 |
+
color: #88F
|
95 |
+
}
|
96 |
+
|
97 |
+
pre .keyword,
|
98 |
+
pre .id,
|
99 |
+
pre .phpdoc,
|
100 |
+
pre .title,
|
101 |
+
pre .built_in,
|
102 |
+
pre .aggregate,
|
103 |
+
pre .css .tag,
|
104 |
+
pre .javadoctag,
|
105 |
+
pre .phpdoc,
|
106 |
+
pre .yardoctag,
|
107 |
+
pre .smalltalk .class,
|
108 |
+
pre .winutils,
|
109 |
+
pre .bash .variable,
|
110 |
+
pre .apache .tag,
|
111 |
+
pre .go .typename,
|
112 |
+
pre .tex .command,
|
113 |
+
pre .markdown .strong,
|
114 |
+
pre .request,
|
115 |
+
pre .status {
|
116 |
+
font-weight: bold;
|
117 |
+
}
|
118 |
+
|
119 |
+
pre .markdown .emphasis {
|
120 |
+
font-style: italic;
|
121 |
+
}
|
122 |
+
|
123 |
+
pre .nginx .built_in {
|
124 |
+
font-weight: normal;
|
125 |
+
}
|
126 |
+
|
127 |
+
pre .coffeescript .javascript,
|
128 |
+
pre .javascript .xml,
|
129 |
+
pre .tex .formula,
|
130 |
+
pre .xml .javascript,
|
131 |
+
pre .xml .vbscript,
|
132 |
+
pre .xml .css,
|
133 |
+
pre .xml .cdata {
|
134 |
+
opacity: 0.5;
|
135 |
+
}
|
skin/adminhtml/default/default/epiceditor/highlight/styles/github.css
ADDED
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
|
3 |
+
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
|
4 |
+
|
5 |
+
*/
|
6 |
+
|
7 |
+
pre code {
|
8 |
+
display: block; padding: 0.5em;
|
9 |
+
color: #333;
|
10 |
+
background: #f8f8ff
|
11 |
+
}
|
12 |
+
|
13 |
+
pre .comment,
|
14 |
+
pre .template_comment,
|
15 |
+
pre .diff .header,
|
16 |
+
pre .javadoc {
|
17 |
+
color: #998;
|
18 |
+
font-style: italic
|
19 |
+
}
|
20 |
+
|
21 |
+
pre .keyword,
|
22 |
+
pre .css .rule .keyword,
|
23 |
+
pre .winutils,
|
24 |
+
pre .javascript .title,
|
25 |
+
pre .nginx .title,
|
26 |
+
pre .subst,
|
27 |
+
pre .request,
|
28 |
+
pre .status {
|
29 |
+
color: #333;
|
30 |
+
font-weight: bold
|
31 |
+
}
|
32 |
+
|
33 |
+
pre .number,
|
34 |
+
pre .hexcolor,
|
35 |
+
pre .ruby .constant {
|
36 |
+
color: #099;
|
37 |
+
}
|
38 |
+
|
39 |
+
pre .string,
|
40 |
+
pre .tag .value,
|
41 |
+
pre .phpdoc,
|
42 |
+
pre .tex .formula {
|
43 |
+
color: #d14
|
44 |
+
}
|
45 |
+
|
46 |
+
pre .title,
|
47 |
+
pre .id {
|
48 |
+
color: #900;
|
49 |
+
font-weight: bold
|
50 |
+
}
|
51 |
+
|
52 |
+
pre .javascript .title,
|
53 |
+
pre .lisp .title,
|
54 |
+
pre .clojure .title,
|
55 |
+
pre .subst {
|
56 |
+
font-weight: normal
|
57 |
+
}
|
58 |
+
|
59 |
+
pre .class .title,
|
60 |
+
pre .haskell .type,
|
61 |
+
pre .vhdl .literal,
|
62 |
+
pre .tex .command {
|
63 |
+
color: #458;
|
64 |
+
font-weight: bold
|
65 |
+
}
|
66 |
+
|
67 |
+
pre .tag,
|
68 |
+
pre .tag .title,
|
69 |
+
pre .rules .property,
|
70 |
+
pre .django .tag .keyword {
|
71 |
+
color: #000080;
|
72 |
+
font-weight: normal
|
73 |
+
}
|
74 |
+
|
75 |
+
pre .attribute,
|
76 |
+
pre .variable,
|
77 |
+
pre .lisp .body {
|
78 |
+
color: #008080
|
79 |
+
}
|
80 |
+
|
81 |
+
pre .regexp {
|
82 |
+
color: #009926
|
83 |
+
}
|
84 |
+
|
85 |
+
pre .class {
|
86 |
+
color: #458;
|
87 |
+
font-weight: bold
|
88 |
+
}
|
89 |
+
|
90 |
+
pre .symbol,
|
91 |
+
pre .ruby .symbol .string,
|
92 |
+
pre .lisp .keyword,
|
93 |
+
pre .tex .special,
|
94 |
+
pre .prompt {
|
95 |
+
color: #990073
|
96 |
+
}
|
97 |
+
|
98 |
+
pre .built_in,
|
99 |
+
pre .lisp .title,
|
100 |
+
pre .clojure .built_in {
|
101 |
+
color: #0086b3
|
102 |
+
}
|
103 |
+
|
104 |
+
pre .preprocessor,
|
105 |
+
pre .pi,
|
106 |
+
pre .doctype,
|
107 |
+
pre .shebang,
|
108 |
+
pre .cdata {
|
109 |
+
color: #999;
|
110 |
+
font-weight: bold
|
111 |
+
}
|
112 |
+
|
113 |
+
pre .deletion {
|
114 |
+
background: #fdd
|
115 |
+
}
|
116 |
+
|
117 |
+
pre .addition {
|
118 |
+
background: #dfd
|
119 |
+
}
|
120 |
+
|
121 |
+
pre .diff .change {
|
122 |
+
background: #0086b3
|
123 |
+
}
|
124 |
+
|
125 |
+
pre .chunk {
|
126 |
+
color: #aaa
|
127 |
+
}
|
skin/adminhtml/default/default/epiceditor/highlight/styles/googlecode.css
ADDED
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
|
3 |
+
Google Code style (c) Aahan Krish <geekpanth3r@gmail.com>
|
4 |
+
|
5 |
+
*/
|
6 |
+
|
7 |
+
pre code {
|
8 |
+
display: block; padding: 0.5em;
|
9 |
+
background: white; color: black;
|
10 |
+
}
|
11 |
+
|
12 |
+
pre .comment,
|
13 |
+
pre .template_comment,
|
14 |
+
pre .javadoc,
|
15 |
+
pre .comment * {
|
16 |
+
color: #800;
|
17 |
+
}
|
18 |
+
|
19 |
+
pre .keyword,
|
20 |
+
pre .method,
|
21 |
+
pre .list .title,
|
22 |
+
pre .clojure .built_in,
|
23 |
+
pre .nginx .title,
|
24 |
+
pre .tag .title,
|
25 |
+
pre .setting .value,
|
26 |
+
pre .winutils,
|
27 |
+
pre .tex .command,
|
28 |
+
pre .http .title,
|
29 |
+
pre .request,
|
30 |
+
pre .status {
|
31 |
+
color: #008;
|
32 |
+
}
|
33 |
+
|
34 |
+
pre .envvar,
|
35 |
+
pre .tex .special {
|
36 |
+
color: #660;
|
37 |
+
}
|
38 |
+
|
39 |
+
pre .string,
|
40 |
+
pre .tag .value,
|
41 |
+
pre .cdata,
|
42 |
+
pre .filter .argument,
|
43 |
+
pre .attr_selector,
|
44 |
+
pre .apache .cbracket,
|
45 |
+
pre .date,
|
46 |
+
pre .regexp {
|
47 |
+
color: #080;
|
48 |
+
}
|
49 |
+
|
50 |
+
pre .sub .identifier,
|
51 |
+
pre .pi,
|
52 |
+
pre .tag,
|
53 |
+
pre .tag .keyword,
|
54 |
+
pre .decorator,
|
55 |
+
pre .ini .title,
|
56 |
+
pre .shebang,
|
57 |
+
pre .prompt,
|
58 |
+
pre .hexcolor,
|
59 |
+
pre .rules .value,
|
60 |
+
pre .css .value .number,
|
61 |
+
pre .literal,
|
62 |
+
pre .symbol,
|
63 |
+
pre .ruby .symbol .string,
|
64 |
+
pre .number,
|
65 |
+
pre .css .function,
|
66 |
+
pre .clojure .attribute {
|
67 |
+
color: #066;
|
68 |
+
}
|
69 |
+
|
70 |
+
pre .class .title,
|
71 |
+
pre .haskell .type,
|
72 |
+
pre .smalltalk .class,
|
73 |
+
pre .javadoctag,
|
74 |
+
pre .yardoctag,
|
75 |
+
pre .phpdoc,
|
76 |
+
pre .typename,
|
77 |
+
pre .tag .attribute,
|
78 |
+
pre .doctype,
|
79 |
+
pre .class .id,
|
80 |
+
pre .built_in,
|
81 |
+
pre .setting,
|
82 |
+
pre .params,
|
83 |
+
pre .variable,
|
84 |
+
pre .clojure .title {
|
85 |
+
color: #606;
|
86 |
+
}
|
87 |
+
|
88 |
+
pre .css .tag,
|
89 |
+
pre .rules .property,
|
90 |
+
pre .pseudo,
|
91 |
+
pre .subst {
|
92 |
+
color: #000;
|
93 |
+
}
|
94 |
+
|
95 |
+
pre .css .class, pre .css .id {
|
96 |
+
color: #9B703F;
|
97 |
+
}
|
98 |
+
|
99 |
+
pre .value .important {
|
100 |
+
color: #ff7700;
|
101 |
+
font-weight: bold;
|
102 |
+
}
|
103 |
+
|
104 |
+
pre .rules .keyword {
|
105 |
+
color: #C5AF75;
|
106 |
+
}
|
107 |
+
|
108 |
+
pre .annotation,
|
109 |
+
pre .apache .sqbracket,
|
110 |
+
pre .nginx .built_in {
|
111 |
+
color: #9B859D;
|
112 |
+
}
|
113 |
+
|
114 |
+
pre .preprocessor,
|
115 |
+
pre .preprocessor * {
|
116 |
+
color: #444;
|
117 |
+
}
|
118 |
+
|
119 |
+
pre .tex .formula {
|
120 |
+
background-color: #EEE;
|
121 |
+
font-style: italic;
|
122 |
+
}
|
123 |
+
|
124 |
+
pre .diff .header,
|
125 |
+
pre .chunk {
|
126 |
+
color: #808080;
|
127 |
+
font-weight: bold;
|
128 |
+
}
|
129 |
+
|
130 |
+
pre .diff .change {
|
131 |
+
background-color: #BCCFF9;
|
132 |
+
}
|
133 |
+
|
134 |
+
pre .addition {
|
135 |
+
background-color: #BAEEBA;
|
136 |
+
}
|
137 |
+
|
138 |
+
pre .deletion {
|
139 |
+
background-color: #FFC8BD;
|
140 |
+
}
|
141 |
+
|
142 |
+
pre .comment .yardoctag {
|
143 |
+
font-weight: bold;
|
144 |
+
}
|
skin/adminhtml/default/default/epiceditor/themes/base/epiceditor.css
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html, body, iframe, div {
|
2 |
+
margin : 0;
|
3 |
+
padding : 0;
|
4 |
+
}
|
5 |
+
|
6 |
+
#epiceditor-utilbar {
|
7 |
+
position : fixed;
|
8 |
+
bottom : 10px;
|
9 |
+
right : 10px;
|
10 |
+
}
|
11 |
+
|
12 |
+
#epiceditor-utilbar button {
|
13 |
+
display : block;
|
14 |
+
float : left;
|
15 |
+
width : 30px;
|
16 |
+
height : 30px;
|
17 |
+
border : none;
|
18 |
+
background : none;
|
19 |
+
}
|
20 |
+
|
21 |
+
#epiceditor-utilbar button.epiceditor-toggle-preview-btn {
|
22 |
+
background-image : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAf9JREFUeNrsVu1twjAQLZmAEcIGYYKGDWACkgkSkPiQ+CifAoEgyQTQDegEpROQDZoRMgH0HToj1yIglKr90Vg62T6f/e4d9gu50+n09BctlwFnwP8TOAgCA10VRr2ZELaHhbBXx3HCVMC+71voXmD6g4Qi2NB13e1DwAAkZhtmmKYRcxsJhHeBPc8bMMufbDU0PxF4vV4TSyth8477csI6lTV/a71er9tioonBarXaIAmLErliNWyqoM8nrJPpHFNLWLcI4xvj5XKpMo2ZgcvzIvs+75S0wKwPPB/CnpWXsG00Gra2WCwshekOVoC9Sb6IGN1ge2HNsWK+B0iJqxAL5oSpYeDJJW02mxVYLAWSGfDtebylA68Bc4wh+ahK5PcxLh6PR5GUpym/iTOfz89PqNVqhRI4iQf1/o174HNMVYDSGeTDmXQ3znogCGrtdpsYVBhER1aH2Wzm8iE7UR74DMTWGNxUQWmNYqTEzq8APoo9sJ8wKoR5eU7T6VQVjZAvx4YvDJWt1Ol0QsTqkppF8EW8/12OhTnSpT2LCe2/KiCTyUQVkJgPuwgb6XG32w05Xui4q0imLLNDxA/uSuZ4PNaZqZlSsejDYfd6veihj8RoNDK5XOUHAen3Dfr9/j7VZxEJ6AwuxCCvhMTM7oNAARhl/0Ay4Az419qXAAMAfBdK7281j6YAAAAASUVORK5CYII=);
|
23 |
+
}
|
24 |
+
|
25 |
+
#epiceditor-utilbar button.epiceditor-toggle-edit-btn {
|
26 |
+
background-image : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnVJREFUeNrsV+lt4lAQNtEWAB2QCtZ0ABWsqYB1BU5AgDgkQOISl9cV4FQQtgLYCuKtIN4K4gogM9H3pMmLTTh24c+O9An7+XnOb8aP1G63M64hN8aV5GqGvxyyyfO8Y3S6hDtc2wTfcZyLRPwdvxEbPSviIwjIRtO49s9ONSRLMIGvwkBI+EPYEEqyQmcZdl2Xo3BgcJ90xPUGDh1veLFYWCBK9oQ6P4BgiXVO6fUjg5zCJcE6kVxsLEN4QTlWzO5yuRwlGp7P55zOxz1RRqK2SfKD8BvOG4IHxUqlEnxop9lsZpITa0KWndGwIeQIXswzHbynpK2xzjXbeBfxdDrlhbUWjYyuiJS9fBJxgL3PItKsprNQrVaD1GQyYUVP2oYelDziPoPnT5+k2QajleEC3usI/exM7oYiXor0hpxS8qhLv5FIVVrcBwkp5ueclbS27qNMvkj7kg3nZX1qtVqAaSUN5OGUwn2M4RUb3263plh700E6I7wTKn1suCAW3PF4zL1r1Ov1SBhXZLEJFqGTQCq5N1BZIp3s+DOi5fXcG7lGo1Ea5DIFSWzcq7a4R6uYqJmlkSqHoeGKeq+w905MtGKj0Yje9TE5ID9pqictQQwmXTfh82cIJ0NML0d0QY8MdhMn13A4zENB0hAJEYn6EnGL3MZ0hsyG3Ww2g70jU8lgMOhqHicJz+KfovVkz3J5/FardfhBgDZzS90SeoJ8cXjQJlUAEmZUCx30kYiTfr9vgFRc72+ChCHSzNH+Qgk+fA7b7fZZJ5AAiIRhT4zUv3/Y07LiaPW9yPE2L5jrI/p/d7wVEZe0U8bJkvr/F+ZS8irAAIorRozUvI0gAAAAAElFTkSuQmCC);
|
27 |
+
}
|
28 |
+
|
29 |
+
#epiceditor-utilbar button.epiceditor-fullscreen-btn {
|
30 |
+
background-image : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAY5JREFUeNrsV8tthDAQhYgCtoV04BKghK2En5AQBw4IITjwq2RLgBJcwpawHZAxMpGDYGwTFPaQkUbG1sybj58NmNM0GVfIh3GRXBbYEid932N9d1zXHWWAGAb4m+9VsUA0H5SubKkKIGA4qyUC2qKBxSCe541HKln7dV2nVbHRtq0Nw7CXGNtz/jzwqjZ5odtqTOagQRC82KRpGkcS/L2Ok7lXZV3Xp7Q6DMNR2mqNthMhKXLqzcUCc6Wgn3wU1wlX1PboHs8tjaLoyVtLT7JFK2ZZM6CZvWyE+X1Voaj3la3DMA63epGqqm4wfyCBH8xmz1+Z1WVZ2vyqU2HvHtv9OI4PsRpjL91YV2a7pcB8onmOifYFUhSFLQCTnQtkDpokyYv73JBtcAQsA3zGTXJBEgNXgrF3CcrBZGwnC+4uqxHnH+zN8/ybvexZwvZNhlsHbrt5CyCgDtu1XosUe58K4kuOF9EKnKYp20eVrxDUJssyreM0bDg4kIw0EfCbftvqQ6KKYf7/wvyVfAkwAMjqoFSaWbrBAAAAAElFTkSuQmCC);
|
31 |
+
}
|
32 |
+
|
33 |
+
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and ( min-device-pixel-ratio: 2), only screen and ( min-resolution: 192dpi), only screen and ( min-resolution: 2dppx) {
|
34 |
+
#epiceditor-utilbar button.epiceditor-toggle-preview-btn {
|
35 |
+
background : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAABrVBMVEWIiIiHh4eIiIiJiYmEhISEhISEhISMjIyNjY2MjIyNjY2MjIyFhYWDg4OFhYWKioqKioqBgYGJiYmJiYmJiYmKioqKioqFhYWIiIiJiYmIiIiJiYmIiIiGhoaIiIiGhoaIiIiHh4eHh4eGhoaFhYWKioqFhYWEhISFhYWEhISDg4ONjY2NjY2MjIyHh4eMjIyLi4uCgoKCgoKCgoKBgYGBgYGOjo6Ojo6BgYGPj4+Ojo6Hh4eNjY2Pj4+BgYGNjY2BgYGHh4eQkJCNjY2FhYWHh4eDg4OQkJCQkJCAgICCgoKAgICAgICQkJCQkJCQkJCAgICQkJCAgICQkJCFhYWHh4eHh4eGhoaKioqGhoaMjIyDg4OEhISDg4OEhISDg4OEhISKioqBgYGJiYmKioqKioqJiYmMjIyEhISCgoKGhoaLi4uPj4+Pj4+BgYGKioqDg4OGhoaGhoaMjIyHh4eEhISEhISDg4OIiIiJiYmGhoaHh4eJiYkAAACAgICFhYWQkJCIiIiEhISLi4uDg4OHh4eGhoaCgoKBgYGJiYmMjIyOjo6KioqNjY2Pj4+o6Lr0AAAAfnRSTlPfvxDPEL8gv5/Pr3AQ3++vn8+/cCCA34/vj8/vMJ+vgJ+vYN/fMIBAv4/v38/v39+PgBBg74DPgGAwMHDvrzBQj1AggJ8wIHC/IM9gjxBQgO+vv89Qz0C/70Bgz89ggIDvYN/fII8wIHDvMJ+/QBBAMBDPnxBgML9AEI/vQACT8cYwAAACXElEQVR42u2WV1caURRGJ73H9J7YW+y99957ARREURAFQRFEOFGMkybxN+eec2cWUwBnrTwli/1yvvnm7PvEuoMAf0FGzsj/nDwxOTUzdyoxNzM1OWFU7h0aPtUxPNRrQPZ0XKagw3OF7Nm9TMOuJ43cQmpavSWV3HRhgKakcmvjhSEaW/VyV/tvg7R3aeU+9ULZ/fLEQ/ndMvXbPrV88EvBvQdOMCsLMzjNd5TFgSTr3SpWOCuUTYWTVVV6m+Sdr0qqqVGxw6pqXUPyZlziFaU9Vi3HVSyzag+D/YlcbXLZLm+85AsOgMK4hkIABz/YkSVVdpS3fnKevQCIYgCcGqKslGd0g3dbIIR5fP8cZCkMdOANWeSLEJZklt5StxEWcmLIuw+AHGE+YiEWE67jGxnlO8xv8OGTEBGRRSACmNtYyBUjgcCCKJPLqjYMAeD04ENEGIjQ7AGikuUFNhdF8Vogj0T5bDyqEjh55AwI4N7/hmRTe4zRxEM+ZuKYFSYeEP9HzPtuEFjm9pKf9W5KQLbKhSVMbkymfHL90i+s/wR5PM9iCaYiLOcLTogCrKEIYwkLD19T25/4bR+unSG3bkOQwiG1QZfV6gryBaqL5c01XCCZ9lbOCOvNUpouUOGishSK+dpKUHMZ2M6Jz7ZHNEO+hOoLUWVZZROx6a8hn+VcRWh1EOtBUuhcPiy+pBdg3fZ3DaOj2ma7LtXVW1uj0XVqTW2aS9/bUP8jJfUN3is+N97mp8nV9Wavka9kZ/e6zuzuNP59Hhkbn53+QkzPjo+NZP6TZOSM/L/LfwAJ69Ba3fXmtwAAAABJRU5ErkJggg==);
|
36 |
+
background-size : 30px 30px;
|
37 |
+
}
|
38 |
+
|
39 |
+
#epiceditor-utilbar button.epiceditor-toggle-edit-btn {
|
40 |
+
background : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAACNFBMVEWIiIiHh4eIiIiGhoaEhISDg4OCgoKDg4OMjIyNjY2MjIyMjIyLi4uMjIyKioqCgoKNjY2Ojo6Dg4ONjY2FhYWFhYWCgoKKioqKioqLi4uLi4uMjIyLi4uFhYWKioqKioqEhISJiYmJiYmEhISEhISFhYWEhISGhoaHh4eJiYmNjY2Hh4eKioqDg4ODg4OCgoKOjo6Ojo6Dg4OOjo6BgYGOjo6AgICCgoKNjY2Dg4OPj4+BgYGBgYGAgICOjo6BgYGOjo6AgICOjo6BgYGBgYGAgICPj4+QkJCQkJCQkJCQkJCPj4+NjY2IiIiIiIiFhYWFhYWEhISEhISGhoaDg4OGhoaDg4OHh4eDg4OCgoKMjIyLi4uLi4uKioqNjY2KioqNjY2NjY2NjY2Dg4OKioqGhoaJiYmIiIiGhoaFhYWEhISFhYWFhYWOjo6Pj4+FhYWGhoaPj4+Hh4eMjIyMjIyMjIyJiYmIiIiIiIiOjo6Ojo6CgoKBgYGPj4+QkJCHh4eHh4eEhISIiIiDg4OEhISDg4ODg4OLi4uHh4eEhISMjIyFhYWGhoaHh4eOjo6IiIiKioqKioqMjIyGhoaIiIiJiYmIiIiFhYWGhoaGhoaHh4eKioqJiYmLi4uIiIiGhoaJiYmHh4eGhoaGhoaJiYmFhYWKioqPj4+IiIiGhoYAAACAgICCgoKQkJCPj4+BgYGDg4OFhYWHh4eOjo6JiYmGhoaLi4uEhISIiIiNjY2MjIyKioqRGRgVAAAAq3RSTlNQz7+Pz4AQr4/vIK+Av99QICBQzyCv37/PcM+f378QgHAwgIBgnxBQMK+PgFCf34Bwn0BQv2Ag7zBwEFDvj4CAv1DvYK/f398gUICA39+fYHAwQHAQn78gz0DfYO8wgO+/YECPIK9gz89Av8/f31AwgK9A72AwIGCAMM+PICCvrxCfr+/fYCAgYO9QgGBQjyCPYM8QcM8wEEAgn58Qn+8w7+/fv0DvQEBA7wCxres+AAAC50lEQVR42u2XVUMbQRSFU3d3d3d3d8EpUKRoKbS40+LuDsEtQOFQKA2FEvhz3XsnS5IlJLB9a/s95J49M99sXpJsNPgD/st/oZwxJJGhTn4+RLxQJ78k9xnUyU+HJV6pk6OGiXR1ciy5sZizfPMrwzl9mIiak5x6/sLnUZmH9+9eqqAQCftyakXkqFUq7MpX6JbW2WBHDnxtmJUAIMiGfD3AYINArDdsCppNfmewxQqx4aRVObFm0ibLAW+aNYkz5ZL4SdusRIkI8SVKOcFyp/cu5ftYA6ySc4Kl3DZuxs4dhfAZV+CDQtNFm0lWuLsBFPoqXF9g9bjSZrlqypwqAC1TClqAtYprIVfLjT+f0gfAXyn7oY9GNZ/KiWVumX17OYYAIUp3O+AnDu7bZqxOk5zU+ZOpPwD0UABNBaEAaPYACBVCZ5Ik14vlg5ClVjFpC0NZ6lplGa0nxN2gSZkg2vtB9FOmKDUNCyemcTStMXXcpmh4yGUl5ToAORMOaGiflhtkoRKCfq41yTw+GFsHKeeIRUfwwbwKOo/eIATi3GQNivREVxyIZsqeADL1+swuvZEiAJ4UmsEUsVEODRAnNp2iulzekrVAbyJLPrYctJTJ7nGQjI7uMULXBIBjIyQWUWLeAGik0E39sQGKYU0QMmp1vGnADSjj0EFtk5uOjuKzOtgok8r34rxasMzEjDFhjdDJNsE7u2VXh9oYDgNllp/n8IgfzJbwXhq9zlRu5soZWtFFl/Zy8SkaljK0R6inJTEinLQo5aSFE889kkqUWvsCdM37ZcnHYnrNBhably5QyoJDtFuJK1xMF3mHgVlkHM2e4eYB02Xxfts/NwXBuSMWLIG7sTmbb/+Hzj3fy1wuQD6N3DMX5/g0VHDDQ3aXAR4jXsEb5/co9fbLN2KdlJbO/zmM5a0qH+KukXxOnfzoO5GmTr5M7mOoktP4xrfUyffIvQ118pNBiTvq5AeDxNV//W+CFX4Doxg1lHC8FNUAAAAASUVORK5CYII=);
|
41 |
+
background-size : 30px 30px;
|
42 |
+
}
|
43 |
+
|
44 |
+
#epiceditor-utilbar button.epiceditor-fullscreen-btn {
|
45 |
+
background : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAMAAAANIilAAAAA5FBMVEWPj4+JiYmJiYmCgoKGhoaPj4+Li4uEhISAgICNjY2Li4uNjY2QkJCFhYWEhISLi4uHh4eHh4eIiIiHh4eGhoaHh4eEhISOjo6EhISJiYmFhYWJiYmFhYWNjY2NjY2Hh4eOjo6CgoKGhoaKioqKioqJiYmKioqDg4ODg4OBgYGGhoaKioqKioqLi4uMjIyMjIyIiIiIiIiMjIyOjo6GhoaDg4ONjY2EhISPj4+CgoIAAACJiYmHh4eIiIiFhYWCgoKPj4+Li4uAgICKioqEhISGhoaBgYGOjo6MjIyQkJCNjY2Dg4O2Jy/OAAAAO3RSTlMQz0DPEHDPz0DvMDBAQBBAQBAQz88wMM/v7zAw788Q7xAQQM9AEBDPEEAwMO/v7zDvMEBA70BAQEBAAAENmbYAAAG1SURBVHja7dftM0JREMdxD5GkEEqKpBJRSc8rQq7Q////2Dnm3t85jtkTmmGG75t7Z3c/t9fN0Tf6x1/Dz0ZrZGZf/BJ8a9QjM/vCwks9Px5aBcslC+P3nPVmi8dcczrcHHM2flug1CHRYcoYNd0YFlrAL1yHqPOC9g9IdbAfjHAjYFjoT+FI1MfRiAM/cZdEl0+oVidVvRaMcAOMgJWGBUYSVhrWjdfvjKqrq1Vzsu7Cy1Vo7XXZhYuj0ahwfHY+sjo/Oy7woyhitkTQsESsZawstG6VlvDCfIlUmfSVVjpDqtL8goBLbKFhsRcwalxcB100CDkxLLQbJxKwpvb3At7Y2iRuJzd4V26HuM2tDQkPWMOamu1Awkeetx2qtDy/lvZaCW173pGIWetA/xBbF+ZgiVgjGcdutLJ7xO1l9VnMiWGhJdzl4vx4CNpN+ifJXUy7RPEuZ2C1AIY1NG5kHI4Dx8MynnBtovYkqHzi25OyP8ONiKFh3djQsCIecn2i/lBvMU+UXxwi3HyE832jvD0RsLuP8CN3Oh0+feRmixE+g7CdLb43WiEz++Jb+M//x/gB/ArCl0G4nsFuEQAAAABJRU5ErkJggg==);
|
46 |
+
background-size : 30px 30px;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
#epiceditor-utilbar button:last-child {
|
51 |
+
margin-left : 15px;
|
52 |
+
}
|
53 |
+
|
54 |
+
#epiceditor-utilbar button:hover {
|
55 |
+
cursor : pointer;
|
56 |
+
}
|
57 |
+
|
58 |
+
.epiceditor-edit-mode #epiceditor-utilbar button.epiceditor-toggle-edit-btn {
|
59 |
+
display : none;
|
60 |
+
}
|
61 |
+
|
62 |
+
.epiceditor-preview-mode #epiceditor-utilbar button.epiceditor-toggle-preview-btn {
|
63 |
+
display : none;
|
64 |
+
}
|
skin/adminhtml/default/default/epiceditor/themes/editor/epic-dark.css
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html {
|
2 |
+
padding : 10px;
|
3 |
+
}
|
4 |
+
|
5 |
+
body {
|
6 |
+
border : 0;
|
7 |
+
background : rgb(41, 41, 41);
|
8 |
+
font-family : monospace;
|
9 |
+
font-size : 14px;
|
10 |
+
padding : 10px;
|
11 |
+
color : #ddd;
|
12 |
+
line-height : 1.35em;
|
13 |
+
margin : 0;
|
14 |
+
padding : 0;
|
15 |
+
}
|
skin/adminhtml/default/default/epiceditor/themes/editor/epic-light.css
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html {
|
2 |
+
padding : 10px;
|
3 |
+
}
|
4 |
+
|
5 |
+
body {
|
6 |
+
border : 0;
|
7 |
+
background : #fff;
|
8 |
+
font-family : monospace;
|
9 |
+
font-size : 14px;
|
10 |
+
padding : 10px;
|
11 |
+
line-height : 1.35em;
|
12 |
+
margin : 0;
|
13 |
+
padding : 0;
|
14 |
+
}
|
skin/adminhtml/default/default/epiceditor/themes/preview/bartik.css
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
font-family : Georgia, "Times New Roman", Times, serif;
|
3 |
+
line-height : 1.5;
|
4 |
+
font-size : 87.5%;
|
5 |
+
word-wrap : break-word;
|
6 |
+
margin : 2em;
|
7 |
+
padding : 0;
|
8 |
+
border : 0;
|
9 |
+
outline : 0;
|
10 |
+
background : #fff;
|
11 |
+
}
|
12 |
+
|
13 |
+
h1,
|
14 |
+
h2,
|
15 |
+
h3,
|
16 |
+
h4,
|
17 |
+
h5,
|
18 |
+
h6 {
|
19 |
+
margin : 1.0em 0 0.5em;
|
20 |
+
font-weight : inherit;
|
21 |
+
}
|
22 |
+
|
23 |
+
h1 {
|
24 |
+
font-size : 1.357em;
|
25 |
+
color : #000;
|
26 |
+
}
|
27 |
+
|
28 |
+
h2 {
|
29 |
+
font-size : 1.143em;
|
30 |
+
}
|
31 |
+
|
32 |
+
p {
|
33 |
+
margin : 0 0 1.2em;
|
34 |
+
}
|
35 |
+
|
36 |
+
del {
|
37 |
+
text-decoration : line-through;
|
38 |
+
}
|
39 |
+
|
40 |
+
tr:nth-child(odd) {
|
41 |
+
background-color : #dddddd;
|
42 |
+
}
|
43 |
+
|
44 |
+
img {
|
45 |
+
outline : 0;
|
46 |
+
}
|
47 |
+
|
48 |
+
code {
|
49 |
+
background-color : #f2f2f2;
|
50 |
+
background-color : rgba(40, 40, 0, 0.06);
|
51 |
+
}
|
52 |
+
|
53 |
+
pre {
|
54 |
+
background-color : #f2f2f2;
|
55 |
+
background-color : rgba(40, 40, 0, 0.06);
|
56 |
+
margin : 10px 0;
|
57 |
+
overflow : hidden;
|
58 |
+
padding : 15px;
|
59 |
+
white-space : pre-wrap;
|
60 |
+
}
|
61 |
+
|
62 |
+
pre code {
|
63 |
+
font-size : 100%;
|
64 |
+
background-color : transparent;
|
65 |
+
}
|
66 |
+
|
67 |
+
blockquote {
|
68 |
+
background : #f7f7f7;
|
69 |
+
border-left : 1px solid #bbb;
|
70 |
+
font-style : italic;
|
71 |
+
margin : 1.5em 10px;
|
72 |
+
padding : 0.5em 10px;
|
73 |
+
}
|
74 |
+
|
75 |
+
blockquote:before {
|
76 |
+
color : #bbb;
|
77 |
+
content : "\201C";
|
78 |
+
font-size : 3em;
|
79 |
+
line-height : 0.1em;
|
80 |
+
margin-right : 0.2em;
|
81 |
+
vertical-align : -.4em;
|
82 |
+
}
|
83 |
+
|
84 |
+
blockquote:after {
|
85 |
+
color : #bbb;
|
86 |
+
content : "\201D";
|
87 |
+
font-size : 3em;
|
88 |
+
line-height : 0.1em;
|
89 |
+
vertical-align : -.45em;
|
90 |
+
}
|
91 |
+
|
92 |
+
blockquote > p:first-child {
|
93 |
+
display : inline;
|
94 |
+
}
|
95 |
+
|
96 |
+
table {
|
97 |
+
font-family : "Helvetica Neue", Helvetica, Arial, sans-serif;
|
98 |
+
border : 0;
|
99 |
+
border-spacing : 0;
|
100 |
+
font-size : 0.857em;
|
101 |
+
margin : 10px 0;
|
102 |
+
width : 100%;
|
103 |
+
}
|
104 |
+
|
105 |
+
table table {
|
106 |
+
font-size : 1em;
|
107 |
+
}
|
108 |
+
|
109 |
+
table tr th {
|
110 |
+
background : #757575;
|
111 |
+
background : rgba(0, 0, 0, 0.51);
|
112 |
+
border-bottom-style : none;
|
113 |
+
}
|
114 |
+
|
115 |
+
table tr th,
|
116 |
+
table tr th a,
|
117 |
+
table tr th a:hover {
|
118 |
+
color : #FFF;
|
119 |
+
font-weight : bold;
|
120 |
+
}
|
121 |
+
|
122 |
+
table tbody tr th {
|
123 |
+
vertical-align : top;
|
124 |
+
}
|
125 |
+
|
126 |
+
tr td,
|
127 |
+
tr th {
|
128 |
+
padding : 4px 9px;
|
129 |
+
border : 1px solid #fff;
|
130 |
+
text-align : left; /* LTR */
|
131 |
+
}
|
132 |
+
|
133 |
+
tr:nth-child(odd) {
|
134 |
+
background : #e4e4e4;
|
135 |
+
background : rgba(0, 0, 0, 0.105);
|
136 |
+
}
|
137 |
+
|
138 |
+
tr,
|
139 |
+
tr:nth-child(even) {
|
140 |
+
background : #efefef;
|
141 |
+
background : rgba(0, 0, 0, 0.063);
|
142 |
+
}
|
143 |
+
|
144 |
+
a {
|
145 |
+
color : #0071B3;
|
146 |
+
}
|
147 |
+
|
148 |
+
a:hover,
|
149 |
+
a:focus {
|
150 |
+
color : #018fe2;
|
151 |
+
}
|
152 |
+
|
153 |
+
a:active {
|
154 |
+
color : #23aeff;
|
155 |
+
}
|
156 |
+
|
157 |
+
a:link,
|
158 |
+
a:visited {
|
159 |
+
text-decoration : none;
|
160 |
+
}
|
161 |
+
|
162 |
+
a:hover,
|
163 |
+
a:active,
|
164 |
+
a:focus {
|
165 |
+
text-decoration : underline;
|
166 |
+
}
|
167 |
+
|
skin/adminhtml/default/default/epiceditor/themes/preview/github.css
ADDED
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html { padding:0 10px; }
|
2 |
+
|
3 |
+
body {
|
4 |
+
margin:0;
|
5 |
+
padding:0;
|
6 |
+
background:#fff;
|
7 |
+
}
|
8 |
+
|
9 |
+
#epiceditor-wrapper{
|
10 |
+
background:white;
|
11 |
+
}
|
12 |
+
|
13 |
+
#epiceditor-preview{
|
14 |
+
padding-top:10px;
|
15 |
+
padding-bottom:10px;
|
16 |
+
font-family: Helvetica,arial,freesans,clean,sans-serif;
|
17 |
+
font-size:13px;
|
18 |
+
line-height:1.6;
|
19 |
+
}
|
20 |
+
|
21 |
+
#epiceditor-preview>*:first-child{
|
22 |
+
margin-top:0!important;
|
23 |
+
}
|
24 |
+
|
25 |
+
#epiceditor-preview>*:last-child{
|
26 |
+
margin-bottom:0!important;
|
27 |
+
}
|
28 |
+
|
29 |
+
#epiceditor-preview a{
|
30 |
+
color:#4183C4;
|
31 |
+
text-decoration:none;
|
32 |
+
}
|
33 |
+
|
34 |
+
#epiceditor-preview a:hover{
|
35 |
+
text-decoration:underline;
|
36 |
+
}
|
37 |
+
|
38 |
+
#epiceditor-preview h1,
|
39 |
+
#epiceditor-preview h2,
|
40 |
+
#epiceditor-preview h3,
|
41 |
+
#epiceditor-preview h4,
|
42 |
+
#epiceditor-preview h5,
|
43 |
+
#epiceditor-preview h6{
|
44 |
+
margin:20px 0 10px;
|
45 |
+
padding:0;
|
46 |
+
font-weight:bold;
|
47 |
+
-webkit-font-smoothing:antialiased;
|
48 |
+
}
|
49 |
+
|
50 |
+
#epiceditor-preview h1 tt,
|
51 |
+
#epiceditor-preview h1 code,
|
52 |
+
#epiceditor-preview h2 tt,
|
53 |
+
#epiceditor-preview h2 code,
|
54 |
+
#epiceditor-preview h3 tt,
|
55 |
+
#epiceditor-preview h3 code,
|
56 |
+
#epiceditor-preview h4 tt,
|
57 |
+
#epiceditor-preview h4 code,
|
58 |
+
#epiceditor-preview h5 tt,
|
59 |
+
#epiceditor-preview h5 code,
|
60 |
+
#epiceditor-preview h6 tt,
|
61 |
+
#epiceditor-preview h6 code{
|
62 |
+
font-size:inherit;
|
63 |
+
}
|
64 |
+
|
65 |
+
#epiceditor-preview h1{
|
66 |
+
font-size:28px;
|
67 |
+
color:#000;
|
68 |
+
}
|
69 |
+
|
70 |
+
#epiceditor-preview h2{
|
71 |
+
font-size:24px;
|
72 |
+
border-bottom:1px solid #ccc;
|
73 |
+
color:#000;
|
74 |
+
}
|
75 |
+
|
76 |
+
#epiceditor-preview h3{
|
77 |
+
font-size:18px;
|
78 |
+
}
|
79 |
+
|
80 |
+
#epiceditor-preview h4{
|
81 |
+
font-size:16px;
|
82 |
+
}
|
83 |
+
|
84 |
+
#epiceditor-preview h5{
|
85 |
+
font-size:14px;
|
86 |
+
}
|
87 |
+
|
88 |
+
#epiceditor-preview h6{
|
89 |
+
color:#777;
|
90 |
+
font-size:14px;
|
91 |
+
}
|
92 |
+
|
93 |
+
#epiceditor-preview p,
|
94 |
+
#epiceditor-preview blockquote,
|
95 |
+
#epiceditor-preview ul,
|
96 |
+
#epiceditor-preview ol,
|
97 |
+
#epiceditor-preview dl,
|
98 |
+
#epiceditor-preview li,
|
99 |
+
#epiceditor-preview table,
|
100 |
+
#epiceditor-preview pre{
|
101 |
+
margin:15px 0;
|
102 |
+
}
|
103 |
+
|
104 |
+
#epiceditor-preview hr{
|
105 |
+
background:transparent url('../../images/modules/pulls/dirty-shade.png') repeat-x 0 0;
|
106 |
+
border:0 none;
|
107 |
+
color:#ccc;
|
108 |
+
height:4px;
|
109 |
+
padding:0;
|
110 |
+
}
|
111 |
+
|
112 |
+
#epiceditor-preview>h2:first-child,
|
113 |
+
#epiceditor-preview>h1:first-child,
|
114 |
+
#epiceditor-preview>h1:first-child+h2,
|
115 |
+
#epiceditor-preview>h3:first-child,
|
116 |
+
#epiceditor-preview>h4:first-child,
|
117 |
+
#epiceditor-preview>h5:first-child,
|
118 |
+
#epiceditor-preview>h6:first-child{
|
119 |
+
margin-top:0;
|
120 |
+
padding-top:0;
|
121 |
+
}
|
122 |
+
|
123 |
+
#epiceditor-preview h1+p,
|
124 |
+
#epiceditor-preview h2+p,
|
125 |
+
#epiceditor-preview h3+p,
|
126 |
+
#epiceditor-preview h4+p,
|
127 |
+
#epiceditor-preview h5+p,
|
128 |
+
#epiceditor-preview h6+p{
|
129 |
+
margin-top:0;
|
130 |
+
}
|
131 |
+
|
132 |
+
#epiceditor-preview li p.first{
|
133 |
+
display:inline-block;
|
134 |
+
}
|
135 |
+
|
136 |
+
#epiceditor-preview ul,
|
137 |
+
#epiceditor-preview ol{
|
138 |
+
padding-left:30px;
|
139 |
+
}
|
140 |
+
|
141 |
+
#epiceditor-preview ul li>:first-child,
|
142 |
+
#epiceditor-preview ol li>:first-child{
|
143 |
+
margin-top:0;
|
144 |
+
}
|
145 |
+
|
146 |
+
#epiceditor-preview ul li>:last-child,
|
147 |
+
#epiceditor-preview ol li>:last-child{
|
148 |
+
margin-bottom:0;
|
149 |
+
}
|
150 |
+
|
151 |
+
#epiceditor-preview dl{
|
152 |
+
padding:0;
|
153 |
+
}
|
154 |
+
|
155 |
+
#epiceditor-preview dl dt{
|
156 |
+
font-size:14px;
|
157 |
+
font-weight:bold;
|
158 |
+
font-style:italic;
|
159 |
+
padding:0;
|
160 |
+
margin:15px 0 5px;
|
161 |
+
}
|
162 |
+
|
163 |
+
#epiceditor-preview dl dt:first-child{
|
164 |
+
padding:0;
|
165 |
+
}
|
166 |
+
|
167 |
+
#epiceditor-preview dl dt>:first-child{
|
168 |
+
margin-top:0;
|
169 |
+
}
|
170 |
+
|
171 |
+
#epiceditor-preview dl dt>:last-child{
|
172 |
+
margin-bottom:0;
|
173 |
+
}
|
174 |
+
|
175 |
+
#epiceditor-preview dl dd{
|
176 |
+
margin:0 0 15px;
|
177 |
+
padding:0 15px;
|
178 |
+
}
|
179 |
+
|
180 |
+
#epiceditor-preview dl dd>:first-child{
|
181 |
+
margin-top:0;
|
182 |
+
}
|
183 |
+
|
184 |
+
#epiceditor-preview dl dd>:last-child{
|
185 |
+
margin-bottom:0;
|
186 |
+
}
|
187 |
+
|
188 |
+
#epiceditor-preview blockquote{
|
189 |
+
border-left:4px solid #DDD;
|
190 |
+
padding:0 15px;
|
191 |
+
color:#777;
|
192 |
+
}
|
193 |
+
|
194 |
+
#epiceditor-preview blockquote>:first-child{
|
195 |
+
margin-top:0;
|
196 |
+
}
|
197 |
+
|
198 |
+
#epiceditor-preview blockquote>:last-child{
|
199 |
+
margin-bottom:0;
|
200 |
+
}
|
201 |
+
|
202 |
+
#epiceditor-preview table{
|
203 |
+
padding:0;
|
204 |
+
border-collapse: collapse;
|
205 |
+
border-spacing: 0;
|
206 |
+
font-size: 100%;
|
207 |
+
font: inherit;
|
208 |
+
}
|
209 |
+
|
210 |
+
#epiceditor-preview table tr{
|
211 |
+
border-top:1px solid #ccc;
|
212 |
+
background-color:#fff;
|
213 |
+
margin:0;
|
214 |
+
padding:0;
|
215 |
+
}
|
216 |
+
|
217 |
+
#epiceditor-preview table tr:nth-child(2n){
|
218 |
+
background-color:#f8f8f8;
|
219 |
+
}
|
220 |
+
|
221 |
+
#epiceditor-preview table tr th{
|
222 |
+
font-weight:bold;
|
223 |
+
}
|
224 |
+
|
225 |
+
#epiceditor-preview table tr th,
|
226 |
+
#epiceditor-preview table tr td{
|
227 |
+
border:1px solid #ccc;
|
228 |
+
text-align:left;
|
229 |
+
margin:0;
|
230 |
+
padding:6px 13px;
|
231 |
+
}
|
232 |
+
|
233 |
+
#epiceditor-preview table tr th>:first-child,
|
234 |
+
#epiceditor-preview table tr td>:first-child{
|
235 |
+
margin-top:0;
|
236 |
+
}
|
237 |
+
|
238 |
+
#epiceditor-preview table tr th>:last-child,
|
239 |
+
#epiceditor-preview table tr td>:last-child{
|
240 |
+
margin-bottom:0;
|
241 |
+
}
|
242 |
+
|
243 |
+
#epiceditor-preview img{
|
244 |
+
max-width:100%;
|
245 |
+
}
|
246 |
+
|
247 |
+
#epiceditor-preview span.frame{
|
248 |
+
display:block;
|
249 |
+
overflow:hidden;
|
250 |
+
}
|
251 |
+
|
252 |
+
#epiceditor-preview span.frame>span{
|
253 |
+
border:1px solid #ddd;
|
254 |
+
display:block;
|
255 |
+
float:left;
|
256 |
+
overflow:hidden;
|
257 |
+
margin:13px 0 0;
|
258 |
+
padding:7px;
|
259 |
+
width:auto;
|
260 |
+
}
|
261 |
+
|
262 |
+
#epiceditor-preview span.frame span img{
|
263 |
+
display:block;
|
264 |
+
float:left;
|
265 |
+
}
|
266 |
+
|
267 |
+
#epiceditor-preview span.frame span span{
|
268 |
+
clear:both;
|
269 |
+
color:#333;
|
270 |
+
display:block;
|
271 |
+
padding:5px 0 0;
|
272 |
+
}
|
273 |
+
|
274 |
+
#epiceditor-preview span.align-center{
|
275 |
+
display:block;
|
276 |
+
overflow:hidden;
|
277 |
+
clear:both;
|
278 |
+
}
|
279 |
+
|
280 |
+
#epiceditor-preview span.align-center>span{
|
281 |
+
display:block;
|
282 |
+
overflow:hidden;
|
283 |
+
margin:13px auto 0;
|
284 |
+
text-align:center;
|
285 |
+
}
|
286 |
+
|
287 |
+
#epiceditor-preview span.align-center span img{
|
288 |
+
margin:0 auto;
|
289 |
+
text-align:center;
|
290 |
+
}
|
291 |
+
|
292 |
+
#epiceditor-preview span.align-right{
|
293 |
+
display:block;
|
294 |
+
overflow:hidden;
|
295 |
+
clear:both;
|
296 |
+
}
|
297 |
+
|
298 |
+
#epiceditor-preview span.align-right>span{
|
299 |
+
display:block;
|
300 |
+
overflow:hidden;
|
301 |
+
margin:13px 0 0;
|
302 |
+
text-align:right;
|
303 |
+
}
|
304 |
+
|
305 |
+
#epiceditor-preview span.align-right span img{
|
306 |
+
margin:0;
|
307 |
+
text-align:right;
|
308 |
+
}
|
309 |
+
|
310 |
+
#epiceditor-preview span.float-left{
|
311 |
+
display:block;
|
312 |
+
margin-right:13px;
|
313 |
+
overflow:hidden;
|
314 |
+
float:left;
|
315 |
+
}
|
316 |
+
|
317 |
+
#epiceditor-preview span.float-left span{
|
318 |
+
margin:13px 0 0;
|
319 |
+
}
|
320 |
+
|
321 |
+
#epiceditor-preview span.float-right{
|
322 |
+
display:block;
|
323 |
+
margin-left:13px;
|
324 |
+
overflow:hidden;
|
325 |
+
float:right;
|
326 |
+
}
|
327 |
+
|
328 |
+
#epiceditor-preview span.float-right>span{
|
329 |
+
display:block;
|
330 |
+
overflow:hidden;
|
331 |
+
margin:13px auto 0;
|
332 |
+
text-align:right;
|
333 |
+
}
|
334 |
+
|
335 |
+
#epiceditor-preview code,
|
336 |
+
#epiceditor-preview tt{
|
337 |
+
margin:0 2px;
|
338 |
+
padding:0 5px;
|
339 |
+
white-space:nowrap;
|
340 |
+
border:1px solid #eaeaea;
|
341 |
+
background-color:#f8f8f8;
|
342 |
+
border-radius:3px;
|
343 |
+
}
|
344 |
+
|
345 |
+
#epiceditor-preview pre>code{
|
346 |
+
margin:0;
|
347 |
+
padding:0;
|
348 |
+
white-space:pre;
|
349 |
+
border:none;
|
350 |
+
background:transparent;
|
351 |
+
}
|
352 |
+
|
353 |
+
#epiceditor-preview .highlight pre,
|
354 |
+
#epiceditor-preview pre{
|
355 |
+
background-color:#f8f8f8;
|
356 |
+
border:1px solid #ccc;
|
357 |
+
font-size:13px;
|
358 |
+
line-height:19px;
|
359 |
+
overflow:auto;
|
360 |
+
padding:6px 10px;
|
361 |
+
border-radius:3px;
|
362 |
+
}
|
363 |
+
|
364 |
+
#epiceditor-preview pre code,
|
365 |
+
#epiceditor-preview pre tt{
|
366 |
+
background-color:transparent;
|
367 |
+
border:none;
|
368 |
+
}
|
skin/adminhtml/default/default/epiceditor/themes/preview/githubNxcode.css
ADDED
@@ -0,0 +1,533 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html {
|
2 |
+
padding : 0 10px;
|
3 |
+
}
|
4 |
+
|
5 |
+
body {
|
6 |
+
margin : 0;
|
7 |
+
padding : 0;
|
8 |
+
background : #fff;
|
9 |
+
}
|
10 |
+
|
11 |
+
#epiceditor-wrapper {
|
12 |
+
background : white;
|
13 |
+
}
|
14 |
+
|
15 |
+
#epiceditor-preview {
|
16 |
+
padding-top : 10px;
|
17 |
+
padding-bottom : 10px;
|
18 |
+
font-family : Helvetica, arial, freesans, clean, sans-serif;
|
19 |
+
font-size : 13px;
|
20 |
+
line-height : 1.6;
|
21 |
+
}
|
22 |
+
|
23 |
+
#epiceditor-preview>*:first-child {
|
24 |
+
margin-top : 0 !important;
|
25 |
+
}
|
26 |
+
|
27 |
+
#epiceditor-preview>*:last-child {
|
28 |
+
margin-bottom : 0 !important;
|
29 |
+
}
|
30 |
+
|
31 |
+
#epiceditor-preview a {
|
32 |
+
color : #4183C4;
|
33 |
+
text-decoration : none;
|
34 |
+
}
|
35 |
+
|
36 |
+
#epiceditor-preview a:hover {
|
37 |
+
text-decoration : underline;
|
38 |
+
}
|
39 |
+
|
40 |
+
#epiceditor-preview h1,
|
41 |
+
#epiceditor-preview h2,
|
42 |
+
#epiceditor-preview h3,
|
43 |
+
#epiceditor-preview h4,
|
44 |
+
#epiceditor-preview h5,
|
45 |
+
#epiceditor-preview h6 {
|
46 |
+
margin : 20px 0 10px;
|
47 |
+
padding : 0;
|
48 |
+
font-weight : bold;
|
49 |
+
-webkit-font-smoothing : antialiased;
|
50 |
+
}
|
51 |
+
|
52 |
+
#epiceditor-preview h1 tt,
|
53 |
+
#epiceditor-preview h1 code,
|
54 |
+
#epiceditor-preview h2 tt,
|
55 |
+
#epiceditor-preview h2 code,
|
56 |
+
#epiceditor-preview h3 tt,
|
57 |
+
#epiceditor-preview h3 code,
|
58 |
+
#epiceditor-preview h4 tt,
|
59 |
+
#epiceditor-preview h4 code,
|
60 |
+
#epiceditor-preview h5 tt,
|
61 |
+
#epiceditor-preview h5 code,
|
62 |
+
#epiceditor-preview h6 tt,
|
63 |
+
#epiceditor-preview h6 code {
|
64 |
+
font-size : inherit;
|
65 |
+
}
|
66 |
+
|
67 |
+
#epiceditor-preview h1 {
|
68 |
+
font-size : 28px;
|
69 |
+
color : #000;
|
70 |
+
}
|
71 |
+
|
72 |
+
#epiceditor-preview h2 {
|
73 |
+
font-size : 24px;
|
74 |
+
border-bottom : 1px solid #ccc;
|
75 |
+
color : #000;
|
76 |
+
}
|
77 |
+
|
78 |
+
#epiceditor-preview h3 {
|
79 |
+
font-size : 18px;
|
80 |
+
}
|
81 |
+
|
82 |
+
#epiceditor-preview h4 {
|
83 |
+
font-size : 16px;
|
84 |
+
}
|
85 |
+
|
86 |
+
#epiceditor-preview h5 {
|
87 |
+
font-size : 14px;
|
88 |
+
}
|
89 |
+
|
90 |
+
#epiceditor-preview h6 {
|
91 |
+
color : #777;
|
92 |
+
font-size : 14px;
|
93 |
+
}
|
94 |
+
|
95 |
+
#epiceditor-preview p,
|
96 |
+
#epiceditor-preview blockquote,
|
97 |
+
#epiceditor-preview ul,
|
98 |
+
#epiceditor-preview ol,
|
99 |
+
#epiceditor-preview dl,
|
100 |
+
#epiceditor-preview li,
|
101 |
+
#epiceditor-preview table,
|
102 |
+
#epiceditor-preview pre {
|
103 |
+
margin : 15px 0;
|
104 |
+
}
|
105 |
+
|
106 |
+
#epiceditor-preview hr {
|
107 |
+
background : transparent url('../../images/modules/pulls/dirty-shade.png') repeat-x 0 0;
|
108 |
+
border : 0 none;
|
109 |
+
color : #ccc;
|
110 |
+
height : 4px;
|
111 |
+
padding : 0;
|
112 |
+
}
|
113 |
+
|
114 |
+
#epiceditor-preview>h2:first-child,
|
115 |
+
#epiceditor-preview>h1:first-child,
|
116 |
+
#epiceditor-preview>h1:first-child+h2,
|
117 |
+
#epiceditor-preview>h3:first-child,
|
118 |
+
#epiceditor-preview>h4:first-child,
|
119 |
+
#epiceditor-preview>h5:first-child,
|
120 |
+
#epiceditor-preview>h6:first-child {
|
121 |
+
margin-top : 0;
|
122 |
+
padding-top : 0;
|
123 |
+
}
|
124 |
+
|
125 |
+
#epiceditor-preview h1+p,
|
126 |
+
#epiceditor-preview h2+p,
|
127 |
+
#epiceditor-preview h3+p,
|
128 |
+
#epiceditor-preview h4+p,
|
129 |
+
#epiceditor-preview h5+p,
|
130 |
+
#epiceditor-preview h6+p {
|
131 |
+
margin-top : 0;
|
132 |
+
}
|
133 |
+
|
134 |
+
#epiceditor-preview li p.first {
|
135 |
+
display : inline-block;
|
136 |
+
}
|
137 |
+
|
138 |
+
#epiceditor-preview ul,
|
139 |
+
#epiceditor-preview ol {
|
140 |
+
padding-left : 30px;
|
141 |
+
}
|
142 |
+
|
143 |
+
#epiceditor-preview ul li>:first-child,
|
144 |
+
#epiceditor-preview ol li>:first-child {
|
145 |
+
margin-top : 0;
|
146 |
+
}
|
147 |
+
|
148 |
+
#epiceditor-preview ul li>:last-child,
|
149 |
+
#epiceditor-preview ol li>:last-child {
|
150 |
+
margin-bottom : 0;
|
151 |
+
}
|
152 |
+
|
153 |
+
#epiceditor-preview dl {
|
154 |
+
padding : 0;
|
155 |
+
}
|
156 |
+
|
157 |
+
#epiceditor-preview dl dt {
|
158 |
+
font-size : 14px;
|
159 |
+
font-weight : bold;
|
160 |
+
font-style : italic;
|
161 |
+
padding : 0;
|
162 |
+
margin : 15px 0 5px;
|
163 |
+
}
|
164 |
+
|
165 |
+
#epiceditor-preview dl dt:first-child {
|
166 |
+
padding : 0;
|
167 |
+
}
|
168 |
+
|
169 |
+
#epiceditor-preview dl dt>:first-child {
|
170 |
+
margin-top : 0;
|
171 |
+
}
|
172 |
+
|
173 |
+
#epiceditor-preview dl dt>:last-child {
|
174 |
+
margin-bottom : 0;
|
175 |
+
}
|
176 |
+
|
177 |
+
#epiceditor-preview dl dd {
|
178 |
+
margin : 0 0 15px;
|
179 |
+
padding : 0 15px;
|
180 |
+
}
|
181 |
+
|
182 |
+
#epiceditor-preview dl dd>:first-child {
|
183 |
+
margin-top : 0;
|
184 |
+
}
|
185 |
+
|
186 |
+
#epiceditor-preview dl dd>:last-child {
|
187 |
+
margin-bottom : 0;
|
188 |
+
}
|
189 |
+
|
190 |
+
#epiceditor-preview blockquote {
|
191 |
+
border-left : 4px solid #DDD;
|
192 |
+
padding : 0 15px;
|
193 |
+
color : #777;
|
194 |
+
}
|
195 |
+
|
196 |
+
#epiceditor-preview blockquote>:first-child {
|
197 |
+
margin-top : 0;
|
198 |
+
}
|
199 |
+
|
200 |
+
#epiceditor-preview blockquote>:last-child {
|
201 |
+
margin-bottom : 0;
|
202 |
+
}
|
203 |
+
|
204 |
+
#epiceditor-preview table {
|
205 |
+
padding : 0;
|
206 |
+
border-collapse : collapse;
|
207 |
+
border-spacing : 0;
|
208 |
+
font-size : 100%;
|
209 |
+
font : inherit;
|
210 |
+
}
|
211 |
+
|
212 |
+
#epiceditor-preview table tr {
|
213 |
+
border-top : 1px solid #ccc;
|
214 |
+
background-color : #fff;
|
215 |
+
margin : 0;
|
216 |
+
padding : 0;
|
217 |
+
}
|
218 |
+
|
219 |
+
#epiceditor-preview table tr:nth-child(2n) {
|
220 |
+
background-color : #f8f8f8;
|
221 |
+
}
|
222 |
+
|
223 |
+
#epiceditor-preview table tr th {
|
224 |
+
font-weight : bold;
|
225 |
+
}
|
226 |
+
|
227 |
+
#epiceditor-preview table tr th,
|
228 |
+
#epiceditor-preview table tr td {
|
229 |
+
border : 1px solid #ccc;
|
230 |
+
text-align : left;
|
231 |
+
margin : 0;
|
232 |
+
padding : 6px 13px;
|
233 |
+
}
|
234 |
+
|
235 |
+
#epiceditor-preview table tr th>:first-child,
|
236 |
+
#epiceditor-preview table tr td>:first-child {
|
237 |
+
margin-top : 0;
|
238 |
+
}
|
239 |
+
|
240 |
+
#epiceditor-preview table tr th>:last-child,
|
241 |
+
#epiceditor-preview table tr td>:last-child {
|
242 |
+
margin-bottom : 0;
|
243 |
+
}
|
244 |
+
|
245 |
+
#epiceditor-preview img {
|
246 |
+
max-width : 100%;
|
247 |
+
}
|
248 |
+
|
249 |
+
#epiceditor-preview span.frame {
|
250 |
+
display : block;
|
251 |
+
overflow : hidden;
|
252 |
+
}
|
253 |
+
|
254 |
+
#epiceditor-preview span.frame>span {
|
255 |
+
border : 1px solid #ddd;
|
256 |
+
display : block;
|
257 |
+
float : left;
|
258 |
+
overflow : hidden;
|
259 |
+
margin : 13px 0 0;
|
260 |
+
padding : 7px;
|
261 |
+
width : auto;
|
262 |
+
}
|
263 |
+
|
264 |
+
#epiceditor-preview span.frame span img {
|
265 |
+
display : block;
|
266 |
+
float : left;
|
267 |
+
}
|
268 |
+
|
269 |
+
#epiceditor-preview span.frame span span {
|
270 |
+
clear : both;
|
271 |
+
color : #333;
|
272 |
+
display : block;
|
273 |
+
padding : 5px 0 0;
|
274 |
+
}
|
275 |
+
|
276 |
+
#epiceditor-preview span.align-center {
|
277 |
+
display : block;
|
278 |
+
overflow : hidden;
|
279 |
+
clear : both;
|
280 |
+
}
|
281 |
+
|
282 |
+
#epiceditor-preview span.align-center>span {
|
283 |
+
display : block;
|
284 |
+
overflow : hidden;
|
285 |
+
margin : 13px auto 0;
|
286 |
+
text-align : center;
|
287 |
+
}
|
288 |
+
|
289 |
+
#epiceditor-preview span.align-center span img {
|
290 |
+
margin : 0 auto;
|
291 |
+
text-align : center;
|
292 |
+
}
|
293 |
+
|
294 |
+
#epiceditor-preview span.align-right {
|
295 |
+
display : block;
|
296 |
+
overflow : hidden;
|
297 |
+
clear : both;
|
298 |
+
}
|
299 |
+
|
300 |
+
#epiceditor-preview span.align-right>span {
|
301 |
+
display : block;
|
302 |
+
overflow : hidden;
|
303 |
+
margin : 13px 0 0;
|
304 |
+
text-align : right;
|
305 |
+
}
|
306 |
+
|
307 |
+
#epiceditor-preview span.align-right span img {
|
308 |
+
margin : 0;
|
309 |
+
text-align : right;
|
310 |
+
}
|
311 |
+
|
312 |
+
#epiceditor-preview span.float-left {
|
313 |
+
display : block;
|
314 |
+
margin-right : 13px;
|
315 |
+
overflow : hidden;
|
316 |
+
float : left;
|
317 |
+
}
|
318 |
+
|
319 |
+
#epiceditor-preview span.float-left span {
|
320 |
+
margin : 13px 0 0;
|
321 |
+
}
|
322 |
+
|
323 |
+
#epiceditor-preview span.float-right {
|
324 |
+
display : block;
|
325 |
+
margin-left : 13px;
|
326 |
+
overflow : hidden;
|
327 |
+
float : right;
|
328 |
+
}
|
329 |
+
|
330 |
+
#epiceditor-preview span.float-right>span {
|
331 |
+
display : block;
|
332 |
+
overflow : hidden;
|
333 |
+
margin : 13px auto 0;
|
334 |
+
text-align : right;
|
335 |
+
}
|
336 |
+
|
337 |
+
#epiceditor-preview code,
|
338 |
+
#epiceditor-preview tt {
|
339 |
+
margin : 0 2px;
|
340 |
+
padding : 0 5px;
|
341 |
+
white-space : nowrap;
|
342 |
+
border : 1px solid #eaeaea;
|
343 |
+
background-color : #f8f8f8;
|
344 |
+
border-radius : 3px;
|
345 |
+
}
|
346 |
+
|
347 |
+
#epiceditor-preview pre>code {
|
348 |
+
margin : 0;
|
349 |
+
padding : 0;
|
350 |
+
white-space : pre;
|
351 |
+
border : none;
|
352 |
+
background : transparent;
|
353 |
+
}
|
354 |
+
|
355 |
+
#epiceditor-preview .highlight pre,
|
356 |
+
#epiceditor-preview pre {
|
357 |
+
background-color : #f8f8f8;
|
358 |
+
border : 1px solid #ccc;
|
359 |
+
font-size : 13px;
|
360 |
+
line-height : 19px;
|
361 |
+
overflow : auto;
|
362 |
+
padding : 6px 10px;
|
363 |
+
border-radius : 3px;
|
364 |
+
}
|
365 |
+
|
366 |
+
#epiceditor-preview pre code,
|
367 |
+
#epiceditor-preview pre tt {
|
368 |
+
background-color : transparent;
|
369 |
+
border : none;
|
370 |
+
}
|
371 |
+
|
372 |
+
/*custom*/
|
373 |
+
pre.hljs {
|
374 |
+
background-color : #fff !important;
|
375 |
+
}
|
376 |
+
|
377 |
+
/*
|
378 |
+
highlight.js
|
379 |
+
XCode style (c) Angel Garcia <angelgarcia.mail@gmail.com>
|
380 |
+
*/
|
381 |
+
pre.hljs code {
|
382 |
+
display : block;
|
383 |
+
padding : 0.5em;
|
384 |
+
background : #fff;
|
385 |
+
color : black;
|
386 |
+
}
|
387 |
+
|
388 |
+
pre.hljs .comment,
|
389 |
+
pre.hljs .template_comment,
|
390 |
+
pre.hljs .javadoc,
|
391 |
+
pre.hljs .comment * {
|
392 |
+
color : rgb(0, 106, 0);
|
393 |
+
}
|
394 |
+
|
395 |
+
pre.hljs .keyword,
|
396 |
+
pre.hljs .literal,
|
397 |
+
pre.hljs .nginx .title {
|
398 |
+
color : rgb(170, 13, 145);
|
399 |
+
}
|
400 |
+
|
401 |
+
pre.hljs .method,
|
402 |
+
pre.hljs .list .title,
|
403 |
+
pre.hljs .tag .title,
|
404 |
+
pre.hljs .setting .value,
|
405 |
+
pre.hljs .winutils,
|
406 |
+
pre.hljs .tex .command,
|
407 |
+
pre.hljs .http .title,
|
408 |
+
pre.hljs .request,
|
409 |
+
pre.hljs .status {
|
410 |
+
color : #008;
|
411 |
+
}
|
412 |
+
|
413 |
+
pre.hljs .envvar,
|
414 |
+
pre.hljs .tex .special {
|
415 |
+
color : #660;
|
416 |
+
}
|
417 |
+
|
418 |
+
pre.hljs .string {
|
419 |
+
color : rgb(196, 26, 22);
|
420 |
+
}
|
421 |
+
|
422 |
+
pre.hljs .tag .value,
|
423 |
+
pre.hljs .cdata,
|
424 |
+
pre.hljs .filter .argument,
|
425 |
+
pre.hljs .attr_selector,
|
426 |
+
pre.hljs .apache .cbracket,
|
427 |
+
pre.hljs .date,
|
428 |
+
pre.hljs .regexp {
|
429 |
+
color : #080;
|
430 |
+
}
|
431 |
+
|
432 |
+
pre.hljs .sub .identifier,
|
433 |
+
pre.hljs .pi,
|
434 |
+
pre.hljs .tag,
|
435 |
+
pre.hljs .tag .keyword,
|
436 |
+
pre.hljs .decorator,
|
437 |
+
pre.hljs .ini .title,
|
438 |
+
pre.hljs .shebang,
|
439 |
+
pre.hljs .prompt,
|
440 |
+
pre.hljs .hexcolor,
|
441 |
+
pre.hljs .rules .value,
|
442 |
+
pre.hljs .css .value .number,
|
443 |
+
pre.hljs .symbol,
|
444 |
+
pre.hljs .symbol .string,
|
445 |
+
pre.hljs .number,
|
446 |
+
pre.hljs .css .function,
|
447 |
+
pre.hljs .clojure .title,
|
448 |
+
pre.hljs .clojure .built_in {
|
449 |
+
color : rgb(28, 0, 207);
|
450 |
+
}
|
451 |
+
|
452 |
+
pre.hljs .class .title,
|
453 |
+
pre.hljs .haskell .type,
|
454 |
+
pre.hljs .smalltalk .class,
|
455 |
+
pre.hljs .javadoctag,
|
456 |
+
pre.hljs .yardoctag,
|
457 |
+
pre.hljs .phpdoc,
|
458 |
+
pre.hljs .typename,
|
459 |
+
pre.hljs .tag .attribute,
|
460 |
+
pre.hljs .doctype,
|
461 |
+
pre.hljs .class .id,
|
462 |
+
pre.hljs .built_in,
|
463 |
+
pre.hljs .setting,
|
464 |
+
pre.hljs .params,
|
465 |
+
pre.hljs .clojure .attribute {
|
466 |
+
color : rgb(92, 38, 153);
|
467 |
+
}
|
468 |
+
|
469 |
+
pre.hljs .variable {
|
470 |
+
color : rgb(63, 110, 116);
|
471 |
+
}
|
472 |
+
|
473 |
+
pre.hljs .css .tag,
|
474 |
+
pre.hljs .rules .property,
|
475 |
+
pre.hljs .pseudo,
|
476 |
+
pre.hljs .subst {
|
477 |
+
color : #000;
|
478 |
+
}
|
479 |
+
|
480 |
+
pre.hljs .css .class, pre.hljs .css .id {
|
481 |
+
color : #9B703F;
|
482 |
+
}
|
483 |
+
|
484 |
+
pre.hljs .value .important {
|
485 |
+
color : #ff7700;
|
486 |
+
font-weight : bold;
|
487 |
+
}
|
488 |
+
|
489 |
+
pre.hljs .rules .keyword {
|
490 |
+
color : #C5AF75;
|
491 |
+
}
|
492 |
+
|
493 |
+
pre.hljs .annotation,
|
494 |
+
pre.hljs .apache .sqbracket,
|
495 |
+
pre.hljs .nginx .built_in {
|
496 |
+
color : #9B859D;
|
497 |
+
}
|
498 |
+
|
499 |
+
pre.hljs .preprocessor,
|
500 |
+
pre.hljs .preprocessor * {
|
501 |
+
color : rgb(100, 56, 32);
|
502 |
+
}
|
503 |
+
|
504 |
+
pre.hljs .tex .formula {
|
505 |
+
background-color : #EEE;
|
506 |
+
font-style : italic;
|
507 |
+
}
|
508 |
+
|
509 |
+
pre.hljs .diff .header,
|
510 |
+
pre.hljs .chunk {
|
511 |
+
color : #808080;
|
512 |
+
font-weight : bold;
|
513 |
+
}
|
514 |
+
|
515 |
+
pre.hljs .diff .change {
|
516 |
+
background-color : #BCCFF9;
|
517 |
+
}
|
518 |
+
|
519 |
+
pre.hljs .addition {
|
520 |
+
background-color : #BAEEBA;
|
521 |
+
}
|
522 |
+
|
523 |
+
pre.hljs .deletion {
|
524 |
+
background-color : #FFC8BD;
|
525 |
+
}
|
526 |
+
|
527 |
+
pre.hljs .comment .yardoctag {
|
528 |
+
font-weight : bold;
|
529 |
+
}
|
530 |
+
|
531 |
+
pre.hljs .method .id {
|
532 |
+
color : #000;
|
533 |
+
}
|
skin/adminhtml/default/default/epiceditor/themes/preview/preview-dark.css
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html {
|
2 |
+
padding : 0 10px;
|
3 |
+
}
|
4 |
+
|
5 |
+
body {
|
6 |
+
margin : 0;
|
7 |
+
padding : 10px 0;
|
8 |
+
background : #000;
|
9 |
+
}
|
10 |
+
|
11 |
+
#epiceditor-preview h1,
|
12 |
+
#epiceditor-preview h2,
|
13 |
+
#epiceditor-preview h3,
|
14 |
+
#epiceditor-preview h4,
|
15 |
+
#epiceditor-preview h5,
|
16 |
+
#epiceditor-preview h6,
|
17 |
+
#epiceditor-preview p,
|
18 |
+
#epiceditor-preview blockquote {
|
19 |
+
margin : 0;
|
20 |
+
padding : 0;
|
21 |
+
}
|
22 |
+
|
23 |
+
#epiceditor-preview {
|
24 |
+
background : #000;
|
25 |
+
font-family : "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif;
|
26 |
+
font-size : 13px;
|
27 |
+
line-height : 18px;
|
28 |
+
color : #ccc;
|
29 |
+
}
|
30 |
+
|
31 |
+
#epiceditor-preview a {
|
32 |
+
color : #fff;
|
33 |
+
}
|
34 |
+
|
35 |
+
#epiceditor-preview a:hover {
|
36 |
+
color : #00ff00;
|
37 |
+
text-decoration : none;
|
38 |
+
}
|
39 |
+
|
40 |
+
#epiceditor-preview a img {
|
41 |
+
border : none;
|
42 |
+
}
|
43 |
+
|
44 |
+
#epiceditor-preview p {
|
45 |
+
margin-bottom : 9px;
|
46 |
+
}
|
47 |
+
|
48 |
+
#epiceditor-preview h1,
|
49 |
+
#epiceditor-preview h2,
|
50 |
+
#epiceditor-preview h3,
|
51 |
+
#epiceditor-preview h4,
|
52 |
+
#epiceditor-preview h5,
|
53 |
+
#epiceditor-preview h6 {
|
54 |
+
color : #cdcdcd;
|
55 |
+
line-height : 36px;
|
56 |
+
}
|
57 |
+
|
58 |
+
#epiceditor-preview h1 {
|
59 |
+
margin-bottom : 18px;
|
60 |
+
font-size : 30px;
|
61 |
+
}
|
62 |
+
|
63 |
+
#epiceditor-preview h2 {
|
64 |
+
font-size : 24px;
|
65 |
+
}
|
66 |
+
|
67 |
+
#epiceditor-preview h3 {
|
68 |
+
font-size : 18px;
|
69 |
+
}
|
70 |
+
|
71 |
+
#epiceditor-preview h4 {
|
72 |
+
font-size : 16px;
|
73 |
+
}
|
74 |
+
|
75 |
+
#epiceditor-preview h5 {
|
76 |
+
font-size : 14px;
|
77 |
+
}
|
78 |
+
|
79 |
+
#epiceditor-preview h6 {
|
80 |
+
font-size : 13px;
|
81 |
+
}
|
82 |
+
|
83 |
+
#epiceditor-preview hr {
|
84 |
+
margin : 0 0 19px;
|
85 |
+
border : 0;
|
86 |
+
border-bottom : 1px solid #ccc;
|
87 |
+
}
|
88 |
+
|
89 |
+
#epiceditor-preview blockquote {
|
90 |
+
padding : 13px 13px 21px 15px;
|
91 |
+
margin-bottom : 18px;
|
92 |
+
font-family : georgia, serif;
|
93 |
+
font-style : italic;
|
94 |
+
}
|
95 |
+
|
96 |
+
#epiceditor-preview blockquote:before {
|
97 |
+
content : "\201C";
|
98 |
+
font-size : 40px;
|
99 |
+
margin-left : -10px;
|
100 |
+
font-family : georgia, serif;
|
101 |
+
color : #eee;
|
102 |
+
}
|
103 |
+
|
104 |
+
#epiceditor-preview blockquote p {
|
105 |
+
font-size : 14px;
|
106 |
+
font-weight : 300;
|
107 |
+
line-height : 18px;
|
108 |
+
margin-bottom : 0;
|
109 |
+
font-style : italic;
|
110 |
+
}
|
111 |
+
|
112 |
+
#epiceditor-preview code, #epiceditor-preview pre {
|
113 |
+
font-family : Monaco, Andale Mono, Courier New, monospace;
|
114 |
+
}
|
115 |
+
|
116 |
+
#epiceditor-preview code {
|
117 |
+
background-color : #000;
|
118 |
+
color : #f92672;
|
119 |
+
padding : 1px 3px;
|
120 |
+
font-size : 12px;
|
121 |
+
-webkit-border-radius : 3px;
|
122 |
+
-moz-border-radius : 3px;
|
123 |
+
border-radius : 3px;
|
124 |
+
}
|
125 |
+
|
126 |
+
#epiceditor-preview pre {
|
127 |
+
display : block;
|
128 |
+
padding : 14px;
|
129 |
+
color : #66d9ef;
|
130 |
+
margin : 0 0 18px;
|
131 |
+
line-height : 16px;
|
132 |
+
font-size : 11px;
|
133 |
+
border : 1px solid #d9d9d9;
|
134 |
+
white-space : pre-wrap;
|
135 |
+
word-wrap : break-word;
|
136 |
+
}
|
137 |
+
|
138 |
+
#epiceditor-preview pre code {
|
139 |
+
background-color : #000;
|
140 |
+
color : #ccc;
|
141 |
+
font-size : 11px;
|
142 |
+
padding : 0;
|
143 |
+
}
|
skin/adminhtml/default/default/markdown.css
DELETED
@@ -1,310 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
Copyright http://kevinburke.bitbucket.org/markdowncss/
|
3 |
-
Adapted for Magento Markdown
|
4 |
-
*/
|
5 |
-
.markdown {
|
6 |
-
margin : 0 auto;
|
7 |
-
font-family : Georgia, Palatino, serif;
|
8 |
-
color : #444444;
|
9 |
-
line-height : 1;
|
10 |
-
max-width : 960px;
|
11 |
-
padding : 30px;
|
12 |
-
background-color : white;
|
13 |
-
}
|
14 |
-
|
15 |
-
.markdown h1, .markdown h2, .markdown h3, .markdown h4 {
|
16 |
-
color : #111111;
|
17 |
-
font-weight : 400;
|
18 |
-
}
|
19 |
-
|
20 |
-
.markdown h1, .markdown h2, .markdown h3, .markdown h4, .markdown h5, .markdown p {
|
21 |
-
margin-bottom : 24px;
|
22 |
-
padding : 0;
|
23 |
-
}
|
24 |
-
|
25 |
-
.markdown h1 {
|
26 |
-
font-size : 48px;
|
27 |
-
}
|
28 |
-
|
29 |
-
.markdown h2 {
|
30 |
-
font-size : 36px;
|
31 |
-
/* The bottom margin is small. It's designed to be used with gray meta text
|
32 |
-
* below a post title. */
|
33 |
-
margin : 24px 0 6px;
|
34 |
-
}
|
35 |
-
|
36 |
-
.markdown h3 {
|
37 |
-
font-size : 24px;
|
38 |
-
}
|
39 |
-
|
40 |
-
.markdown h4 {
|
41 |
-
font-size : 21px;
|
42 |
-
}
|
43 |
-
|
44 |
-
.markdown h5 {
|
45 |
-
font-size : 18px;
|
46 |
-
}
|
47 |
-
|
48 |
-
.markdown a {
|
49 |
-
color : #0099ff;
|
50 |
-
margin : 0;
|
51 |
-
padding : 0;
|
52 |
-
vertical-align : baseline;
|
53 |
-
}
|
54 |
-
|
55 |
-
.markdown a:hover {
|
56 |
-
text-decoration : none;
|
57 |
-
color : #ff6600;
|
58 |
-
}
|
59 |
-
|
60 |
-
.markdown a:visited {
|
61 |
-
color : purple;
|
62 |
-
}
|
63 |
-
|
64 |
-
.markdown ul, ol {
|
65 |
-
list-style: disc inside;
|
66 |
-
padding : 0;
|
67 |
-
margin : 0;
|
68 |
-
}
|
69 |
-
|
70 |
-
.markdown li {
|
71 |
-
line-height : 24px;
|
72 |
-
}
|
73 |
-
|
74 |
-
.markdown li ul, .markdown li ul {
|
75 |
-
margin-left : 24px;
|
76 |
-
}
|
77 |
-
|
78 |
-
.markdown p, .markdown ul, .markdown ol {
|
79 |
-
font-size : 16px;
|
80 |
-
line-height : 24px;
|
81 |
-
/*max-width : 540px;*/
|
82 |
-
}
|
83 |
-
|
84 |
-
.markdown pre {
|
85 |
-
padding : 0px 24px;
|
86 |
-
max-width : 700px;
|
87 |
-
white-space : pre-wrap;
|
88 |
-
}
|
89 |
-
|
90 |
-
.markdown code, .markdown pre code {
|
91 |
-
font-family : Consolas, Monaco, Andale Mono, monospace;
|
92 |
-
line-height : 1.5;
|
93 |
-
font-size : 13px;
|
94 |
-
|
95 |
-
margin : 0 2px;
|
96 |
-
padding : 0 5px;
|
97 |
-
/*white-space: nowrap;*/
|
98 |
-
border : 1px solid #eaeaea;
|
99 |
-
background-color : #f8f8f8;
|
100 |
-
border-radius : 3px;
|
101 |
-
}
|
102 |
-
|
103 |
-
.markdown aside {
|
104 |
-
display : block;
|
105 |
-
float : right;
|
106 |
-
width : 390px;
|
107 |
-
}
|
108 |
-
|
109 |
-
.markdown blockquote {
|
110 |
-
border-left : .5em solid #eee;
|
111 |
-
padding : 0 2em;
|
112 |
-
margin-left : 0;
|
113 |
-
max-width : 476px;
|
114 |
-
}
|
115 |
-
|
116 |
-
.markdown blockquote cite {
|
117 |
-
font-size : 14px;
|
118 |
-
line-height : 20px;
|
119 |
-
color : #bfbfbf;
|
120 |
-
}
|
121 |
-
|
122 |
-
.markdown blockquote cite:before {
|
123 |
-
content : '\2014 \00A0';
|
124 |
-
}
|
125 |
-
|
126 |
-
.markdown blockquote p {
|
127 |
-
color : #666;
|
128 |
-
max-width : 460px;
|
129 |
-
}
|
130 |
-
|
131 |
-
.markdown hr {
|
132 |
-
width : 540px;
|
133 |
-
text-align : left;
|
134 |
-
margin : 0 auto 0 0;
|
135 |
-
color : #999;
|
136 |
-
}
|
137 |
-
|
138 |
-
/* Code below this line is copyright Twitter Inc. */
|
139 |
-
|
140 |
-
.markdown button,
|
141 |
-
.markdown input,
|
142 |
-
.markdown select,
|
143 |
-
.markdown textarea {
|
144 |
-
font-size : 100%;
|
145 |
-
margin : 0;
|
146 |
-
vertical-align : baseline;
|
147 |
-
*vertical-align : middle;
|
148 |
-
}
|
149 |
-
|
150 |
-
.markdown button, .markdown input {
|
151 |
-
line-height : normal;
|
152 |
-
*overflow : visible;
|
153 |
-
}
|
154 |
-
|
155 |
-
.markdown button::-moz-focus-inner, .markdown input::-moz-focus-inner {
|
156 |
-
border : 0;
|
157 |
-
padding : 0;
|
158 |
-
}
|
159 |
-
|
160 |
-
.markdown button,
|
161 |
-
.markdown input[type="button"],
|
162 |
-
.markdown input[type="reset"],
|
163 |
-
.markdown input[type="submit"] {
|
164 |
-
cursor : pointer;
|
165 |
-
-webkit-appearance : button;
|
166 |
-
}
|
167 |
-
|
168 |
-
.markdown input[type=checkbox], .markdown input[type=radio] {
|
169 |
-
cursor : pointer;
|
170 |
-
}
|
171 |
-
|
172 |
-
/* override default chrome & firefox settings */
|
173 |
-
.markdown input:not([type="image"]), .markdown textarea {
|
174 |
-
-webkit-box-sizing : content-box;
|
175 |
-
-moz-box-sizing : content-box;
|
176 |
-
box-sizing : content-box;
|
177 |
-
}
|
178 |
-
|
179 |
-
.markdown input[type="search"] {
|
180 |
-
-webkit-appearance : textfield;
|
181 |
-
-webkit-box-sizing : content-box;
|
182 |
-
-moz-box-sizing : content-box;
|
183 |
-
box-sizing : content-box;
|
184 |
-
}
|
185 |
-
|
186 |
-
.markdown input[type="search"]::-webkit-search-decoration {
|
187 |
-
-webkit-appearance : none;
|
188 |
-
}
|
189 |
-
|
190 |
-
.markdown label,
|
191 |
-
.markdown input,
|
192 |
-
.markdown select,
|
193 |
-
.markdown textarea {
|
194 |
-
font-family : "Helvetica Neue", Helvetica, Arial, sans-serif;
|
195 |
-
font-size : 13px;
|
196 |
-
font-weight : normal;
|
197 |
-
line-height : normal;
|
198 |
-
margin-bottom : 18px;
|
199 |
-
}
|
200 |
-
|
201 |
-
.markdown input[type=checkbox], .markdown input[type=radio] {
|
202 |
-
cursor : pointer;
|
203 |
-
margin-bottom : 0;
|
204 |
-
}
|
205 |
-
|
206 |
-
.markdown input[type=text],
|
207 |
-
.markdown input[type=password],
|
208 |
-
.markdown textarea,
|
209 |
-
.markdown select {
|
210 |
-
display : inline-block;
|
211 |
-
width : 210px;
|
212 |
-
padding : 4px;
|
213 |
-
font-size : 13px;
|
214 |
-
font-weight : normal;
|
215 |
-
line-height : 18px;
|
216 |
-
height : 18px;
|
217 |
-
color : #808080;
|
218 |
-
border : 1px solid #ccc;
|
219 |
-
-webkit-border-radius : 3px;
|
220 |
-
-moz-border-radius : 3px;
|
221 |
-
border-radius : 3px;
|
222 |
-
}
|
223 |
-
|
224 |
-
.markdown select, .markdown input[type=file] {
|
225 |
-
height : 27px;
|
226 |
-
line-height : 27px;
|
227 |
-
}
|
228 |
-
|
229 |
-
.markdown textarea {
|
230 |
-
height : auto;
|
231 |
-
}
|
232 |
-
|
233 |
-
/* grey out placeholders */
|
234 |
-
.markdown :-moz-placeholder {
|
235 |
-
color : #bfbfbf;
|
236 |
-
}
|
237 |
-
|
238 |
-
.markdown ::-webkit-input-placeholder {
|
239 |
-
color : #bfbfbf;
|
240 |
-
}
|
241 |
-
|
242 |
-
.markdown input[type=text],
|
243 |
-
.markdown input[type=password],
|
244 |
-
.markdown select,
|
245 |
-
.markdown textarea {
|
246 |
-
-webkit-transition : border linear 0.2s, box-shadow linear 0.2s;
|
247 |
-
-moz-transition : border linear 0.2s, box-shadow linear 0.2s;
|
248 |
-
transition : border linear 0.2s, box-shadow linear 0.2s;
|
249 |
-
-webkit-box-shadow : inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
250 |
-
-moz-box-shadow : inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
251 |
-
box-shadow : inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
252 |
-
}
|
253 |
-
|
254 |
-
.markdown input[type=text]:focus, .markdown input[type=password]:focus, .markdown textarea:focus {
|
255 |
-
outline : none;
|
256 |
-
border-color : rgba(82, 168, 236, 0.8);
|
257 |
-
-webkit-box-shadow : inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
|
258 |
-
-moz-box-shadow : inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
|
259 |
-
box-shadow : inset 0 1px 3px rgba(0, 0, 0, 0.1), 0 0 8px rgba(82, 168, 236, 0.6);
|
260 |
-
}
|
261 |
-
|
262 |
-
/* buttons */
|
263 |
-
.markdown button {
|
264 |
-
display : inline-block;
|
265 |
-
padding : 4px 14px;
|
266 |
-
font-family : "Helvetica Neue", Helvetica, Arial, sans-serif;
|
267 |
-
font-size : 13px;
|
268 |
-
line-height : 18px;
|
269 |
-
-webkit-border-radius : 4px;
|
270 |
-
-moz-border-radius : 4px;
|
271 |
-
border-radius : 4px;
|
272 |
-
-webkit-box-shadow : inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
273 |
-
-moz-box-shadow : inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
274 |
-
box-shadow : inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
|
275 |
-
background-color : #0064cd;
|
276 |
-
background-repeat : repeat-x;
|
277 |
-
background-image : -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));
|
278 |
-
background-image : -moz-linear-gradient(top, #049cdb, #0064cd);
|
279 |
-
background-image : -ms-linear-gradient(top, #049cdb, #0064cd);
|
280 |
-
background-image : -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));
|
281 |
-
background-image : -webkit-linear-gradient(top, #049cdb, #0064cd);
|
282 |
-
background-image : -o-linear-gradient(top, #049cdb, #0064cd);
|
283 |
-
background-image : linear-gradient(top, #049cdb, #0064cd);
|
284 |
-
color : #fff;
|
285 |
-
text-shadow : 0 -1px 0 rgba(0, 0, 0, 0.25);
|
286 |
-
border : 1px solid #004b9a;
|
287 |
-
border-bottom-color : #003f81;
|
288 |
-
-webkit-transition : 0.1s linear all;
|
289 |
-
-moz-transition : 0.1s linear all;
|
290 |
-
transition : 0.1s linear all;
|
291 |
-
border-color : #0064cd #0064cd #003f81;
|
292 |
-
border-color : rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
293 |
-
}
|
294 |
-
|
295 |
-
.markdown button:hover {
|
296 |
-
color : #fff;
|
297 |
-
background-position : 0 -15px;
|
298 |
-
text-decoration : none;
|
299 |
-
}
|
300 |
-
|
301 |
-
.markdown button:active {
|
302 |
-
-webkit-box-shadow : inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
303 |
-
-moz-box-shadow : inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
304 |
-
box-shadow : inset 0 3px 7px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
|
305 |
-
}
|
306 |
-
|
307 |
-
.markdown button::-moz-focus-inner {
|
308 |
-
padding : 0;
|
309 |
-
border : 0;
|
310 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
skin/adminhtml/default/default/markdown/mdm.css
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
Magento Markdown Module CSS
|
3 |
+
*/
|
4 |
+
.fReaderDrag {
|
5 |
+
border : 5px solid darkseagreen;
|
6 |
+
}
|