Chrome浏览器扩展v1.0
BIN
BrowserMark/css/fonts/icomoon.eot
Normal file
15
BrowserMark/css/fonts/icomoon.svg
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="icomoon" horiz-adv-x="512">
|
||||
<font-face units-per-em="512" ascent="480" descent="-32" />
|
||||
<missing-glyph horiz-adv-x="512" />
|
||||
<glyph unicode=" " d="" horiz-adv-x="256" />
|
||||
<glyph unicode="" d="M463.906 480h-144.281c-26.453 0-63.398-15.303-82.102-34.007l-223.495-223.495c-18.704-18.704-18.704-49.312 0-68.016l172.455-172.453c18.704-18.705 49.311-18.705 68.015 0l223.495 223.494c18.704 18.705 34.007 55.651 34.007 82.102v144.281c0 26.452-21.643 48.094-48.094 48.094zM400 320c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48z" />
|
||||
<glyph unicode="" d="M367.334 146.509l-70.605 80.691 70.605 80.691c12.007 12.007 12.007 31.463 0 43.443-12.007 11.981-31.462 11.981-43.443 0l-67.891-77.594-67.865 77.568c-12.006 12.007-31.463 12.007-43.443 0-11.981-12.006-11.981-31.462 0-43.443l70.579-80.666-70.605-80.691c-11.981-12.007-11.981-31.411 0-43.392 12.006-12.007 31.463-12.007 43.443 0l67.891 77.543 67.865-77.543c12.007-12.007 31.462-12.007 43.443 0s12.007 31.385 0.026 43.392z" />
|
||||
<glyph unicode="" d="M512 288h-192l71.765 71.765c-36.265 36.263-84.48 56.235-135.765 56.235-51.285 0-99.5-19.972-135.765-56.235-36.263-36.265-56.235-84.48-56.235-135.765 0-51.285 19.972-99.5 56.235-135.765 36.265-36.263 84.48-56.235 135.765-56.235 51.285 0 99.5 19.972 135.764 56.236 3.028 3.027 5.93 6.146 8.728 9.334l48.16-42.141c-46.923-53.583-115.832-87.429-192.652-87.429-141.385 0-256 114.615-256 256 0 141.385 114.615 256 256 256 70.693 0 134.684-28.663 181.008-74.992l74.992 74.992v-192z" />
|
||||
<glyph unicode="" d="M360.704 429.209c-29.209 21.069-65.843 31.591-109.978 31.591-33.587 0-61.901-7.424-84.915-22.221-36.531-23.194-55.936-62.566-58.291-118.118h84.633c0 16.179 4.71 31.769 14.157 46.771s25.472 22.502 48.077 22.502c22.963 0 38.81-6.093 47.462-18.253 8.678-12.211 13.005-25.702 13.005-40.499 0-12.877-6.451-24.653-14.233-35.379-4.275-6.247-9.933-11.981-16.921-17.255 0 0-45.901-29.44-66.073-53.095-11.699-13.722-12.749-34.253-13.773-63.719-0.077-2.099 0.717-6.425 8.064-6.425s59.315 0 65.843 0 7.885 4.839 7.987 6.963c0.461 10.726 1.664 16.205 3.635 22.4 3.712 11.699 13.747 21.913 25.063 30.695l23.296 16.077c21.017 16.384 37.811 29.824 45.209 40.371 12.647 17.357 21.529 38.707 21.529 64.025 0 41.344-14.618 72.525-43.776 93.568zM249.369 104.345c-29.184 0.87-53.248-19.303-54.169-50.944-0.922-31.616 21.965-52.505 51.149-53.376 30.464-0.896 53.888 18.637 54.81 50.253 0.896 31.642-21.325 53.171-51.789 54.067z" />
|
||||
<glyph unicode="" d="M373.76 332.774l-235.52 0.026 117.76-204.8z" />
|
||||
</font></defs></svg>
|
After Width: | Height: | Size: 2.7 KiB |
BIN
BrowserMark/css/fonts/icomoon.ttf
Normal file
BIN
BrowserMark/css/fonts/icomoon.woff
Normal file
681
BrowserMark/css/github-markdown.css
Normal file
@ -0,0 +1,681 @@
|
||||
@font-face {
|
||||
font-family: octicons-link;
|
||||
src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAZwABAAAAAACFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEU0lHAAAGaAAAAAgAAAAIAAAAAUdTVUIAAAZcAAAACgAAAAoAAQAAT1MvMgAAAyQAAABJAAAAYFYEU3RjbWFwAAADcAAAAEUAAACAAJThvmN2dCAAAATkAAAABAAAAAQAAAAAZnBnbQAAA7gAAACyAAABCUM+8IhnYXNwAAAGTAAAABAAAAAQABoAI2dseWYAAAFsAAABPAAAAZwcEq9taGVhZAAAAsgAAAA0AAAANgh4a91oaGVhAAADCAAAABoAAAAkCA8DRGhtdHgAAAL8AAAADAAAAAwGAACfbG9jYQAAAsAAAAAIAAAACABiATBtYXhwAAACqAAAABgAAAAgAA8ASm5hbWUAAAToAAABQgAAAlXu73sOcG9zdAAABiwAAAAeAAAAME3QpOBwcmVwAAAEbAAAAHYAAAB/aFGpk3jaTY6xa8JAGMW/O62BDi0tJLYQincXEypYIiGJjSgHniQ6umTsUEyLm5BV6NDBP8Tpts6F0v+k/0an2i+itHDw3v2+9+DBKTzsJNnWJNTgHEy4BgG3EMI9DCEDOGEXzDADU5hBKMIgNPZqoD3SilVaXZCER3/I7AtxEJLtzzuZfI+VVkprxTlXShWKb3TBecG11rwoNlmmn1P2WYcJczl32etSpKnziC7lQyWe1smVPy/Lt7Kc+0vWY/gAgIIEqAN9we0pwKXreiMasxvabDQMM4riO+qxM2ogwDGOZTXxwxDiycQIcoYFBLj5K3EIaSctAq2kTYiw+ymhce7vwM9jSqO8JyVd5RH9gyTt2+J/yUmYlIR0s04n6+7Vm1ozezUeLEaUjhaDSuXHwVRgvLJn1tQ7xiuVv/ocTRF42mNgZGBgYGbwZOBiAAFGJBIMAAizAFoAAABiAGIAznjaY2BkYGAA4in8zwXi+W2+MjCzMIDApSwvXzC97Z4Ig8N/BxYGZgcgl52BCSQKAA3jCV8CAABfAAAAAAQAAEB42mNgZGBg4f3vACQZQABIMjKgAmYAKEgBXgAAeNpjYGY6wTiBgZWBg2kmUxoDA4MPhGZMYzBi1AHygVLYQUCaawqDA4PChxhmh/8ODDEsvAwHgMKMIDnGL0x7gJQCAwMAJd4MFwAAAHjaY2BgYGaA4DAGRgYQkAHyGMF8NgYrIM3JIAGVYYDT+AEjAwuDFpBmA9KMDEwMCh9i/v8H8sH0/4dQc1iAmAkALaUKLgAAAHjaTY9LDsIgEIbtgqHUPpDi3gPoBVyRTmTddOmqTXThEXqrob2gQ1FjwpDvfwCBdmdXC5AVKFu3e5MfNFJ29KTQT48Ob9/lqYwOGZxeUelN2U2R6+cArgtCJpauW7UQBqnFkUsjAY/kOU1cP+DAgvxwn1chZDwUbd6CFimGXwzwF6tPbFIcjEl+vvmM/byA48e6tWrKArm4ZJlCbdsrxksL1AwWn/yBSJKpYbq8AXaaTb8AAHja28jAwOC00ZrBeQNDQOWO//sdBBgYGRiYWYAEELEwMTE4uzo5Zzo5b2BxdnFOcALxNjA6b2ByTswC8jYwg0VlNuoCTWAMqNzMzsoK1rEhNqByEyerg5PMJlYuVueETKcd/89uBpnpvIEVomeHLoMsAAe1Id4AAAAAAAB42oWQT07CQBTGv0JBhagk7HQzKxca2sJCE1hDt4QF+9JOS0nbaaYDCQfwCJ7Au3AHj+LO13FMmm6cl7785vven0kBjHCBhfpYuNa5Ph1c0e2Xu3jEvWG7UdPDLZ4N92nOm+EBXuAbHmIMSRMs+4aUEd4Nd3CHD8NdvOLTsA2GL8M9PODbcL+hD7C1xoaHeLJSEao0FEW14ckxC+TU8TxvsY6X0eLPmRhry2WVioLpkrbp84LLQPGI7c6sOiUzpWIWS5GzlSgUzzLBSikOPFTOXqly7rqx0Z1Q5BAIoZBSFihQYQOOBEdkCOgXTOHA07HAGjGWiIjaPZNW13/+lm6S9FT7rLHFJ6fQbkATOG1j2OFMucKJJsxIVfQORl+9Jyda6Sl1dUYhSCm1dyClfoeDve4qMYdLEbfqHf3O/AdDumsjAAB42mNgYoAAZQYjBmyAGYQZmdhL8zLdDEydARfoAqIAAAABAAMABwAKABMAB///AA8AAQAAAAAAAAAAAAAAAAABAAAAAA==) format('woff');
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
line-height: 1.5;
|
||||
color: #333;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.markdown-body .pl-c {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
.markdown-body .pl-c1,
|
||||
.markdown-body .pl-s .pl-v {
|
||||
color: #0086b3;
|
||||
}
|
||||
|
||||
.markdown-body .pl-e,
|
||||
.markdown-body .pl-en {
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.markdown-body .pl-smi,
|
||||
.markdown-body .pl-s .pl-s1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.markdown-body .pl-ent {
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.markdown-body .pl-k {
|
||||
color: #a71d5d;
|
||||
}
|
||||
|
||||
.markdown-body .pl-s,
|
||||
.markdown-body .pl-pds,
|
||||
.markdown-body .pl-s .pl-pse .pl-s1,
|
||||
.markdown-body .pl-sr,
|
||||
.markdown-body .pl-sr .pl-cce,
|
||||
.markdown-body .pl-sr .pl-sre,
|
||||
.markdown-body .pl-sr .pl-sra {
|
||||
color: #183691;
|
||||
}
|
||||
|
||||
.markdown-body .pl-v {
|
||||
color: #ed6a43;
|
||||
}
|
||||
|
||||
.markdown-body .pl-id {
|
||||
color: #b52a1d;
|
||||
}
|
||||
|
||||
.markdown-body .pl-ii {
|
||||
color: #f8f8f8;
|
||||
background-color: #b52a1d;
|
||||
}
|
||||
|
||||
.markdown-body .pl-sr .pl-cce {
|
||||
font-weight: bold;
|
||||
color: #63a35c;
|
||||
}
|
||||
|
||||
.markdown-body .pl-ml {
|
||||
color: #693a17;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mh,
|
||||
.markdown-body .pl-mh .pl-en,
|
||||
.markdown-body .pl-ms {
|
||||
font-weight: bold;
|
||||
color: #1d3e81;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mq {
|
||||
color: #008080;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mi {
|
||||
font-style: italic;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mb {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.markdown-body .pl-md {
|
||||
color: #bd2c00;
|
||||
background-color: #ffecec;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mi1 {
|
||||
color: #55a532;
|
||||
background-color: #eaffea;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mdr {
|
||||
font-weight: bold;
|
||||
color: #795da3;
|
||||
}
|
||||
|
||||
.markdown-body .pl-mo {
|
||||
color: #1d3e81;
|
||||
}
|
||||
|
||||
.markdown-body .octicon {
|
||||
display: inline-block;
|
||||
vertical-align: text-top;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.markdown-body a {
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects;
|
||||
}
|
||||
|
||||
.markdown-body a:active,
|
||||
.markdown-body a:hover {
|
||||
outline-width: 0;
|
||||
}
|
||||
|
||||
.markdown-body strong {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
.markdown-body strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
.markdown-body img {
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.markdown-body svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown-body code,
|
||||
.markdown-body kbd,
|
||||
.markdown-body pre {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.markdown-body [type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.markdown-body a {
|
||||
color: #4078c0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body a:hover,
|
||||
.markdown-body a:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.markdown-body strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
height: 0;
|
||||
margin: 15px 0;
|
||||
overflow: hidden;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body hr::before {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body hr::after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.markdown-body td,
|
||||
.markdown-body th {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body h2 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body h5 {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body h6 {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.markdown-body p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.markdown-body blockquote {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding-left: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body ol ol,
|
||||
.markdown-body ul ol {
|
||||
list-style-type: lower-roman;
|
||||
}
|
||||
|
||||
.markdown-body ul ul ol,
|
||||
.markdown-body ul ol ol,
|
||||
.markdown-body ol ul ol,
|
||||
.markdown-body ol ol ol {
|
||||
list-style-type: lower-alpha;
|
||||
}
|
||||
|
||||
.markdown-body dd {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.markdown-body code {
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
|
||||
.markdown-body .octicon {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.markdown-body input {
|
||||
-webkit-font-feature-settings: "liga" 0;
|
||||
font-feature-settings: "liga" 0;
|
||||
}
|
||||
|
||||
.markdown-body::before {
|
||||
display: table;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body::after {
|
||||
display: table;
|
||||
clear: both;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.markdown-body>*:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body>*:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body a:not([href]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body .anchor {
|
||||
float: left;
|
||||
padding-right: 4px;
|
||||
margin-left: -20px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.markdown-body .anchor:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.markdown-body p,
|
||||
.markdown-body blockquote,
|
||||
.markdown-body ul,
|
||||
.markdown-body ol,
|
||||
.markdown-body dl,
|
||||
.markdown-body table,
|
||||
.markdown-body pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
height: 0.25em;
|
||||
padding: 0;
|
||||
margin: 24px 0;
|
||||
background-color: #e7e7e7;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body blockquote {
|
||||
padding: 0 1em;
|
||||
color: #777;
|
||||
border-left: 0.25em solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.markdown-body blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font-size: 11px;
|
||||
line-height: 10px;
|
||||
color: #555;
|
||||
vertical-align: middle;
|
||||
background-color: #fcfcfc;
|
||||
border: solid 1px #ccc;
|
||||
border-bottom-color: #bbb;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #bbb;
|
||||
}
|
||||
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.markdown-body h1 .octicon-link,
|
||||
.markdown-body h2 .octicon-link,
|
||||
.markdown-body h3 .octicon-link,
|
||||
.markdown-body h4 .octicon-link,
|
||||
.markdown-body h5 .octicon-link,
|
||||
.markdown-body h6 .octicon-link {
|
||||
color: #000;
|
||||
vertical-align: middle;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.markdown-body h1:hover .anchor,
|
||||
.markdown-body h2:hover .anchor,
|
||||
.markdown-body h3:hover .anchor,
|
||||
.markdown-body h4:hover .anchor,
|
||||
.markdown-body h5:hover .anchor,
|
||||
.markdown-body h6:hover .anchor {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body h1:hover .anchor .octicon-link,
|
||||
.markdown-body h2:hover .anchor .octicon-link,
|
||||
.markdown-body h3:hover .anchor .octicon-link,
|
||||
.markdown-body h4:hover .anchor .octicon-link,
|
||||
.markdown-body h5:hover .anchor .octicon-link,
|
||||
.markdown-body h6:hover .anchor .octicon-link {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 2em;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.markdown-body h2 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.5em;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.markdown-body h3 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.markdown-body h4 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-body h5 {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.markdown-body h6 {
|
||||
font-size: 0.85em;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.markdown-body ul ul,
|
||||
.markdown-body ul ol,
|
||||
.markdown-body ol ol,
|
||||
.markdown-body ol ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body li>p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.markdown-body li+li {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
.markdown-body dl {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body dl dt {
|
||||
padding: 0;
|
||||
margin-top: 16px;
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body dl dd {
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.markdown-body table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body table th,
|
||||
.markdown-body table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.markdown-body table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.markdown-body img {
|
||||
max-width: 100%;
|
||||
box-sizing: content-box;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.markdown-body code {
|
||||
padding: 0;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown-body code::before,
|
||||
.markdown-body code::after {
|
||||
letter-spacing: -0.2em;
|
||||
content: "\00a0";
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
.markdown-body pre>code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
word-break: normal;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body .highlight {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body .highlight pre {
|
||||
margin-bottom: 0;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.markdown-body .highlight pre,
|
||||
.markdown-body pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown-body pre code {
|
||||
display: inline;
|
||||
max-width: auto;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body pre code::before,
|
||||
.markdown-body pre code::after {
|
||||
content: normal;
|
||||
}
|
||||
|
||||
.markdown-body .pl-0 {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body .pl-1 {
|
||||
padding-left: 3px !important;
|
||||
}
|
||||
|
||||
.markdown-body .pl-2 {
|
||||
padding-left: 6px !important;
|
||||
}
|
||||
|
||||
.markdown-body .pl-3 {
|
||||
padding-left: 12px !important;
|
||||
}
|
||||
|
||||
.markdown-body .pl-4 {
|
||||
padding-left: 24px !important;
|
||||
}
|
||||
|
||||
.markdown-body .pl-5 {
|
||||
padding-left: 36px !important;
|
||||
}
|
||||
|
||||
.markdown-body .pl-6 {
|
||||
padding-left: 48px !important;
|
||||
}
|
||||
|
||||
.markdown-body .full-commit .btn-outline:not(:disabled):hover {
|
||||
color: #4078c0;
|
||||
border: 1px solid #4078c0;
|
||||
}
|
||||
|
||||
.markdown-body kbd {
|
||||
display: inline-block;
|
||||
padding: 3px 5px;
|
||||
font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
line-height: 10px;
|
||||
color: #555;
|
||||
vertical-align: middle;
|
||||
background-color: #fcfcfc;
|
||||
border: solid 1px #ccc;
|
||||
border-bottom-color: #bbb;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 -1px 0 #bbb;
|
||||
}
|
||||
|
||||
.markdown-body :checked+.radio-label {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border-color: #4078c0;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item+.task-list-item {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.markdown-body .task-list-item input {
|
||||
margin: 0 0.2em 0.25em -1.6em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
border-bottom-color: #eee;
|
||||
}
|
BIN
BrowserMark/css/images/sujilogo.jpeg
Normal file
After Width: | Height: | Size: 6.1 KiB |
2
BrowserMark/css/layui.css
Normal file
8
BrowserMark/css/notification.css
Normal file
@ -0,0 +1,8 @@
|
||||
body{float:left;font-size:12px;font-family:'\5FAE\8F6F\96C5\9ED1',sans-serif;overflow:hidden;}
|
||||
.wrap{margin-left: 40px;}
|
||||
.wrap .title{margin:0;font-weight:bold;}
|
||||
.wrap .content{width:233px;margin:2px 0 10px 0;}
|
||||
a:link, a:visited, a:hover{color:#81b205}
|
||||
ul{list-style: none}
|
||||
ul,li{padding: 0;margin: 0}
|
||||
.icon { float:left;}
|
229
BrowserMark/css/popup.css
Normal file
@ -0,0 +1,229 @@
|
||||
|
||||
::-webkit-scrollbar{width:4px;height:4px;}
|
||||
::-webkit-scrollbar:hover{width: 10px;height: 6px;}
|
||||
::-webkit-scrollbar-thumb{border-radius:1px;background-color: #aaa}
|
||||
::-webkit-scrollbar-thumb:hover{background-color: #999;}
|
||||
|
||||
@font-face {
|
||||
font-family: 'icomoon';
|
||||
src:url('fonts/icomoon.eot?-7801l6');
|
||||
src:url('fonts/icomoon.eot?#iefix-7801l6') format('embedded-opentype'),
|
||||
url('fonts/icomoon.woff?-7801l6') format('woff'),
|
||||
url('fonts/icomoon.ttf?-7801l6') format('truetype'),
|
||||
url('fonts/icomoon.svg?-7801l6#icomoon') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
[class^="icon-"], [class*=" icon-"] {
|
||||
font-family: 'icomoon';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
|
||||
/* Better Font Rendering =========== */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* 开关样式 */
|
||||
.layui-form-onswitch{
|
||||
border-color: #1E9FFF;
|
||||
background-color: #1E9FFF;
|
||||
}
|
||||
/* select 选择器样式 */
|
||||
.layui-form-select dl dd.layui-this {
|
||||
background-color: #1E9FFF;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color:#f2f2f2;
|
||||
color:#555;
|
||||
font-size:14px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
overflow:hidden;
|
||||
padding:0;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
color: rgb(5, 5, 5);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.not-selectable {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 438px;
|
||||
margin:8px 0 0 8px;
|
||||
}
|
||||
|
||||
.top {
|
||||
position:relative;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
background-position:-1px -1px;
|
||||
width:105px;
|
||||
height:32px;
|
||||
display:inline-block;
|
||||
text-indent:100%;
|
||||
white-space:nowrap;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.topcorner {
|
||||
position:absolute;
|
||||
right:0px;
|
||||
top:-8px;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-o-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.topcorner a {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
line-height: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
.topcorner .optionbtn { font-size: 12px; }
|
||||
|
||||
.topcorner .optionbtn:hover { color: #8ab833; }
|
||||
|
||||
.topcorner .closebtn { font-size: 16px; }
|
||||
|
||||
.topcorner .closebtn:hover { color: #8ab833; }
|
||||
|
||||
.mrdoc-utils {
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.mrdoc-auto-extract {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.titleinp {
|
||||
height: 35px;width: 432px;
|
||||
line-height: 24px;
|
||||
font-size: 18px;color: #000;
|
||||
margin: 10px 0;
|
||||
padding: 0 4px;
|
||||
background-color: #fff;
|
||||
border-radius: 1px;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-top-color: #c0c0c0;
|
||||
}
|
||||
|
||||
.titleinp:hover {
|
||||
border-color: #a0a0a0 #b9b9b9 #b9b9b9 #b9b9b9;
|
||||
}
|
||||
|
||||
.titleinp:focus {
|
||||
outline: none;
|
||||
border: 1px solid black;
|
||||
box-shadow: inset 0px 1px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.mrdoc-extra {
|
||||
position: relative;
|
||||
z-index: 1000004;
|
||||
}
|
||||
|
||||
.select {
|
||||
margin: 0 0 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.projects{
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
|
||||
.notecontentwrap{
|
||||
position:relative;
|
||||
width:432px;
|
||||
border: 1px solid #cbcbcb;
|
||||
border-radius: 1px;
|
||||
background-color:#fff;
|
||||
}
|
||||
.notecontentwrap:hover {
|
||||
border-color: #a0a0a0 #b9b9b9 #b9b9b9 #b9b9b9;
|
||||
}
|
||||
|
||||
.notecontentwrap .notecontent{
|
||||
resize:none;
|
||||
border:0 none;
|
||||
outline:none;
|
||||
height:246px;
|
||||
padding:0;
|
||||
min-height:100px;
|
||||
max-height:440px;
|
||||
overflow:auto;
|
||||
width: 430px;
|
||||
}
|
||||
.notecontentwrap .notecontent img{
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
.bottom{
|
||||
font-size:14px;
|
||||
-webkit-user-select:none;
|
||||
user-select:none;
|
||||
position:relative;
|
||||
color:#999;
|
||||
}
|
||||
.bottom .btn{
|
||||
position:absolute;
|
||||
color: #666;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 3px 14px;
|
||||
vertical-align: middle;
|
||||
background-color: #fff;
|
||||
border: 1px solid #cbcbcb;
|
||||
border-radius: 2px;
|
||||
margin: 10px 5px 0 0;
|
||||
}
|
||||
|
||||
.bottom .resetbtn{
|
||||
right:72px;
|
||||
background-color: #fafafa;
|
||||
}
|
||||
.bottom .savebtn{
|
||||
right:0;
|
||||
color: #fff;
|
||||
border-color: black;
|
||||
background-color: black;
|
||||
}
|
||||
.resetbtn:hover {
|
||||
background-color: #fff;
|
||||
border: 1px solid #c6c6c6;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
|
||||
}
|
||||
.savebtn:hover{
|
||||
background-color: #666;
|
||||
border: 1px solid #666;
|
||||
box-shadow: 0 1px 1px rgba(0,0,0,0.1);
|
||||
}
|
139
BrowserMark/css/prism.css
Normal file
@ -0,0 +1,139 @@
|
||||
/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+abap+actionscript+ada+apacheconf+apl+applescript+asciidoc+aspnet+autoit+autohotkey+bash+basic+batch+c+brainfuck+bro+bison+csharp+cpp+coffeescript+ruby+css-extras+d+dart+diff+docker+eiffel+elixir+erlang+fsharp+fortran+gherkin+git+glsl+go+graphql+groovy+haml+handlebars+haskell+haxe+http+icon+inform7+ini+j+jade+java+jolie+json+julia+keyman+kotlin+latex+less+livescript+lolcode+lua+makefile+markdown+matlab+mel+mizar+monkey+nasm+nginx+nim+nix+nsis+objectivec+ocaml+oz+parigp+parser+pascal+perl+php+php-extras+powershell+processing+prolog+properties+protobuf+puppet+pure+python+q+qore+r+jsx+reason+rest+rip+roboconf+crystal+rust+sas+sass+scss+scala+scheme+smalltalk+smarty+sql+stylus+swift+tcl+textile+twig+typescript+verilog+vhdl+vim+wiki+xojo+yaml */
|
||||
/**
|
||||
* prism.js default theme for JavaScript, CSS and HTML
|
||||
* Based on dabblet (http://dabblet.com)
|
||||
* @author Lea Verou
|
||||
*/
|
||||
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
color: black;
|
||||
background: none;
|
||||
text-shadow: 0 1px white;
|
||||
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-spacing: normal;
|
||||
word-break: normal;
|
||||
word-wrap: normal;
|
||||
line-height: 1.5;
|
||||
|
||||
-moz-tab-size: 4;
|
||||
-o-tab-size: 4;
|
||||
tab-size: 4;
|
||||
|
||||
-webkit-hyphens: none;
|
||||
-moz-hyphens: none;
|
||||
-ms-hyphens: none;
|
||||
hyphens: none;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
|
||||
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
|
||||
code[class*="language-"]::selection, code[class*="language-"] ::selection {
|
||||
text-shadow: none;
|
||||
background: #b3d4fc;
|
||||
}
|
||||
|
||||
@media print {
|
||||
code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
pre[class*="language-"] {
|
||||
padding: 1em;
|
||||
margin: .5em 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:not(pre) > code[class*="language-"],
|
||||
pre[class*="language-"] {
|
||||
background: #f5f2f0;
|
||||
}
|
||||
|
||||
/* Inline code */
|
||||
:not(pre) > code[class*="language-"] {
|
||||
padding: .1em;
|
||||
border-radius: .3em;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.token.comment,
|
||||
.token.prolog,
|
||||
.token.doctype,
|
||||
.token.cdata {
|
||||
color: slategray;
|
||||
}
|
||||
|
||||
.token.punctuation {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.namespace {
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.token.property,
|
||||
.token.tag,
|
||||
.token.boolean,
|
||||
.token.number,
|
||||
.token.constant,
|
||||
.token.symbol,
|
||||
.token.deleted {
|
||||
color: #905;
|
||||
}
|
||||
|
||||
.token.selector,
|
||||
.token.attr-name,
|
||||
.token.string,
|
||||
.token.char,
|
||||
.token.builtin,
|
||||
.token.inserted {
|
||||
color: #690;
|
||||
}
|
||||
|
||||
.token.operator,
|
||||
.token.entity,
|
||||
.token.url,
|
||||
.language-css .token.string,
|
||||
.style .token.string {
|
||||
color: #a67f59;
|
||||
/*background: hsla(0, 0%, 100%, .5);*/
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.token.atrule,
|
||||
.token.attr-value,
|
||||
.token.keyword {
|
||||
color: #07a;
|
||||
}
|
||||
|
||||
.token.function {
|
||||
color: #DD4A68;
|
||||
}
|
||||
|
||||
.token.regex,
|
||||
.token.important,
|
||||
.token.variable {
|
||||
color: #e90;
|
||||
}
|
||||
|
||||
.token.important,
|
||||
.token.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
.token.italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.token.entity {
|
||||
cursor: help;
|
||||
}
|
BIN
BrowserMark/img/128x128.png
Normal file
After Width: | Height: | Size: 10 KiB |
337
BrowserMark/js/background.js
Normal file
@ -0,0 +1,337 @@
|
||||
var self = this;
|
||||
var chromeSchemeReg = /chrome:\/\/.*/ig; // Chrome配置项地址的正则表达式
|
||||
layer = layui.layer;
|
||||
|
||||
// 侦听来自popup的消息
|
||||
chrome.runtime.onMessage.addListener(function(request, sender,sendResponse) {
|
||||
if (!sender || sender.id !== chrome.i18n.getMessage("@@extension_id")) return;
|
||||
switch (request.name) {
|
||||
case 'createoptionstab':
|
||||
chrome.tabs.create({
|
||||
url: chrome.i18n.getMessage('helperUrl')
|
||||
});
|
||||
break;
|
||||
case 'checktoken': // 检验token - 回传文集列表数据给popup
|
||||
self.checkToken(function(projects){
|
||||
chrome.tabs.sendMessage(sender.tab.id,{
|
||||
name:'checktokenvalue',
|
||||
data:projects
|
||||
});
|
||||
});
|
||||
case 'savedocfrompopup': // 保存文档
|
||||
self.saveDoc(request.data);
|
||||
break;
|
||||
case 'pasteimage': // 粘贴上传图片 - 回传图片URL给popup
|
||||
self.pasteImg(request.data,function(url){
|
||||
chrome.tabs.sendMessage(sender.tab.id,{
|
||||
name:'pasteimgurl',
|
||||
data:url
|
||||
});
|
||||
});
|
||||
break;
|
||||
case 'selectprojects':
|
||||
selectProjects(request.data,function(projects){
|
||||
chrome.tabs.sendMessage(sender.tab.id,{
|
||||
name:'selectprojectsvalue',
|
||||
data:projects
|
||||
});
|
||||
})
|
||||
break;
|
||||
case 'image2base64':
|
||||
getImgBase64(request.data,function(url){
|
||||
chrome.tabs.sendMessage(sender.tab.id,{
|
||||
name:'img2base64url',
|
||||
data:{url:url,source:request.data}
|
||||
});
|
||||
})
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
//侦听长连接
|
||||
chrome.runtime.onConnect.addListener(function(port) {
|
||||
switch (port.name) {
|
||||
case 'mrdocclipperisready':
|
||||
self.mrdocclipperisreadyHandlerConnect(port);
|
||||
case 'mrdocclipperisnotready':
|
||||
self.mrdocclipperisnotreadyHandlerConnect(port);
|
||||
break;
|
||||
case 'actionfrompopupinspecotr':
|
||||
self.actionfrompopupinspecotrHandler(port);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// 侦听浏览器上扩展图标被点击
|
||||
chrome.browserAction.onClicked.addListener(function(tab) {
|
||||
console.log("扩展图标被点击")
|
||||
console.log(tab)
|
||||
if (!chrome.runtime.sendMessage) {
|
||||
var msg = "抱歉,MrDoc剪藏器暂时不支持该版本的Chrome浏览器,请将浏览器升级到最新稳定版本。点击右上角工具按钮选择'关于 Google Chrome(G)'进行自动升级"
|
||||
notifyTipsFail(msg)
|
||||
return;
|
||||
}
|
||||
var match = tab.url.match(/^(.*?):/),
|
||||
scheme = match[1].toLowerCase();
|
||||
if (chromeSchemeReg.test(tab.url) || (scheme != "http" && scheme != "https")) {
|
||||
notifyTipsFail("不能在Chrome设置操作!")
|
||||
return;
|
||||
}
|
||||
self.createPopup();//创建popup窗口
|
||||
});
|
||||
|
||||
//JQ设置步骤
|
||||
jQuerySetUp = function() {
|
||||
$.ajaxSetup({
|
||||
dataType: 'json',
|
||||
cache: false,
|
||||
// dataFilter: function(data) {
|
||||
// console.log(data)
|
||||
// data = $.parseJSON(data.substr(9)); //remove 'while(1);'
|
||||
// return data.success ? data.data : {
|
||||
// error: data.error
|
||||
// };
|
||||
// },
|
||||
beforeSend: function(xhr) {
|
||||
xhr.setRequestHeader('UserClient', 'inote_web_chromeext/3.1.0');
|
||||
}
|
||||
});
|
||||
};
|
||||
jQuerySetUp();
|
||||
|
||||
//从文本中获取标题
|
||||
getTitleByText = function(txt) {
|
||||
//todo
|
||||
var self = this,
|
||||
finalTitle = '';
|
||||
if (txt.length <= 100) return txt;
|
||||
if (txt.length > 0) {
|
||||
var t = txt.substr(0, 100),
|
||||
l = t.length,
|
||||
i = l - 1,
|
||||
hasSpecialChar = false;
|
||||
while (i >= 0) {
|
||||
if (/^(9|10|44|65292|46|12290|59|65307)$/.test(t.charCodeAt(i))) {
|
||||
hasSpecialChar = true;
|
||||
break;
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
hasSpecialChar ? (t = t.substr(0, i)) : '';
|
||||
i = 0;
|
||||
l = t.length;
|
||||
while (i < l) {
|
||||
if (/^(9|10)$/.test(t.charCodeAt(i))) {
|
||||
break;
|
||||
} else {
|
||||
finalTitle += t.charAt(i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
finalTitle = finalTitle.trim();
|
||||
return finalTitle.length > 0 ? finalTitle : '[未命名笔记]';
|
||||
};
|
||||
|
||||
|
||||
//创建popup
|
||||
createPopup = function() {
|
||||
chrome.tabs.executeScript(null, {
|
||||
code: "try{mrdocClipper.createPopup();}catch(e){console.log(e);var port = chrome.runtime.connect({name: 'mrdocclipperisnotready'});port.postMessage();}"
|
||||
});
|
||||
};
|
||||
//关闭popup
|
||||
closePopup = function() {
|
||||
chrome.tabs.executeScript(null, {
|
||||
code: "mrdocClipper.closePopup();"
|
||||
});
|
||||
};
|
||||
|
||||
// 检查用户Token状态
|
||||
checkToken = function(callback){
|
||||
var self = this;
|
||||
var opt = chrome.storage.local;
|
||||
// 获取mrdoc地址
|
||||
opt.get(['serverUrl'],function(r){
|
||||
self.mrdocUrl = r['serverUrl'];
|
||||
// 获取账户token
|
||||
opt.get(['accountKey'],function(r){
|
||||
self.mrdocToken = r['accountKey'];
|
||||
// 如果存在mrdoc服务地址和账户token,获取文集
|
||||
if(self.mrdocUrl != undefined && self.mrdocToken != undefined){
|
||||
$.get(self.mrdocUrl + '/api/get_projects/?token='+self.mrdocToken,function(r){
|
||||
console.log(r)
|
||||
if(r.status){ // 如果获取文集成功,表示token验证成功,已登录
|
||||
// console.log(r.data)
|
||||
var userProjects = r.data;
|
||||
var item = {
|
||||
"projects":userProjects,
|
||||
"isLogin":true,
|
||||
"token":self.mrdocToken,
|
||||
"url":self.mrdocUrl
|
||||
}
|
||||
callback(item)
|
||||
}else{// 获取文集失败,表示token验证失败,未登录
|
||||
console.log('token验证失败')
|
||||
callback({'isLogin':false})
|
||||
//return {"isLogin":false}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
// 保存文档
|
||||
saveDoc = function(data){
|
||||
var self = this;
|
||||
// console.log(data);
|
||||
$.post(self.url+'/api/create_doc/?token='+self.token,data,function(r){
|
||||
// var layer = layui.layer;
|
||||
layer.closeAll('loading')
|
||||
if(r.status){
|
||||
//消息提示
|
||||
notifyTipsSucce('文档已保存成功,你可以前往mrdoc站点查看和修改!')
|
||||
//关闭popup
|
||||
self.closePopup()
|
||||
}else{
|
||||
//消息提示
|
||||
notifyTipsFail("文档保存失败!")
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 粘贴上传图片
|
||||
pasteImg = function(data,callback){
|
||||
//console.log(data)
|
||||
$.post(self.url+'/api/upload_img/?token='+self.token,{data:data}, function (ret) {
|
||||
if (ret.success === 1) {
|
||||
//新一行的图片显示
|
||||
console.log("上传图片成功")
|
||||
//console.log(ret.url)
|
||||
callback(ret.url)
|
||||
notifyTipsSucce("图片上传成功")
|
||||
}else{
|
||||
console.log("上传图片失败")
|
||||
notifyTipsFail("图片上传失败!")
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取文集
|
||||
selectProjects = function(data,callback){
|
||||
var self = this;
|
||||
// console.log(data)
|
||||
self.url = data.url,self.token = data.token;
|
||||
$.ajax({
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
type: 'GET',
|
||||
url: url+'/api/get_projects/?token='+token,
|
||||
success: function(r) {
|
||||
// console.log(r)
|
||||
if(r.status){
|
||||
callback(r.data)
|
||||
}else{
|
||||
callback({error:true})
|
||||
notifyTipsFail("文集获取请求失败,请确认你的账户token是否正确!")
|
||||
}
|
||||
},
|
||||
error: function(r) {
|
||||
callback({error:true})
|
||||
// console.log(r)
|
||||
notifyTipsFail("文集获取请求失败,请确认你的MrDoc站点可访问!")
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取外链图片base64编码
|
||||
getImgBase64 = function(data,callback){
|
||||
window.URL = window.URL || window.webkitURL;
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("get", data, true);
|
||||
// 至关重要
|
||||
xhr.responseType = "blob";
|
||||
xhr.onload = function(){
|
||||
if(this.status == 200){
|
||||
//得到一个blob对象
|
||||
var blob = this.response;
|
||||
console.log("blob", blob)
|
||||
// 至关重要
|
||||
let oFileReader = new FileReader();
|
||||
oFileReader.onloadend = function (e) {
|
||||
// 此处拿到的已经是 base64的图片了
|
||||
let base64 = e.target.result;
|
||||
//console.log("图片base64", base64)
|
||||
self.pasteImg(base64,callback)
|
||||
};
|
||||
oFileReader.readAsDataURL(blob);
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// ////////////消息提示框////////////////
|
||||
|
||||
//成功的消息提示框
|
||||
notifyTipsSucce = function(data){
|
||||
chrome.notifications.create(null, {
|
||||
type: 'basic',
|
||||
iconUrl: 'img/128x128.png',
|
||||
title: 'MrDoc剪藏:操作成功!',
|
||||
message: data
|
||||
},function(id){
|
||||
setTimeout(() => {
|
||||
chrome.notifications.clear(id)
|
||||
}, 3000);
|
||||
});
|
||||
};
|
||||
|
||||
//失败的消息提示框
|
||||
notifyTipsFail = function(data){
|
||||
chrome.notifications.create(null, {
|
||||
type: 'basic',
|
||||
iconUrl: 'img/128x128.png',
|
||||
title: 'MrDoc剪藏:操作失败!',
|
||||
message: data
|
||||
},function(id){
|
||||
setTimeout(() => {
|
||||
chrome.notifications.clear(id)
|
||||
}, 3000);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
mrdocclipperisreadyHandlerConnect = function(port) {
|
||||
var self = this;
|
||||
port.onMessage.addListener(function(msg) {
|
||||
ReadyErrorNotify.close();
|
||||
});
|
||||
};
|
||||
mrdocclipperisnotreadyHandlerConnect = function(port) {
|
||||
var self = this;
|
||||
port.onMessage.addListener(function(data) {
|
||||
data = data || {};
|
||||
// ReadyErrorNotify.show(data.key);
|
||||
notifyTipsFail(data.key)
|
||||
});
|
||||
};
|
||||
//来自popup注入器的处理操作
|
||||
actionfrompopupinspecotrHandler = function(port) {
|
||||
var self = this;
|
||||
port.onMessage.addListener(function(data) {
|
||||
console.log("页面剪藏数据")
|
||||
console.log(data)
|
||||
//发送到popup
|
||||
chrome.tabs.sendMessage(port.sender.tab.id, {
|
||||
name: 'actionfrompopupinspecotr',
|
||||
data: data
|
||||
});
|
||||
});
|
||||
};
|
206
BrowserMark/js/codemirror/addon/comment/comment.js
vendored
Normal file
@ -0,0 +1,206 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var noOptions = {};
|
||||
var nonWS = /[^\s\u00a0]/;
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function firstNonWS(str) {
|
||||
var found = str.search(nonWS);
|
||||
return found == -1 ? 0 : found;
|
||||
}
|
||||
|
||||
CodeMirror.commands.toggleComment = function(cm) {
|
||||
cm.toggleComment();
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("toggleComment", function(options) {
|
||||
if (!options) options = noOptions;
|
||||
var cm = this;
|
||||
var minLine = Infinity, ranges = this.listSelections(), mode = null;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var from = ranges[i].from(), to = ranges[i].to();
|
||||
if (from.line >= minLine) continue;
|
||||
if (to.line >= minLine) to = Pos(minLine, 0);
|
||||
minLine = from.line;
|
||||
if (mode == null) {
|
||||
if (cm.uncomment(from, to, options)) mode = "un";
|
||||
else { cm.lineComment(from, to, options); mode = "line"; }
|
||||
} else if (mode == "un") {
|
||||
cm.uncomment(from, to, options);
|
||||
} else {
|
||||
cm.lineComment(from, to, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Rough heuristic to try and detect lines that are part of multi-line string
|
||||
function probablyInsideString(cm, pos, line) {
|
||||
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"`]/.test(line)
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("lineComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var firstLine = self.getLine(from.line);
|
||||
if (firstLine == null || probablyInsideString(self, from, firstLine)) return;
|
||||
|
||||
var commentString = options.lineComment || mode.lineComment;
|
||||
if (!commentString) {
|
||||
if (options.blockCommentStart || mode.blockCommentStart) {
|
||||
options.fullLines = true;
|
||||
self.blockComment(from, to, options);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1);
|
||||
var pad = options.padding == null ? " " : options.padding;
|
||||
var blankLines = options.commentBlankLines || from.line == to.line;
|
||||
|
||||
self.operation(function() {
|
||||
if (options.indent) {
|
||||
var baseString = null;
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
var line = self.getLine(i);
|
||||
var whitespace = line.slice(0, firstNonWS(line));
|
||||
if (baseString == null || baseString.length > whitespace.length) {
|
||||
baseString = whitespace;
|
||||
}
|
||||
}
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
var line = self.getLine(i), cut = baseString.length;
|
||||
if (!blankLines && !nonWS.test(line)) continue;
|
||||
if (line.slice(0, cut) != baseString) cut = firstNonWS(line);
|
||||
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut));
|
||||
}
|
||||
} else {
|
||||
for (var i = from.line; i < end; ++i) {
|
||||
if (blankLines || nonWS.test(self.getLine(i)))
|
||||
self.replaceRange(commentString + pad, Pos(i, 0));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("blockComment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||||
if (!startString || !endString) {
|
||||
if ((options.lineComment || mode.lineComment) && options.fullLines != false)
|
||||
self.lineComment(from, to, options);
|
||||
return;
|
||||
}
|
||||
if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return
|
||||
|
||||
var end = Math.min(to.line, self.lastLine());
|
||||
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end;
|
||||
|
||||
var pad = options.padding == null ? " " : options.padding;
|
||||
if (from.line > end) return;
|
||||
|
||||
self.operation(function() {
|
||||
if (options.fullLines != false) {
|
||||
var lastLineHasText = nonWS.test(self.getLine(end));
|
||||
self.replaceRange(pad + endString, Pos(end));
|
||||
self.replaceRange(startString + pad, Pos(from.line, 0));
|
||||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||||
if (lead != null) for (var i = from.line + 1; i <= end; ++i)
|
||||
if (i != end || lastLineHasText)
|
||||
self.replaceRange(lead + pad, Pos(i, 0));
|
||||
} else {
|
||||
self.replaceRange(endString, to);
|
||||
self.replaceRange(startString, from);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("uncomment", function(from, to, options) {
|
||||
if (!options) options = noOptions;
|
||||
var self = this, mode = self.getModeAt(from);
|
||||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end);
|
||||
|
||||
// Try finding line comments
|
||||
var lineString = options.lineComment || mode.lineComment, lines = [];
|
||||
var pad = options.padding == null ? " " : options.padding, didSomething;
|
||||
lineComment: {
|
||||
if (!lineString) break lineComment;
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = self.getLine(i);
|
||||
var found = line.indexOf(lineString);
|
||||
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1;
|
||||
if (found == -1 && nonWS.test(line)) break lineComment;
|
||||
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment;
|
||||
lines.push(line);
|
||||
}
|
||||
self.operation(function() {
|
||||
for (var i = start; i <= end; ++i) {
|
||||
var line = lines[i - start];
|
||||
var pos = line.indexOf(lineString), endPos = pos + lineString.length;
|
||||
if (pos < 0) continue;
|
||||
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length;
|
||||
didSomething = true;
|
||||
self.replaceRange("", Pos(i, pos), Pos(i, endPos));
|
||||
}
|
||||
});
|
||||
if (didSomething) return true;
|
||||
}
|
||||
|
||||
// Try block comments
|
||||
var startString = options.blockCommentStart || mode.blockCommentStart;
|
||||
var endString = options.blockCommentEnd || mode.blockCommentEnd;
|
||||
if (!startString || !endString) return false;
|
||||
var lead = options.blockCommentLead || mode.blockCommentLead;
|
||||
var startLine = self.getLine(start), open = startLine.indexOf(startString)
|
||||
if (open == -1) return false
|
||||
var endLine = end == start ? startLine : self.getLine(end)
|
||||
var close = endLine.indexOf(endString, end == start ? open + startString.length : 0);
|
||||
if (close == -1 && start != end) {
|
||||
endLine = self.getLine(--end);
|
||||
close = endLine.indexOf(endString);
|
||||
}
|
||||
if (close == -1 ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(start, open + 1))) ||
|
||||
!/comment/.test(self.getTokenTypeAt(Pos(end, close + 1))))
|
||||
return false;
|
||||
|
||||
// Avoid killing block comments completely outside the selection.
|
||||
// Positions of the last startString before the start of the selection, and the first endString after it.
|
||||
var lastStart = startLine.lastIndexOf(startString, from.ch);
|
||||
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length);
|
||||
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false;
|
||||
// Positions of the first endString after the end of the selection, and the last startString before it.
|
||||
firstEnd = endLine.indexOf(endString, to.ch);
|
||||
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch);
|
||||
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart;
|
||||
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false;
|
||||
|
||||
self.operation(function() {
|
||||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)),
|
||||
Pos(end, close + endString.length));
|
||||
var openEnd = open + startString.length;
|
||||
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length;
|
||||
self.replaceRange("", Pos(start, open), Pos(start, openEnd));
|
||||
if (lead) for (var i = start + 1; i <= end; ++i) {
|
||||
var line = self.getLine(i), found = line.indexOf(lead);
|
||||
if (found == -1 || nonWS.test(line.slice(0, found))) continue;
|
||||
var foundEnd = found + lead.length;
|
||||
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length;
|
||||
self.replaceRange("", Pos(i, found), Pos(i, foundEnd));
|
||||
}
|
||||
});
|
||||
return true;
|
||||
});
|
||||
});
|
85
BrowserMark/js/codemirror/addon/comment/continuecomment.js
vendored
Normal file
@ -0,0 +1,85 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
var modes = ["clike", "css", "javascript"];
|
||||
|
||||
for (var i = 0; i < modes.length; ++i)
|
||||
CodeMirror.extendMode(modes[i], {blockCommentContinue: " * "});
|
||||
|
||||
function continueComment(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), mode, inserts = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var pos = ranges[i].head, token = cm.getTokenAt(pos);
|
||||
if (token.type != "comment") return CodeMirror.Pass;
|
||||
var modeHere = CodeMirror.innerMode(cm.getMode(), token.state).mode;
|
||||
if (!mode) mode = modeHere;
|
||||
else if (mode != modeHere) return CodeMirror.Pass;
|
||||
|
||||
var insert = null;
|
||||
if (mode.blockCommentStart && mode.blockCommentContinue) {
|
||||
var end = token.string.indexOf(mode.blockCommentEnd);
|
||||
var full = cm.getRange(CodeMirror.Pos(pos.line, 0), CodeMirror.Pos(pos.line, token.end)), found;
|
||||
if (end != -1 && end == token.string.length - mode.blockCommentEnd.length && pos.ch >= end) {
|
||||
// Comment ended, don't continue it
|
||||
} else if (token.string.indexOf(mode.blockCommentStart) == 0) {
|
||||
insert = full.slice(0, token.start);
|
||||
if (!/^\s*$/.test(insert)) {
|
||||
insert = "";
|
||||
for (var j = 0; j < token.start; ++j) insert += " ";
|
||||
}
|
||||
} else if ((found = full.indexOf(mode.blockCommentContinue)) != -1 &&
|
||||
found + mode.blockCommentContinue.length > token.start &&
|
||||
/^\s*$/.test(full.slice(0, found))) {
|
||||
insert = full.slice(0, found);
|
||||
}
|
||||
if (insert != null) insert += mode.blockCommentContinue;
|
||||
}
|
||||
if (insert == null && mode.lineComment && continueLineCommentEnabled(cm)) {
|
||||
var line = cm.getLine(pos.line), found = line.indexOf(mode.lineComment);
|
||||
if (found > -1) {
|
||||
insert = line.slice(0, found);
|
||||
if (/\S/.test(insert)) insert = null;
|
||||
else insert += mode.lineComment + line.slice(found + mode.lineComment.length).match(/^\s*/)[0];
|
||||
}
|
||||
}
|
||||
if (insert == null) return CodeMirror.Pass;
|
||||
inserts[i] = "\n" + insert;
|
||||
}
|
||||
|
||||
cm.operation(function() {
|
||||
for (var i = ranges.length - 1; i >= 0; i--)
|
||||
cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert");
|
||||
});
|
||||
}
|
||||
|
||||
function continueLineCommentEnabled(cm) {
|
||||
var opt = cm.getOption("continueComments");
|
||||
if (opt && typeof opt == "object")
|
||||
return opt.continueLineComment !== false;
|
||||
return true;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("continueComments", null, function(cm, val, prev) {
|
||||
if (prev && prev != CodeMirror.Init)
|
||||
cm.removeKeyMap("continueComment");
|
||||
if (val) {
|
||||
var key = "Enter";
|
||||
if (typeof val == "string")
|
||||
key = val;
|
||||
else if (typeof val == "object" && val.key)
|
||||
key = val.key;
|
||||
var map = {name: "continueComment"};
|
||||
map[key] = continueComment;
|
||||
cm.addKeyMap(map);
|
||||
}
|
||||
});
|
||||
});
|
32
BrowserMark/js/codemirror/addon/dialog/dialog.css
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
.CodeMirror-dialog {
|
||||
position: absolute;
|
||||
left: 0; right: 0;
|
||||
background: inherit;
|
||||
z-index: 15;
|
||||
padding: .1em .8em;
|
||||
overflow: hidden;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-top {
|
||||
border-bottom: 1px solid #eee;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog-bottom {
|
||||
border-top: 1px solid #eee;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog input {
|
||||
border: none;
|
||||
outline: none;
|
||||
background: transparent;
|
||||
width: 20em;
|
||||
color: inherit;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.CodeMirror-dialog button {
|
||||
font-size: 70%;
|
||||
}
|
157
BrowserMark/js/codemirror/addon/dialog/dialog.js
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
function dialogDiv(cm, template, bottom) {
|
||||
var wrap = cm.getWrapperElement();
|
||||
var dialog;
|
||||
dialog = wrap.appendChild(document.createElement("div"));
|
||||
if (bottom)
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom";
|
||||
else
|
||||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top";
|
||||
|
||||
if (typeof template == "string") {
|
||||
dialog.innerHTML = template;
|
||||
} else { // Assuming it's a detached DOM element.
|
||||
dialog.appendChild(template);
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function closeNotification(cm, newVal) {
|
||||
if (cm.state.currentNotificationClose)
|
||||
cm.state.currentNotificationClose();
|
||||
cm.state.currentNotificationClose = newVal;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("openDialog", function(template, callback, options) {
|
||||
if (!options) options = {};
|
||||
|
||||
closeNotification(this, null);
|
||||
|
||||
var dialog = dialogDiv(this, template, options.bottom);
|
||||
var closed = false, me = this;
|
||||
function close(newVal) {
|
||||
if (typeof newVal == 'string') {
|
||||
inp.value = newVal;
|
||||
} else {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
|
||||
if (options.onClose) options.onClose(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
var inp = dialog.getElementsByTagName("input")[0], button;
|
||||
if (inp) {
|
||||
inp.focus();
|
||||
|
||||
if (options.value) {
|
||||
inp.value = options.value;
|
||||
if (options.selectValueOnOpen !== false) {
|
||||
inp.select();
|
||||
}
|
||||
}
|
||||
|
||||
if (options.onInput)
|
||||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);});
|
||||
if (options.onKeyUp)
|
||||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);});
|
||||
|
||||
CodeMirror.on(inp, "keydown", function(e) {
|
||||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; }
|
||||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) {
|
||||
inp.blur();
|
||||
CodeMirror.e_stop(e);
|
||||
close();
|
||||
}
|
||||
if (e.keyCode == 13) callback(inp.value, e);
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(inp, "blur", close);
|
||||
} else if (button = dialog.getElementsByTagName("button")[0]) {
|
||||
CodeMirror.on(button, "click", function() {
|
||||
close();
|
||||
me.focus();
|
||||
});
|
||||
|
||||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close);
|
||||
|
||||
button.focus();
|
||||
}
|
||||
return close;
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) {
|
||||
closeNotification(this, null);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var buttons = dialog.getElementsByTagName("button");
|
||||
var closed = false, me = this, blurring = 1;
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
me.focus();
|
||||
}
|
||||
buttons[0].focus();
|
||||
for (var i = 0; i < buttons.length; ++i) {
|
||||
var b = buttons[i];
|
||||
(function(callback) {
|
||||
CodeMirror.on(b, "click", function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
if (callback) callback(me);
|
||||
});
|
||||
})(callbacks[i]);
|
||||
CodeMirror.on(b, "blur", function() {
|
||||
--blurring;
|
||||
setTimeout(function() { if (blurring <= 0) close(); }, 200);
|
||||
});
|
||||
CodeMirror.on(b, "focus", function() { ++blurring; });
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* openNotification
|
||||
* Opens a notification, that can be closed with an optional timer
|
||||
* (default 5000ms timer) and always closes on click.
|
||||
*
|
||||
* If a notification is opened while another is opened, it will close the
|
||||
* currently opened one and open the new one immediately.
|
||||
*/
|
||||
CodeMirror.defineExtension("openNotification", function(template, options) {
|
||||
closeNotification(this, close);
|
||||
var dialog = dialogDiv(this, template, options && options.bottom);
|
||||
var closed = false, doneTimer;
|
||||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000;
|
||||
|
||||
function close() {
|
||||
if (closed) return;
|
||||
closed = true;
|
||||
clearTimeout(doneTimer);
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
}
|
||||
|
||||
CodeMirror.on(dialog, 'click', function(e) {
|
||||
CodeMirror.e_preventDefault(e);
|
||||
close();
|
||||
});
|
||||
|
||||
if (duration)
|
||||
doneTimer = setTimeout(close, duration);
|
||||
|
||||
return close;
|
||||
});
|
||||
});
|
202
BrowserMark/js/codemirror/addon/edit/closebrackets.js
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
var defaults = {
|
||||
pairs: "()[]{}''\"\"",
|
||||
triples: "",
|
||||
explode: "[]{}"
|
||||
};
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.removeKeyMap(keyMap);
|
||||
cm.state.closeBrackets = null;
|
||||
}
|
||||
if (val) {
|
||||
cm.state.closeBrackets = val;
|
||||
cm.addKeyMap(keyMap);
|
||||
}
|
||||
});
|
||||
|
||||
function getOption(conf, name) {
|
||||
if (name == "pairs" && typeof conf == "string") return conf;
|
||||
if (typeof conf == "object" && conf[name] != null) return conf[name];
|
||||
return defaults[name];
|
||||
}
|
||||
|
||||
var bind = defaults.pairs + "`";
|
||||
var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
|
||||
for (var i = 0; i < bind.length; i++)
|
||||
keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
|
||||
|
||||
function handler(ch) {
|
||||
return function(cm) { return handleChar(cm, ch); };
|
||||
}
|
||||
|
||||
function getConfig(cm) {
|
||||
var deflt = cm.state.closeBrackets;
|
||||
if (!deflt) return null;
|
||||
var mode = cm.getModeAt(cm.getCursor());
|
||||
return mode.closeBrackets || deflt;
|
||||
}
|
||||
|
||||
function handleBackspace(cm) {
|
||||
var conf = getConfig(cm);
|
||||
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
|
||||
var pairs = getOption(conf, "pairs");
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var around = charsAround(cm, ranges[i].head);
|
||||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
}
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var cur = ranges[i].head;
|
||||
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete");
|
||||
}
|
||||
}
|
||||
|
||||
function handleEnter(cm) {
|
||||
var conf = getConfig(cm);
|
||||
var explode = conf && getOption(conf, "explode");
|
||||
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var around = charsAround(cm, ranges[i].head);
|
||||
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
|
||||
}
|
||||
cm.operation(function() {
|
||||
cm.replaceSelection("\n\n", null);
|
||||
cm.execCommand("goCharLeft");
|
||||
ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var line = ranges[i].head.line;
|
||||
cm.indentLine(line, null, true);
|
||||
cm.indentLine(line + 1, null, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function contractSelection(sel) {
|
||||
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0;
|
||||
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)),
|
||||
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))};
|
||||
}
|
||||
|
||||
function handleChar(cm, ch) {
|
||||
var conf = getConfig(cm);
|
||||
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
|
||||
var pairs = getOption(conf, "pairs");
|
||||
var pos = pairs.indexOf(ch);
|
||||
if (pos == -1) return CodeMirror.Pass;
|
||||
var triples = getOption(conf, "triples");
|
||||
|
||||
var identical = pairs.charAt(pos + 1) == ch;
|
||||
var ranges = cm.listSelections();
|
||||
var opening = pos % 2 == 0;
|
||||
|
||||
var type;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i], cur = range.head, curType;
|
||||
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
|
||||
if (opening && !range.empty()) {
|
||||
curType = "surround";
|
||||
} else if ((identical || !opening) && next == ch) {
|
||||
if (identical && stringStartsAfter(cm, cur))
|
||||
curType = "both";
|
||||
else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
|
||||
curType = "skipThree";
|
||||
else
|
||||
curType = "skip";
|
||||
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
|
||||
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
|
||||
(cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
|
||||
curType = "addFour";
|
||||
} else if (identical) {
|
||||
if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
|
||||
else return CodeMirror.Pass;
|
||||
} else if (opening && (cm.getLine(cur.line).length == cur.ch ||
|
||||
isClosingBracket(next, pairs) ||
|
||||
/\s/.test(next))) {
|
||||
curType = "both";
|
||||
} else {
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
if (!type) type = curType;
|
||||
else if (type != curType) return CodeMirror.Pass;
|
||||
}
|
||||
|
||||
var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
|
||||
var right = pos % 2 ? ch : pairs.charAt(pos + 1);
|
||||
cm.operation(function() {
|
||||
if (type == "skip") {
|
||||
cm.execCommand("goCharRight");
|
||||
} else if (type == "skipThree") {
|
||||
for (var i = 0; i < 3; i++)
|
||||
cm.execCommand("goCharRight");
|
||||
} else if (type == "surround") {
|
||||
var sels = cm.getSelections();
|
||||
for (var i = 0; i < sels.length; i++)
|
||||
sels[i] = left + sels[i] + right;
|
||||
cm.replaceSelections(sels, "around");
|
||||
sels = cm.listSelections().slice();
|
||||
for (var i = 0; i < sels.length; i++)
|
||||
sels[i] = contractSelection(sels[i]);
|
||||
cm.setSelections(sels);
|
||||
} else if (type == "both") {
|
||||
cm.replaceSelection(left + right, null);
|
||||
cm.triggerElectric(left + right);
|
||||
cm.execCommand("goCharLeft");
|
||||
} else if (type == "addFour") {
|
||||
cm.replaceSelection(left + left + left + left, "before");
|
||||
cm.execCommand("goCharRight");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function isClosingBracket(ch, pairs) {
|
||||
var pos = pairs.lastIndexOf(ch);
|
||||
return pos > -1 && pos % 2 == 1;
|
||||
}
|
||||
|
||||
function charsAround(cm, pos) {
|
||||
var str = cm.getRange(Pos(pos.line, pos.ch - 1),
|
||||
Pos(pos.line, pos.ch + 1));
|
||||
return str.length == 2 ? str : null;
|
||||
}
|
||||
|
||||
// Project the token type that will exists after the given char is
|
||||
// typed, and use it to determine whether it would cause the start
|
||||
// of a string token.
|
||||
function enteringString(cm, pos, ch) {
|
||||
var line = cm.getLine(pos.line);
|
||||
var token = cm.getTokenAt(pos);
|
||||
if (/\bstring2?\b/.test(token.type)) return false;
|
||||
var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
|
||||
stream.pos = stream.start = token.start;
|
||||
for (;;) {
|
||||
var type1 = cm.getMode().token(stream, token.state);
|
||||
if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
|
||||
stream.start = stream.pos;
|
||||
}
|
||||
}
|
||||
|
||||
function stringStartsAfter(cm, pos) {
|
||||
var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1))
|
||||
return /\bstring/.test(token.type) && token.start == pos.ch
|
||||
}
|
||||
});
|
169
BrowserMark/js/codemirror/addon/edit/closetag.js
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
/**
|
||||
* Tag-closer extension for CodeMirror.
|
||||
*
|
||||
* This extension adds an "autoCloseTags" option that can be set to
|
||||
* either true to get the default behavior, or an object to further
|
||||
* configure its behavior.
|
||||
*
|
||||
* These are supported options:
|
||||
*
|
||||
* `whenClosing` (default true)
|
||||
* Whether to autoclose when the '/' of a closing tag is typed.
|
||||
* `whenOpening` (default true)
|
||||
* Whether to autoclose the tag when the final '>' of an opening
|
||||
* tag is typed.
|
||||
* `dontCloseTags` (default is empty tags for HTML, none for XML)
|
||||
* An array of tag names that should not be autoclosed.
|
||||
* `indentTags` (default is block tags for HTML, none for XML)
|
||||
* An array of tag names that should, when opened, cause a
|
||||
* blank line to be added inside the tag, and the blank line and
|
||||
* closing line to be indented.
|
||||
*
|
||||
* See demos/closetag.html for a usage example.
|
||||
*/
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) {
|
||||
if (old != CodeMirror.Init && old)
|
||||
cm.removeKeyMap("autoCloseTags");
|
||||
if (!val) return;
|
||||
var map = {name: "autoCloseTags"};
|
||||
if (typeof val != "object" || val.whenClosing)
|
||||
map["'/'"] = function(cm) { return autoCloseSlash(cm); };
|
||||
if (typeof val != "object" || val.whenOpening)
|
||||
map["'>'"] = function(cm) { return autoCloseGT(cm); };
|
||||
cm.addKeyMap(map);
|
||||
});
|
||||
|
||||
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param",
|
||||
"source", "track", "wbr"];
|
||||
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4",
|
||||
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"];
|
||||
|
||||
function autoCloseGT(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (inner.mode.name != "xml" || !state.tagName) return CodeMirror.Pass;
|
||||
|
||||
var opt = cm.getOption("autoCloseTags"), html = inner.mode.configuration == "html";
|
||||
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose);
|
||||
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent);
|
||||
|
||||
var tagName = state.tagName;
|
||||
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch);
|
||||
var lowerTagName = tagName.toLowerCase();
|
||||
// Don't process the '>' at the end of an end-tag or self-closing tag
|
||||
if (!tagName ||
|
||||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) ||
|
||||
tok.type == "tag" && state.type == "closeTag" ||
|
||||
tok.string.indexOf("/") == (tok.string.length - 1) || // match something like <someTagName />
|
||||
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 ||
|
||||
closingTagExists(cm, tagName, pos, state, true))
|
||||
return CodeMirror.Pass;
|
||||
|
||||
var indent = indentTags && indexOf(indentTags, lowerTagName) > -1;
|
||||
replacements[i] = {indent: indent,
|
||||
text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">",
|
||||
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)};
|
||||
}
|
||||
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var info = replacements[i];
|
||||
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert");
|
||||
var sel = cm.listSelections().slice(0);
|
||||
sel[i] = {head: info.newPos, anchor: info.newPos};
|
||||
cm.setSelections(sel);
|
||||
if (info.indent) {
|
||||
cm.indentLine(info.newPos.line, null, true);
|
||||
cm.indentLine(info.newPos.line + 1, null, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function autoCloseCurrent(cm, typingSlash) {
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
var head = typingSlash ? "/" : "</";
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
if (!ranges[i].empty()) return CodeMirror.Pass;
|
||||
var pos = ranges[i].head, tok = cm.getTokenAt(pos);
|
||||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state;
|
||||
if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" ||
|
||||
tok.start != pos.ch - 1))
|
||||
return CodeMirror.Pass;
|
||||
// Kludge to get around the fact that we are not in XML mode
|
||||
// when completing in JS/CSS snippet in htmlmixed mode. Does not
|
||||
// work for other XML embedded languages (there is no general
|
||||
// way to go from a mixed mode to its current XML state).
|
||||
var replacement;
|
||||
if (inner.mode.name != "xml") {
|
||||
if (cm.getMode().name == "htmlmixed" && inner.mode.name == "javascript")
|
||||
replacement = head + "script";
|
||||
else if (cm.getMode().name == "htmlmixed" && inner.mode.name == "css")
|
||||
replacement = head + "style";
|
||||
else
|
||||
return CodeMirror.Pass;
|
||||
} else {
|
||||
if (!state.context || !state.context.tagName ||
|
||||
closingTagExists(cm, state.context.tagName, pos, state))
|
||||
return CodeMirror.Pass;
|
||||
replacement = head + state.context.tagName;
|
||||
}
|
||||
if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">";
|
||||
replacements[i] = replacement;
|
||||
}
|
||||
cm.replaceSelections(replacements);
|
||||
ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++)
|
||||
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line)
|
||||
cm.indentLine(ranges[i].head.line);
|
||||
}
|
||||
|
||||
function autoCloseSlash(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
return autoCloseCurrent(cm, true);
|
||||
}
|
||||
|
||||
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); };
|
||||
|
||||
function indexOf(collection, elt) {
|
||||
if (collection.indexOf) return collection.indexOf(elt);
|
||||
for (var i = 0, e = collection.length; i < e; ++i)
|
||||
if (collection[i] == elt) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If xml-fold is loaded, we use its functionality to try and verify
|
||||
// whether a given tag is actually unclosed.
|
||||
function closingTagExists(cm, tagName, pos, state, newTag) {
|
||||
if (!CodeMirror.scanForClosingTag) return false;
|
||||
var end = Math.min(cm.lastLine() + 1, pos.line + 500);
|
||||
var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end);
|
||||
if (!nextClose || nextClose.tag != tagName) return false;
|
||||
var cx = state.context;
|
||||
// If the immediate wrapping context contains onCx instances of
|
||||
// the same tag, a closing tag only exists if there are at least
|
||||
// that many closing tags of that type following.
|
||||
for (var onCx = newTag ? 1 : 0; cx && cx.tagName == tagName; cx = cx.prev) ++onCx;
|
||||
pos = nextClose.to;
|
||||
for (var i = 1; i < onCx; i++) {
|
||||
var next = CodeMirror.scanForClosingTag(cm, pos, null, end);
|
||||
if (!next || next.tag != tagName) return false;
|
||||
pos = next.to;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
51
BrowserMark/js/codemirror/addon/edit/continuelist.js
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var listRE = /^(\s*)(>[> ]*|- \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/,
|
||||
emptyListRE = /^(\s*)(>[> ]*|- \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/,
|
||||
unorderedListRE = /[*+-]\s/;
|
||||
|
||||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
|
||||
if (cm.getOption("disableInput")) return CodeMirror.Pass;
|
||||
var ranges = cm.listSelections(), replacements = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var pos = ranges[i].head;
|
||||
var eolState = cm.getStateAfter(pos.line);
|
||||
var inList = eolState.list !== false;
|
||||
var inQuote = eolState.quote !== 0;
|
||||
|
||||
var line = cm.getLine(pos.line), match = listRE.exec(line);
|
||||
if (!ranges[i].empty() || (!inList && !inQuote) || !match) {
|
||||
cm.execCommand("newlineAndIndent");
|
||||
return;
|
||||
}
|
||||
if (emptyListRE.test(line)) {
|
||||
cm.replaceRange("", {
|
||||
line: pos.line, ch: 0
|
||||
}, {
|
||||
line: pos.line, ch: pos.ch + 1
|
||||
});
|
||||
replacements[i] = "\n";
|
||||
} else {
|
||||
var indent = match[1], after = match[5];
|
||||
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
|
||||
? match[2].replace("x", " ")
|
||||
: (parseInt(match[3], 10) + 1) + match[4];
|
||||
|
||||
replacements[i] = "\n" + indent + bullet + after;
|
||||
}
|
||||
}
|
||||
|
||||
cm.replaceSelections(replacements);
|
||||
};
|
||||
});
|
122
BrowserMark/js/codemirror/addon/edit/matchbrackets.js
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
|
||||
(document.documentMode == null || document.documentMode < 8);
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
|
||||
|
||||
function findMatchingBracket(cm, where, strict, config) {
|
||||
var line = cm.getLineHandle(where.line), pos = where.ch - 1;
|
||||
var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
|
||||
if (!match) return null;
|
||||
var dir = match.charAt(1) == ">" ? 1 : -1;
|
||||
if (strict && (dir > 0) != (pos == where.ch)) return null;
|
||||
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
|
||||
|
||||
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
|
||||
if (found == null) return null;
|
||||
return {from: Pos(where.line, pos), to: found && found.pos,
|
||||
match: found && found.ch == match.charAt(0), forward: dir > 0};
|
||||
}
|
||||
|
||||
// bracketRegex is used to specify which type of bracket to scan
|
||||
// should be a regexp, e.g. /[[\]]/
|
||||
//
|
||||
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
||||
//
|
||||
// Returns false when no bracket was found, null when it reached
|
||||
// maxScanLines and gave up
|
||||
function scanForBracket(cm, where, dir, style, config) {
|
||||
var maxScanLen = (config && config.maxScanLineLength) || 10000;
|
||||
var maxScanLines = (config && config.maxScanLines) || 1000;
|
||||
|
||||
var stack = [];
|
||||
var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
|
||||
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
|
||||
: Math.max(cm.firstLine() - 1, where.line - maxScanLines);
|
||||
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
|
||||
var line = cm.getLine(lineNo);
|
||||
if (!line) continue;
|
||||
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
|
||||
if (line.length > maxScanLen) continue;
|
||||
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
|
||||
for (; pos != end; pos += dir) {
|
||||
var ch = line.charAt(pos);
|
||||
if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
|
||||
var match = matching[ch];
|
||||
if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
|
||||
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
|
||||
else stack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
|
||||
}
|
||||
|
||||
function matchBrackets(cm, autoclear, config) {
|
||||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
||||
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
|
||||
var marks = [], ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
|
||||
if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
|
||||
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
|
||||
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
|
||||
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
|
||||
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
|
||||
}
|
||||
}
|
||||
|
||||
if (marks.length) {
|
||||
// Kludge to work around the IE bug from issue #1193, where text
|
||||
// input stops going to the textare whever this fires.
|
||||
if (ie_lt8 && cm.state.focused) cm.focus();
|
||||
|
||||
var clear = function() {
|
||||
cm.operation(function() {
|
||||
for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||||
});
|
||||
};
|
||||
if (autoclear) setTimeout(clear, 800);
|
||||
else return clear;
|
||||
}
|
||||
}
|
||||
|
||||
var currentlyHighlighted = null;
|
||||
function doMatchBrackets(cm) {
|
||||
cm.operation(function() {
|
||||
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
|
||||
currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchBrackets);
|
||||
if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchBrackets = typeof val == "object" ? val : {};
|
||||
cm.on("cursorActivity", doMatchBrackets);
|
||||
}
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
|
||||
CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
|
||||
return findMatchingBracket(this, pos, strict, config);
|
||||
});
|
||||
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
|
||||
return scanForBracket(this, pos, dir, style, config);
|
||||
});
|
||||
});
|
66
BrowserMark/js/codemirror/addon/edit/matchtags.js
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../fold/xml-fold"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../fold/xml-fold"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("matchTags", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.off("cursorActivity", doMatchTags);
|
||||
cm.off("viewportChange", maybeUpdateMatch);
|
||||
clear(cm);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.matchBothTags = typeof val == "object" && val.bothTags;
|
||||
cm.on("cursorActivity", doMatchTags);
|
||||
cm.on("viewportChange", maybeUpdateMatch);
|
||||
doMatchTags(cm);
|
||||
}
|
||||
});
|
||||
|
||||
function clear(cm) {
|
||||
if (cm.state.tagHit) cm.state.tagHit.clear();
|
||||
if (cm.state.tagOther) cm.state.tagOther.clear();
|
||||
cm.state.tagHit = cm.state.tagOther = null;
|
||||
}
|
||||
|
||||
function doMatchTags(cm) {
|
||||
cm.state.failedTagMatch = false;
|
||||
cm.operation(function() {
|
||||
clear(cm);
|
||||
if (cm.somethingSelected()) return;
|
||||
var cur = cm.getCursor(), range = cm.getViewport();
|
||||
range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to);
|
||||
var match = CodeMirror.findMatchingTag(cm, cur, range);
|
||||
if (!match) return;
|
||||
if (cm.state.matchBothTags) {
|
||||
var hit = match.at == "open" ? match.open : match.close;
|
||||
if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"});
|
||||
}
|
||||
var other = match.at == "close" ? match.open : match.close;
|
||||
if (other)
|
||||
cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"});
|
||||
else
|
||||
cm.state.failedTagMatch = true;
|
||||
});
|
||||
}
|
||||
|
||||
function maybeUpdateMatch(cm) {
|
||||
if (cm.state.failedTagMatch) doMatchTags(cm);
|
||||
}
|
||||
|
||||
CodeMirror.commands.toMatchingTag = function(cm) {
|
||||
var found = CodeMirror.findMatchingTag(cm, cm.getCursor());
|
||||
if (found) {
|
||||
var other = found.at == "close" ? found.open : found.close;
|
||||
if (other) cm.extendSelection(other.to, other.from);
|
||||
}
|
||||
};
|
||||
});
|
27
BrowserMark/js/codemirror/addon/edit/trailingspace.js
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) {
|
||||
if (prev == CodeMirror.Init) prev = false;
|
||||
if (prev && !val)
|
||||
cm.removeOverlay("trailingspace");
|
||||
else if (!prev && val)
|
||||
cm.addOverlay({
|
||||
token: function(stream) {
|
||||
for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {}
|
||||
if (i > stream.pos) { stream.pos = i; return null; }
|
||||
stream.pos = l;
|
||||
return "trailingspace";
|
||||
},
|
||||
name: "trailingspace"
|
||||
});
|
||||
});
|
||||
});
|
105
BrowserMark/js/codemirror/addon/fold/brace-fold.js
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("fold", "brace", function(cm, start) {
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
var tokenType;
|
||||
|
||||
function findOpening(openCh) {
|
||||
for (var at = start.ch, pass = 0;;) {
|
||||
var found = at <= 0 ? -1 : lineText.lastIndexOf(openCh, at - 1);
|
||||
if (found == -1) {
|
||||
if (pass == 1) break;
|
||||
pass = 1;
|
||||
at = lineText.length;
|
||||
continue;
|
||||
}
|
||||
if (pass == 1 && found < start.ch) break;
|
||||
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1));
|
||||
if (!/^(comment|string)/.test(tokenType)) return found + 1;
|
||||
at = found - 1;
|
||||
}
|
||||
}
|
||||
|
||||
var startToken = "{", endToken = "}", startCh = findOpening("{");
|
||||
if (startCh == null) {
|
||||
startToken = "[", endToken = "]";
|
||||
startCh = findOpening("[");
|
||||
}
|
||||
|
||||
if (startCh == null) return;
|
||||
var count = 1, lastLine = cm.lastLine(), end, endCh;
|
||||
outer: for (var i = line; i <= lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
|
||||
if (nextOpen < 0) nextOpen = text.length;
|
||||
if (nextClose < 0) nextClose = text.length;
|
||||
pos = Math.min(nextOpen, nextClose);
|
||||
if (pos == text.length) break;
|
||||
if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == tokenType) {
|
||||
if (pos == nextOpen) ++count;
|
||||
else if (!--count) { end = i; endCh = pos; break outer; }
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || line == end && endCh == startCh) return;
|
||||
return {from: CodeMirror.Pos(line, startCh),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "import", function(cm, start) {
|
||||
function hasImport(line) {
|
||||
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
||||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
||||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
||||
if (start.type != "keyword" || start.string != "import") return null;
|
||||
// Now find closing semicolon, return its position
|
||||
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) {
|
||||
var text = cm.getLine(i), semi = text.indexOf(";");
|
||||
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)};
|
||||
}
|
||||
}
|
||||
|
||||
var startLine = start.line, has = hasImport(startLine), prev;
|
||||
if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1))
|
||||
return null;
|
||||
for (var end = has.end;;) {
|
||||
var next = hasImport(end.line + 1);
|
||||
if (next == null) break;
|
||||
end = next.end;
|
||||
}
|
||||
return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "include", function(cm, start) {
|
||||
function hasInclude(line) {
|
||||
if (line < cm.firstLine() || line > cm.lastLine()) return null;
|
||||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1));
|
||||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1));
|
||||
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8;
|
||||
}
|
||||
|
||||
var startLine = start.line, has = hasInclude(startLine);
|
||||
if (has == null || hasInclude(startLine - 1) != null) return null;
|
||||
for (var end = startLine;;) {
|
||||
var next = hasInclude(end + 1);
|
||||
if (next == null) break;
|
||||
++end;
|
||||
}
|
||||
return {from: CodeMirror.Pos(startLine, has + 1),
|
||||
to: cm.clipPos(CodeMirror.Pos(end))};
|
||||
});
|
||||
|
||||
});
|
59
BrowserMark/js/codemirror/addon/fold/comment-fold.js
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) {
|
||||
return mode.blockCommentStart && mode.blockCommentEnd;
|
||||
}, function(cm, start) {
|
||||
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd;
|
||||
if (!startToken || !endToken) return;
|
||||
var line = start.line, lineText = cm.getLine(line);
|
||||
|
||||
var startCh;
|
||||
for (var at = start.ch, pass = 0;;) {
|
||||
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1);
|
||||
if (found == -1) {
|
||||
if (pass == 1) return;
|
||||
pass = 1;
|
||||
at = lineText.length;
|
||||
continue;
|
||||
}
|
||||
if (pass == 1 && found < start.ch) return;
|
||||
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) &&
|
||||
(found == 0 || lineText.slice(found - endToken.length, found) == endToken ||
|
||||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) {
|
||||
startCh = found + startToken.length;
|
||||
break;
|
||||
}
|
||||
at = found - 1;
|
||||
}
|
||||
|
||||
var depth = 1, lastLine = cm.lastLine(), end, endCh;
|
||||
outer: for (var i = line; i <= lastLine; ++i) {
|
||||
var text = cm.getLine(i), pos = i == line ? startCh : 0;
|
||||
for (;;) {
|
||||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos);
|
||||
if (nextOpen < 0) nextOpen = text.length;
|
||||
if (nextClose < 0) nextClose = text.length;
|
||||
pos = Math.min(nextOpen, nextClose);
|
||||
if (pos == text.length) break;
|
||||
if (pos == nextOpen) ++depth;
|
||||
else if (!--depth) { end = i; endCh = pos; break outer; }
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
if (end == null || line == end && endCh == startCh) return;
|
||||
return {from: CodeMirror.Pos(line, startCh),
|
||||
to: CodeMirror.Pos(end, endCh)};
|
||||
});
|
||||
|
||||
});
|
150
BrowserMark/js/codemirror/addon/fold/foldcode.js
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function doFold(cm, pos, options, force) {
|
||||
if (options && options.call) {
|
||||
var finder = options;
|
||||
options = null;
|
||||
} else {
|
||||
var finder = getOption(cm, options, "rangeFinder");
|
||||
}
|
||||
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0);
|
||||
var minSize = getOption(cm, options, "minFoldSize");
|
||||
|
||||
function getRange(allowFolded) {
|
||||
var range = finder(cm, pos);
|
||||
if (!range || range.to.line - range.from.line < minSize) return null;
|
||||
var marks = cm.findMarksAt(range.from);
|
||||
for (var i = 0; i < marks.length; ++i) {
|
||||
if (marks[i].__isFold && force !== "fold") {
|
||||
if (!allowFolded) return null;
|
||||
range.cleared = true;
|
||||
marks[i].clear();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
var range = getRange(true);
|
||||
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) {
|
||||
pos = CodeMirror.Pos(pos.line - 1, 0);
|
||||
range = getRange(false);
|
||||
}
|
||||
if (!range || range.cleared || force === "unfold") return;
|
||||
|
||||
var myWidget = makeWidget(cm, options);
|
||||
CodeMirror.on(myWidget, "mousedown", function(e) {
|
||||
myRange.clear();
|
||||
CodeMirror.e_preventDefault(e);
|
||||
});
|
||||
var myRange = cm.markText(range.from, range.to, {
|
||||
replacedWith: myWidget,
|
||||
clearOnEnter: getOption(cm, options, "clearOnEnter"),
|
||||
__isFold: true
|
||||
});
|
||||
myRange.on("clear", function(from, to) {
|
||||
CodeMirror.signal(cm, "unfold", cm, from, to);
|
||||
});
|
||||
CodeMirror.signal(cm, "fold", cm, range.from, range.to);
|
||||
}
|
||||
|
||||
function makeWidget(cm, options) {
|
||||
var widget = getOption(cm, options, "widget");
|
||||
if (typeof widget == "string") {
|
||||
var text = document.createTextNode(widget);
|
||||
widget = document.createElement("span");
|
||||
widget.appendChild(text);
|
||||
widget.className = "CodeMirror-foldmarker";
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
// Clumsy backwards-compatible interface
|
||||
CodeMirror.newFoldFunction = function(rangeFinder, widget) {
|
||||
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); };
|
||||
};
|
||||
|
||||
// New-style interface
|
||||
CodeMirror.defineExtension("foldCode", function(pos, options, force) {
|
||||
doFold(this, pos, options, force);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("isFolded", function(pos) {
|
||||
var marks = this.findMarksAt(pos);
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold) return true;
|
||||
});
|
||||
|
||||
CodeMirror.commands.toggleFold = function(cm) {
|
||||
cm.foldCode(cm.getCursor());
|
||||
};
|
||||
CodeMirror.commands.fold = function(cm) {
|
||||
cm.foldCode(cm.getCursor(), null, "fold");
|
||||
};
|
||||
CodeMirror.commands.unfold = function(cm) {
|
||||
cm.foldCode(cm.getCursor(), null, "unfold");
|
||||
};
|
||||
CodeMirror.commands.foldAll = function(cm) {
|
||||
cm.operation(function() {
|
||||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), null, "fold");
|
||||
});
|
||||
};
|
||||
CodeMirror.commands.unfoldAll = function(cm) {
|
||||
cm.operation(function() {
|
||||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), null, "unfold");
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper("fold", "combine", function() {
|
||||
var funcs = Array.prototype.slice.call(arguments, 0);
|
||||
return function(cm, start) {
|
||||
for (var i = 0; i < funcs.length; ++i) {
|
||||
var found = funcs[i](cm, start);
|
||||
if (found) return found;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("fold", "auto", function(cm, start) {
|
||||
var helpers = cm.getHelpers(start, "fold");
|
||||
for (var i = 0; i < helpers.length; i++) {
|
||||
var cur = helpers[i](cm, start);
|
||||
if (cur) return cur;
|
||||
}
|
||||
});
|
||||
|
||||
var defaultOptions = {
|
||||
rangeFinder: CodeMirror.fold.auto,
|
||||
widget: "\u2194",
|
||||
minFoldSize: 0,
|
||||
scanUp: false,
|
||||
clearOnEnter: true
|
||||
};
|
||||
|
||||
CodeMirror.defineOption("foldOptions", null);
|
||||
|
||||
function getOption(cm, options, name) {
|
||||
if (options && options[name] !== undefined)
|
||||
return options[name];
|
||||
var editorOptions = cm.options.foldOptions;
|
||||
if (editorOptions && editorOptions[name] !== undefined)
|
||||
return editorOptions[name];
|
||||
return defaultOptions[name];
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("foldOption", function(options, name) {
|
||||
return getOption(this, options, name);
|
||||
});
|
||||
});
|
20
BrowserMark/js/codemirror/addon/fold/foldgutter.css
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
.CodeMirror-foldmarker {
|
||||
color: blue;
|
||||
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px;
|
||||
font-family: arial;
|
||||
line-height: .3;
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter {
|
||||
width: .7em;
|
||||
}
|
||||
.CodeMirror-foldgutter-open,
|
||||
.CodeMirror-foldgutter-folded {
|
||||
cursor: pointer;
|
||||
}
|
||||
.CodeMirror-foldgutter-open:after {
|
||||
content: "\25BE";
|
||||
}
|
||||
.CodeMirror-foldgutter-folded:after {
|
||||
content: "\25B8";
|
||||
}
|
146
BrowserMark/js/codemirror/addon/fold/foldgutter.js
vendored
Normal file
@ -0,0 +1,146 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./foldcode"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./foldcode"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
cm.clearGutter(cm.state.foldGutter.options.gutter);
|
||||
cm.state.foldGutter = null;
|
||||
cm.off("gutterClick", onGutterClick);
|
||||
cm.off("change", onChange);
|
||||
cm.off("viewportChange", onViewportChange);
|
||||
cm.off("fold", onFold);
|
||||
cm.off("unfold", onFold);
|
||||
cm.off("swapDoc", onChange);
|
||||
}
|
||||
if (val) {
|
||||
cm.state.foldGutter = new State(parseOptions(val));
|
||||
updateInViewport(cm);
|
||||
cm.on("gutterClick", onGutterClick);
|
||||
cm.on("change", onChange);
|
||||
cm.on("viewportChange", onViewportChange);
|
||||
cm.on("fold", onFold);
|
||||
cm.on("unfold", onFold);
|
||||
cm.on("swapDoc", onChange);
|
||||
}
|
||||
});
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function State(options) {
|
||||
this.options = options;
|
||||
this.from = this.to = 0;
|
||||
}
|
||||
|
||||
function parseOptions(opts) {
|
||||
if (opts === true) opts = {};
|
||||
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
|
||||
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
|
||||
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
|
||||
return opts;
|
||||
}
|
||||
|
||||
function isFolded(cm, line) {
|
||||
var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
|
||||
for (var i = 0; i < marks.length; ++i)
|
||||
if (marks[i].__isFold && marks[i].find().from.line == line) return marks[i];
|
||||
}
|
||||
|
||||
function marker(spec) {
|
||||
if (typeof spec == "string") {
|
||||
var elt = document.createElement("div");
|
||||
elt.className = spec + " CodeMirror-guttermarker-subtle";
|
||||
return elt;
|
||||
} else {
|
||||
return spec.cloneNode(true);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFoldInfo(cm, from, to) {
|
||||
var opts = cm.state.foldGutter.options, cur = from;
|
||||
var minSize = cm.foldOption(opts, "minFoldSize");
|
||||
var func = cm.foldOption(opts, "rangeFinder");
|
||||
cm.eachLine(from, to, function(line) {
|
||||
var mark = null;
|
||||
if (isFolded(cm, cur)) {
|
||||
mark = marker(opts.indicatorFolded);
|
||||
} else {
|
||||
var pos = Pos(cur, 0);
|
||||
var range = func && func(cm, pos);
|
||||
if (range && range.to.line - range.from.line >= minSize)
|
||||
mark = marker(opts.indicatorOpen);
|
||||
}
|
||||
cm.setGutterMarker(line, opts.gutter, mark);
|
||||
++cur;
|
||||
});
|
||||
}
|
||||
|
||||
function updateInViewport(cm) {
|
||||
var vp = cm.getViewport(), state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
cm.operation(function() {
|
||||
updateFoldInfo(cm, vp.from, vp.to);
|
||||
});
|
||||
state.from = vp.from; state.to = vp.to;
|
||||
}
|
||||
|
||||
function onGutterClick(cm, line, gutter) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var opts = state.options;
|
||||
if (gutter != opts.gutter) return;
|
||||
var folded = isFolded(cm, line);
|
||||
if (folded) folded.clear();
|
||||
else cm.foldCode(Pos(line, 0), opts.rangeFinder);
|
||||
}
|
||||
|
||||
function onChange(cm) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var opts = state.options;
|
||||
state.from = state.to = 0;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
|
||||
}
|
||||
|
||||
function onViewportChange(cm) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var opts = state.options;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function() {
|
||||
var vp = cm.getViewport();
|
||||
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
|
||||
updateInViewport(cm);
|
||||
} else {
|
||||
cm.operation(function() {
|
||||
if (vp.from < state.from) {
|
||||
updateFoldInfo(cm, vp.from, state.from);
|
||||
state.from = vp.from;
|
||||
}
|
||||
if (vp.to > state.to) {
|
||||
updateFoldInfo(cm, state.to, vp.to);
|
||||
state.to = vp.to;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, opts.updateViewportTimeSpan || 400);
|
||||
}
|
||||
|
||||
function onFold(cm, from) {
|
||||
var state = cm.state.foldGutter;
|
||||
if (!state) return;
|
||||
var line = from.line;
|
||||
if (line >= state.from && line < state.to)
|
||||
updateFoldInfo(cm, line, line + 1);
|
||||
}
|
||||
});
|
44
BrowserMark/js/codemirror/addon/fold/indent-fold.js
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("fold", "indent", function(cm, start) {
|
||||
var tabSize = cm.getOption("tabSize"), firstLine = cm.getLine(start.line);
|
||||
if (!/\S/.test(firstLine)) return;
|
||||
var getIndent = function(line) {
|
||||
return CodeMirror.countColumn(line, null, tabSize);
|
||||
};
|
||||
var myIndent = getIndent(firstLine);
|
||||
var lastLineInFold = null;
|
||||
// Go through lines until we find a line that definitely doesn't belong in
|
||||
// the block we're folding, or to the end.
|
||||
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) {
|
||||
var curLine = cm.getLine(i);
|
||||
var curIndent = getIndent(curLine);
|
||||
if (curIndent > myIndent) {
|
||||
// Lines with a greater indent are considered part of the block.
|
||||
lastLineInFold = i;
|
||||
} else if (!/\S/.test(curLine)) {
|
||||
// Empty lines might be breaks within the block we're trying to fold.
|
||||
} else {
|
||||
// A non-empty line at an indent equal to or less than ours marks the
|
||||
// start of another block.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastLineInFold) return {
|
||||
from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length)
|
||||
};
|
||||
});
|
||||
|
||||
});
|
49
BrowserMark/js/codemirror/addon/fold/markdown-fold.js
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.registerHelper("fold", "markdown", function(cm, start) {
|
||||
var maxDepth = 100;
|
||||
|
||||
function isHeader(lineNo) {
|
||||
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0));
|
||||
return tokentype && /\bheader\b/.test(tokentype);
|
||||
}
|
||||
|
||||
function headerLevel(lineNo, line, nextLine) {
|
||||
var match = line && line.match(/^#+/);
|
||||
if (match && isHeader(lineNo)) return match[0].length;
|
||||
match = nextLine && nextLine.match(/^[=\-]+\s*$/);
|
||||
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2;
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1);
|
||||
var level = headerLevel(start.line, firstLine, nextLine);
|
||||
if (level === maxDepth) return undefined;
|
||||
|
||||
var lastLineNo = cm.lastLine();
|
||||
var end = start.line, nextNextLine = cm.getLine(end + 2);
|
||||
while (end < lastLineNo) {
|
||||
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break;
|
||||
++end;
|
||||
nextLine = nextNextLine;
|
||||
nextNextLine = cm.getLine(end + 2);
|
||||
}
|
||||
|
||||
return {
|
||||
from: CodeMirror.Pos(start.line, firstLine.length),
|
||||
to: CodeMirror.Pos(end, cm.getLine(end).length)
|
||||
};
|
||||
});
|
||||
|
||||
});
|
182
BrowserMark/js/codemirror/addon/fold/xml-fold.js
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; }
|
||||
|
||||
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
||||
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
||||
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g");
|
||||
|
||||
function Iter(cm, line, ch, range) {
|
||||
this.line = line; this.ch = ch;
|
||||
this.cm = cm; this.text = cm.getLine(line);
|
||||
this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine();
|
||||
this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine();
|
||||
}
|
||||
|
||||
function tagAt(iter, ch) {
|
||||
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch));
|
||||
return type && /\btag\b/.test(type);
|
||||
}
|
||||
|
||||
function nextLine(iter) {
|
||||
if (iter.line >= iter.max) return;
|
||||
iter.ch = 0;
|
||||
iter.text = iter.cm.getLine(++iter.line);
|
||||
return true;
|
||||
}
|
||||
function prevLine(iter) {
|
||||
if (iter.line <= iter.min) return;
|
||||
iter.text = iter.cm.getLine(--iter.line);
|
||||
iter.ch = iter.text.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
function toTagEnd(iter) {
|
||||
for (;;) {
|
||||
var gt = iter.text.indexOf(">", iter.ch);
|
||||
if (gt == -1) { if (nextLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; }
|
||||
var lastSlash = iter.text.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
||||
iter.ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
function toTagStart(iter) {
|
||||
for (;;) {
|
||||
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1;
|
||||
if (lt == -1) { if (prevLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; }
|
||||
xmlTagStart.lastIndex = lt;
|
||||
iter.ch = lt;
|
||||
var match = xmlTagStart.exec(iter.text);
|
||||
if (match && match.index == lt) return match;
|
||||
}
|
||||
}
|
||||
|
||||
function toNextTag(iter) {
|
||||
for (;;) {
|
||||
xmlTagStart.lastIndex = iter.ch;
|
||||
var found = xmlTagStart.exec(iter.text);
|
||||
if (!found) { if (nextLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; }
|
||||
iter.ch = found.index + found[0].length;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
function toPrevTag(iter) {
|
||||
for (;;) {
|
||||
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1;
|
||||
if (gt == -1) { if (prevLine(iter)) continue; else return; }
|
||||
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; }
|
||||
var lastSlash = iter.text.lastIndexOf("/", gt);
|
||||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt));
|
||||
iter.ch = gt + 1;
|
||||
return selfClose ? "selfClose" : "regular";
|
||||
}
|
||||
}
|
||||
|
||||
function findMatchingClose(iter, tag) {
|
||||
var stack = [];
|
||||
for (;;) {
|
||||
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0);
|
||||
if (!next || !(end = toTagEnd(iter))) return;
|
||||
if (end == "selfClose") continue;
|
||||
if (next[1]) { // closing tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (i < 0 && (!tag || tag == next[2])) return {
|
||||
tag: next[2],
|
||||
from: Pos(startLine, startCh),
|
||||
to: Pos(iter.line, iter.ch)
|
||||
};
|
||||
} else { // opening tag
|
||||
stack.push(next[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function findMatchingOpen(iter, tag) {
|
||||
var stack = [];
|
||||
for (;;) {
|
||||
var prev = toPrevTag(iter);
|
||||
if (!prev) return;
|
||||
if (prev == "selfClose") { toTagStart(iter); continue; }
|
||||
var endLine = iter.line, endCh = iter.ch;
|
||||
var start = toTagStart(iter);
|
||||
if (!start) return;
|
||||
if (start[1]) { // closing tag
|
||||
stack.push(start[2]);
|
||||
} else { // opening tag
|
||||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) {
|
||||
stack.length = i;
|
||||
break;
|
||||
}
|
||||
if (i < 0 && (!tag || tag == start[2])) return {
|
||||
tag: start[2],
|
||||
from: Pos(iter.line, iter.ch),
|
||||
to: Pos(endLine, endCh)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.registerHelper("fold", "xml", function(cm, start) {
|
||||
var iter = new Iter(cm, start.line, 0);
|
||||
for (;;) {
|
||||
var openTag = toNextTag(iter), end;
|
||||
if (!openTag || iter.line != start.line || !(end = toTagEnd(iter))) return;
|
||||
if (!openTag[1] && end != "selfClose") {
|
||||
var startPos = Pos(iter.line, iter.ch);
|
||||
var endPos = findMatchingClose(iter, openTag[2]);
|
||||
return endPos && {from: startPos, to: endPos.from};
|
||||
}
|
||||
}
|
||||
});
|
||||
CodeMirror.findMatchingTag = function(cm, pos, range) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return;
|
||||
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch);
|
||||
var start = end && toTagStart(iter);
|
||||
if (!end || !start || cmp(iter, pos) > 0) return;
|
||||
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]};
|
||||
if (end == "selfClose") return {open: here, close: null, at: "open"};
|
||||
|
||||
if (start[1]) { // closing tag
|
||||
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"};
|
||||
} else { // opening tag
|
||||
iter = new Iter(cm, to.line, to.ch, range);
|
||||
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"};
|
||||
}
|
||||
};
|
||||
|
||||
CodeMirror.findEnclosingTag = function(cm, pos, range) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, range);
|
||||
for (;;) {
|
||||
var open = findMatchingOpen(iter);
|
||||
if (!open) break;
|
||||
var forward = new Iter(cm, pos.line, pos.ch, range);
|
||||
var close = findMatchingClose(forward, open.tag);
|
||||
if (close) return {open: open, close: close};
|
||||
}
|
||||
};
|
||||
|
||||
// Used by addon/edit/closetag.js
|
||||
CodeMirror.scanForClosingTag = function(cm, pos, name, end) {
|
||||
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null);
|
||||
return findMatchingClose(iter, name);
|
||||
};
|
||||
});
|
49
BrowserMark/js/codemirror/addon/search/jump-to-line.js
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Defines jumpToLine command. Uses dialog.js if present.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../dialog/dialog"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../dialog/dialog"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
|
||||
else f(prompt(shortText, deflt));
|
||||
}
|
||||
|
||||
var jumpDialog =
|
||||
'Jump to line: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use line:column or scroll% syntax)</span>';
|
||||
|
||||
function interpretLine(cm, string) {
|
||||
var num = Number(string)
|
||||
if (/^[-+]/.test(string)) return cm.getCursor().line + num
|
||||
else return num - 1
|
||||
}
|
||||
|
||||
CodeMirror.commands.jumpToLine = function(cm) {
|
||||
var cur = cm.getCursor();
|
||||
dialog(cm, jumpDialog, "Jump to line:", (cur.line + 1) + ":" + cur.ch, function(posStr) {
|
||||
if (!posStr) return;
|
||||
|
||||
var match;
|
||||
if (match = /^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(posStr)) {
|
||||
cm.setCursor(interpretLine(cm, match[1]), Number(match[2]))
|
||||
} else if (match = /^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(posStr)) {
|
||||
var line = Math.round(cm.lineCount() * Number(match[1]) / 100);
|
||||
if (/^[-+]/.test(match[1])) line = cur.line + line + 1;
|
||||
cm.setCursor(line - 1, cur.ch);
|
||||
} else if (match = /^\s*\:?\s*([\+\-]?\d+)\s*/.exec(posStr)) {
|
||||
cm.setCursor(interpretLine(cm, match[1]), cur.ch);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.keyMap["default"]["Alt-G"] = "jumpToLine";
|
||||
});
|
165
BrowserMark/js/codemirror/addon/search/match-highlighter.js
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Highlighting text that matches the selection
|
||||
//
|
||||
// Defines an option highlightSelectionMatches, which, when enabled,
|
||||
// will style strings that match the selection throughout the
|
||||
// document.
|
||||
//
|
||||
// The option can be set to true to simply enable it, or to a
|
||||
// {minChars, style, wordsOnly, showToken, delay} object to explicitly
|
||||
// configure it. minChars is the minimum amount of characters that should be
|
||||
// selected for the behavior to occur, and style is the token style to
|
||||
// apply to the matches. This will be prefixed by "cm-" to create an
|
||||
// actual CSS class name. If wordsOnly is enabled, the matches will be
|
||||
// highlighted only if the selected text is a word. showToken, when enabled,
|
||||
// will cause the current token to be highlighted when nothing is selected.
|
||||
// delay is used to specify how much time to wait, in milliseconds, before
|
||||
// highlighting the matches. If annotateScrollbar is enabled, the occurences
|
||||
// will be highlighted on the scrollbar via the matchesonscrollbar addon.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./matchesonscrollbar"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./matchesonscrollbar"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var defaults = {
|
||||
style: "matchhighlight",
|
||||
minChars: 2,
|
||||
delay: 100,
|
||||
wordsOnly: false,
|
||||
annotateScrollbar: false,
|
||||
showToken: false,
|
||||
trim: true
|
||||
}
|
||||
|
||||
function State(options) {
|
||||
this.options = {}
|
||||
for (var name in defaults)
|
||||
this.options[name] = (options && options.hasOwnProperty(name) ? options : defaults)[name]
|
||||
this.overlay = this.timeout = null;
|
||||
this.matchesonscroll = null;
|
||||
this.active = false;
|
||||
}
|
||||
|
||||
CodeMirror.defineOption("highlightSelectionMatches", false, function(cm, val, old) {
|
||||
if (old && old != CodeMirror.Init) {
|
||||
removeOverlay(cm);
|
||||
clearTimeout(cm.state.matchHighlighter.timeout);
|
||||
cm.state.matchHighlighter = null;
|
||||
cm.off("cursorActivity", cursorActivity);
|
||||
cm.off("focus", onFocus)
|
||||
}
|
||||
if (val) {
|
||||
var state = cm.state.matchHighlighter = new State(val);
|
||||
if (cm.hasFocus()) {
|
||||
state.active = true
|
||||
highlightMatches(cm)
|
||||
} else {
|
||||
cm.on("focus", onFocus)
|
||||
}
|
||||
cm.on("cursorActivity", cursorActivity);
|
||||
}
|
||||
});
|
||||
|
||||
function cursorActivity(cm) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
if (state.active || cm.hasFocus()) scheduleHighlight(cm, state)
|
||||
}
|
||||
|
||||
function onFocus(cm) {
|
||||
var state = cm.state.matchHighlighter
|
||||
if (!state.active) {
|
||||
state.active = true
|
||||
scheduleHighlight(cm, state)
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleHighlight(cm, state) {
|
||||
clearTimeout(state.timeout);
|
||||
state.timeout = setTimeout(function() {highlightMatches(cm);}, state.options.delay);
|
||||
}
|
||||
|
||||
function addOverlay(cm, query, hasBoundary, style) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
cm.addOverlay(state.overlay = makeOverlay(query, hasBoundary, style));
|
||||
if (state.options.annotateScrollbar && cm.showMatchesOnScrollbar) {
|
||||
var searchFor = hasBoundary ? new RegExp("\\b" + query + "\\b") : query;
|
||||
state.matchesonscroll = cm.showMatchesOnScrollbar(searchFor, false,
|
||||
{className: "CodeMirror-selection-highlight-scrollbar"});
|
||||
}
|
||||
}
|
||||
|
||||
function removeOverlay(cm) {
|
||||
var state = cm.state.matchHighlighter;
|
||||
if (state.overlay) {
|
||||
cm.removeOverlay(state.overlay);
|
||||
state.overlay = null;
|
||||
if (state.matchesonscroll) {
|
||||
state.matchesonscroll.clear();
|
||||
state.matchesonscroll = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function highlightMatches(cm) {
|
||||
cm.operation(function() {
|
||||
var state = cm.state.matchHighlighter;
|
||||
removeOverlay(cm);
|
||||
if (!cm.somethingSelected() && state.options.showToken) {
|
||||
var re = state.options.showToken === true ? /[\w$]/ : state.options.showToken;
|
||||
var cur = cm.getCursor(), line = cm.getLine(cur.line), start = cur.ch, end = start;
|
||||
while (start && re.test(line.charAt(start - 1))) --start;
|
||||
while (end < line.length && re.test(line.charAt(end))) ++end;
|
||||
if (start < end)
|
||||
addOverlay(cm, line.slice(start, end), re, state.options.style);
|
||||
return;
|
||||
}
|
||||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||||
if (from.line != to.line) return;
|
||||
if (state.options.wordsOnly && !isWord(cm, from, to)) return;
|
||||
var selection = cm.getRange(from, to)
|
||||
if (state.options.trim) selection = selection.replace(/^\s+|\s+$/g, "")
|
||||
if (selection.length >= state.options.minChars)
|
||||
addOverlay(cm, selection, false, state.options.style);
|
||||
});
|
||||
}
|
||||
|
||||
function isWord(cm, from, to) {
|
||||
var str = cm.getRange(from, to);
|
||||
if (str.match(/^\w+$/) !== null) {
|
||||
if (from.ch > 0) {
|
||||
var pos = {line: from.line, ch: from.ch - 1};
|
||||
var chr = cm.getRange(pos, from);
|
||||
if (chr.match(/\W/) === null) return false;
|
||||
}
|
||||
if (to.ch < cm.getLine(from.line).length) {
|
||||
var pos = {line: to.line, ch: to.ch + 1};
|
||||
var chr = cm.getRange(to, pos);
|
||||
if (chr.match(/\W/) === null) return false;
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
function boundariesAround(stream, re) {
|
||||
return (!stream.start || !re.test(stream.string.charAt(stream.start - 1))) &&
|
||||
(stream.pos == stream.string.length || !re.test(stream.string.charAt(stream.pos)));
|
||||
}
|
||||
|
||||
function makeOverlay(query, hasBoundary, style) {
|
||||
return {token: function(stream) {
|
||||
if (stream.match(query) &&
|
||||
(!hasBoundary || boundariesAround(stream, hasBoundary)))
|
||||
return style;
|
||||
stream.next();
|
||||
stream.skipTo(query.charAt(0)) || stream.skipToEnd();
|
||||
}};
|
||||
}
|
||||
});
|
8
BrowserMark/js/codemirror/addon/search/matchesonscrollbar.css
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
.CodeMirror-search-match {
|
||||
background: gold;
|
||||
border-top: 1px solid orange;
|
||||
border-bottom: 1px solid orange;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
opacity: .5;
|
||||
}
|
97
BrowserMark/js/codemirror/addon/search/matchesonscrollbar.js
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../scroll/annotatescrollbar"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./searchcursor", "../scroll/annotatescrollbar"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) {
|
||||
if (typeof options == "string") options = {className: options};
|
||||
if (!options) options = {};
|
||||
return new SearchAnnotation(this, query, caseFold, options);
|
||||
});
|
||||
|
||||
function SearchAnnotation(cm, query, caseFold, options) {
|
||||
this.cm = cm;
|
||||
this.options = options;
|
||||
var annotateOptions = {listenForChanges: false};
|
||||
for (var prop in options) annotateOptions[prop] = options[prop];
|
||||
if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match";
|
||||
this.annotation = cm.annotateScrollbar(annotateOptions);
|
||||
this.query = query;
|
||||
this.caseFold = caseFold;
|
||||
this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1};
|
||||
this.matches = [];
|
||||
this.update = null;
|
||||
|
||||
this.findMatches();
|
||||
this.annotation.update(this.matches);
|
||||
|
||||
var self = this;
|
||||
cm.on("change", this.changeHandler = function(_cm, change) { self.onChange(change); });
|
||||
}
|
||||
|
||||
var MAX_MATCHES = 1000;
|
||||
|
||||
SearchAnnotation.prototype.findMatches = function() {
|
||||
if (!this.gap) return;
|
||||
for (var i = 0; i < this.matches.length; i++) {
|
||||
var match = this.matches[i];
|
||||
if (match.from.line >= this.gap.to) break;
|
||||
if (match.to.line >= this.gap.from) this.matches.splice(i--, 1);
|
||||
}
|
||||
var cursor = this.cm.getSearchCursor(this.query, CodeMirror.Pos(this.gap.from, 0), this.caseFold);
|
||||
var maxMatches = this.options && this.options.maxMatches || MAX_MATCHES;
|
||||
while (cursor.findNext()) {
|
||||
var match = {from: cursor.from(), to: cursor.to()};
|
||||
if (match.from.line >= this.gap.to) break;
|
||||
this.matches.splice(i++, 0, match);
|
||||
if (this.matches.length > maxMatches) break;
|
||||
}
|
||||
this.gap = null;
|
||||
};
|
||||
|
||||
function offsetLine(line, changeStart, sizeChange) {
|
||||
if (line <= changeStart) return line;
|
||||
return Math.max(changeStart, line + sizeChange);
|
||||
}
|
||||
|
||||
SearchAnnotation.prototype.onChange = function(change) {
|
||||
var startLine = change.from.line;
|
||||
var endLine = CodeMirror.changeEnd(change).line;
|
||||
var sizeChange = endLine - change.to.line;
|
||||
if (this.gap) {
|
||||
this.gap.from = Math.min(offsetLine(this.gap.from, startLine, sizeChange), change.from.line);
|
||||
this.gap.to = Math.max(offsetLine(this.gap.to, startLine, sizeChange), change.from.line);
|
||||
} else {
|
||||
this.gap = {from: change.from.line, to: endLine + 1};
|
||||
}
|
||||
|
||||
if (sizeChange) for (var i = 0; i < this.matches.length; i++) {
|
||||
var match = this.matches[i];
|
||||
var newFrom = offsetLine(match.from.line, startLine, sizeChange);
|
||||
if (newFrom != match.from.line) match.from = CodeMirror.Pos(newFrom, match.from.ch);
|
||||
var newTo = offsetLine(match.to.line, startLine, sizeChange);
|
||||
if (newTo != match.to.line) match.to = CodeMirror.Pos(newTo, match.to.ch);
|
||||
}
|
||||
clearTimeout(this.update);
|
||||
var self = this;
|
||||
this.update = setTimeout(function() { self.updateAfterChange(); }, 250);
|
||||
};
|
||||
|
||||
SearchAnnotation.prototype.updateAfterChange = function() {
|
||||
this.findMatches();
|
||||
this.annotation.update(this.matches);
|
||||
};
|
||||
|
||||
SearchAnnotation.prototype.clear = function() {
|
||||
this.cm.off("change", this.changeHandler);
|
||||
this.annotation.clear();
|
||||
};
|
||||
});
|
252
BrowserMark/js/codemirror/addon/search/search.js
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// Define search commands. Depends on dialog.js or another
|
||||
// implementation of the openDialog method.
|
||||
|
||||
// Replace works a little oddly -- it will do the replace on the next
|
||||
// Ctrl-G (or whatever is bound to findNext) press. You prevent a
|
||||
// replace by making sure the match is no longer selected when hitting
|
||||
// Ctrl-G.
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("./searchcursor"), require("../dialog/dialog"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "./searchcursor", "../dialog/dialog"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function searchOverlay(query, caseInsensitive) {
|
||||
if (typeof query == "string")
|
||||
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), caseInsensitive ? "gi" : "g");
|
||||
else if (!query.global)
|
||||
query = new RegExp(query.source, query.ignoreCase ? "gi" : "g");
|
||||
|
||||
return {token: function(stream) {
|
||||
query.lastIndex = stream.pos;
|
||||
var match = query.exec(stream.string);
|
||||
if (match && match.index == stream.pos) {
|
||||
stream.pos += match[0].length || 1;
|
||||
return "searching";
|
||||
} else if (match) {
|
||||
stream.pos = match.index;
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
function SearchState() {
|
||||
this.posFrom = this.posTo = this.lastQuery = this.query = null;
|
||||
this.overlay = null;
|
||||
}
|
||||
|
||||
function getSearchState(cm) {
|
||||
return cm.state.search || (cm.state.search = new SearchState());
|
||||
}
|
||||
|
||||
function queryCaseInsensitive(query) {
|
||||
return typeof query == "string" && query == query.toLowerCase();
|
||||
}
|
||||
|
||||
function getSearchCursor(cm, query, pos) {
|
||||
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
||||
return cm.getSearchCursor(query, pos, queryCaseInsensitive(query));
|
||||
}
|
||||
|
||||
function persistentDialog(cm, text, deflt, onEnter, onKeyDown) {
|
||||
cm.openDialog(text, onEnter, {
|
||||
value: deflt,
|
||||
selectValueOnOpen: true,
|
||||
closeOnEnter: false,
|
||||
onClose: function() { clearSearch(cm); },
|
||||
onKeyDown: onKeyDown
|
||||
});
|
||||
}
|
||||
|
||||
function dialog(cm, text, shortText, deflt, f) {
|
||||
if (cm.openDialog) cm.openDialog(text, f, {value: deflt, selectValueOnOpen: true});
|
||||
else f(prompt(shortText, deflt));
|
||||
}
|
||||
|
||||
function confirmDialog(cm, text, shortText, fs) {
|
||||
if (cm.openConfirm) cm.openConfirm(text, fs);
|
||||
else if (confirm(shortText)) fs[0]();
|
||||
}
|
||||
|
||||
function parseString(string) {
|
||||
return string.replace(/\\(.)/g, function(_, ch) {
|
||||
if (ch == "n") return "\n"
|
||||
if (ch == "r") return "\r"
|
||||
return ch
|
||||
})
|
||||
}
|
||||
|
||||
function parseQuery(query) {
|
||||
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
||||
if (isRE) {
|
||||
try { query = new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i"); }
|
||||
catch(e) {} // Not a regular expression after all, do a string search
|
||||
} else {
|
||||
query = parseString(query)
|
||||
}
|
||||
if (typeof query == "string" ? query == "" : query.test(""))
|
||||
query = /x^/;
|
||||
return query;
|
||||
}
|
||||
|
||||
var queryDialog =
|
||||
'Search: <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
|
||||
|
||||
function startSearch(cm, state, query) {
|
||||
state.queryText = query;
|
||||
state.query = parseQuery(query);
|
||||
cm.removeOverlay(state.overlay, queryCaseInsensitive(state.query));
|
||||
state.overlay = searchOverlay(state.query, queryCaseInsensitive(state.query));
|
||||
cm.addOverlay(state.overlay);
|
||||
if (cm.showMatchesOnScrollbar) {
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
state.annotate = cm.showMatchesOnScrollbar(state.query, queryCaseInsensitive(state.query));
|
||||
}
|
||||
}
|
||||
|
||||
function doSearch(cm, rev, persistent, immediate) {
|
||||
var state = getSearchState(cm);
|
||||
if (state.query) return findNext(cm, rev);
|
||||
var q = cm.getSelection() || state.lastQuery;
|
||||
if (persistent && cm.openDialog) {
|
||||
var hiding = null
|
||||
var searchNext = function(query, event) {
|
||||
CodeMirror.e_stop(event);
|
||||
if (!query) return;
|
||||
if (query != state.queryText) {
|
||||
startSearch(cm, state, query);
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
}
|
||||
if (hiding) hiding.style.opacity = 1
|
||||
findNext(cm, event.shiftKey, function(_, to) {
|
||||
var dialog
|
||||
if (to.line < 3 && document.querySelector &&
|
||||
(dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) &&
|
||||
dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top)
|
||||
(hiding = dialog).style.opacity = .4
|
||||
})
|
||||
};
|
||||
persistentDialog(cm, queryDialog, q, searchNext, function(event, query) {
|
||||
var keyName = CodeMirror.keyName(event)
|
||||
var cmd = CodeMirror.keyMap[cm.getOption("keyMap")][keyName]
|
||||
if (!cmd) cmd = cm.getOption('extraKeys')[keyName]
|
||||
if (cmd == "findNext" || cmd == "findPrev" ||
|
||||
cmd == "findPersistentNext" || cmd == "findPersistentPrev") {
|
||||
CodeMirror.e_stop(event);
|
||||
startSearch(cm, getSearchState(cm), query);
|
||||
cm.execCommand(cmd);
|
||||
} else if (cmd == "find" || cmd == "findPersistent") {
|
||||
CodeMirror.e_stop(event);
|
||||
searchNext(query, event);
|
||||
}
|
||||
});
|
||||
if (immediate && q) {
|
||||
startSearch(cm, state, q);
|
||||
findNext(cm, rev);
|
||||
}
|
||||
} else {
|
||||
dialog(cm, queryDialog, "Search for:", q, function(query) {
|
||||
if (query && !state.query) cm.operation(function() {
|
||||
startSearch(cm, state, query);
|
||||
state.posFrom = state.posTo = cm.getCursor();
|
||||
findNext(cm, rev);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function findNext(cm, rev, callback) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo);
|
||||
if (!cursor.find(rev)) {
|
||||
cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0));
|
||||
if (!cursor.find(rev)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
|
||||
state.posFrom = cursor.from(); state.posTo = cursor.to();
|
||||
if (callback) callback(cursor.from(), cursor.to())
|
||||
});}
|
||||
|
||||
function clearSearch(cm) {cm.operation(function() {
|
||||
var state = getSearchState(cm);
|
||||
state.lastQuery = state.query;
|
||||
if (!state.query) return;
|
||||
state.query = state.queryText = null;
|
||||
cm.removeOverlay(state.overlay);
|
||||
if (state.annotate) { state.annotate.clear(); state.annotate = null; }
|
||||
});}
|
||||
|
||||
var replaceQueryDialog =
|
||||
' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">(Use /re/ syntax for regexp search)</span>';
|
||||
var replacementQueryDialog = 'With: <input type="text" style="width: 10em" class="CodeMirror-search-field"/>';
|
||||
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>All</button> <button>Stop</button>";
|
||||
|
||||
function replaceAll(cm, query, text) {
|
||||
cm.operation(function() {
|
||||
for (var cursor = getSearchCursor(cm, query); cursor.findNext();) {
|
||||
if (typeof query != "string") {
|
||||
var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
||||
cursor.replace(text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||||
} else cursor.replace(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function replace(cm, all) {
|
||||
if (cm.getOption("readOnly")) return;
|
||||
var query = cm.getSelection() || getSearchState(cm).lastQuery;
|
||||
var dialogText = all ? "Replace all:" : "Replace:"
|
||||
dialog(cm, dialogText + replaceQueryDialog, dialogText, query, function(query) {
|
||||
if (!query) return;
|
||||
query = parseQuery(query);
|
||||
dialog(cm, replacementQueryDialog, "Replace with:", "", function(text) {
|
||||
text = parseString(text)
|
||||
if (all) {
|
||||
replaceAll(cm, query, text)
|
||||
} else {
|
||||
clearSearch(cm);
|
||||
var cursor = getSearchCursor(cm, query, cm.getCursor("from"));
|
||||
var advance = function() {
|
||||
var start = cursor.from(), match;
|
||||
if (!(match = cursor.findNext())) {
|
||||
cursor = getSearchCursor(cm, query);
|
||||
if (!(match = cursor.findNext()) ||
|
||||
(start && cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
|
||||
}
|
||||
cm.setSelection(cursor.from(), cursor.to());
|
||||
cm.scrollIntoView({from: cursor.from(), to: cursor.to()});
|
||||
confirmDialog(cm, doReplaceConfirm, "Replace?",
|
||||
[function() {doReplace(match);}, advance,
|
||||
function() {replaceAll(cm, query, text)}]);
|
||||
};
|
||||
var doReplace = function(match) {
|
||||
cursor.replace(typeof query == "string" ? text :
|
||||
text.replace(/\$(\d)/g, function(_, i) {return match[i];}));
|
||||
advance();
|
||||
};
|
||||
advance();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|
||||
CodeMirror.commands.findPersistent = function(cm) {clearSearch(cm); doSearch(cm, false, true);};
|
||||
CodeMirror.commands.findPersistentNext = function(cm) {doSearch(cm, false, true, true);};
|
||||
CodeMirror.commands.findPersistentPrev = function(cm) {doSearch(cm, true, true, true);};
|
||||
CodeMirror.commands.findNext = doSearch;
|
||||
CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
|
||||
CodeMirror.commands.clearSearch = clearSearch;
|
||||
CodeMirror.commands.replace = replace;
|
||||
CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
|
||||
});
|
189
BrowserMark/js/codemirror/addon/search/searchcursor.js
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function SearchCursor(doc, query, pos, caseFold) {
|
||||
this.atOccurrence = false; this.doc = doc;
|
||||
if (caseFold == null && typeof query == "string") caseFold = false;
|
||||
|
||||
pos = pos ? doc.clipPos(pos) : Pos(0, 0);
|
||||
this.pos = {from: pos, to: pos};
|
||||
|
||||
// The matches method is filled in based on the type of query.
|
||||
// It takes a position and a direction, and returns an object
|
||||
// describing the next occurrence of the query, or null if no
|
||||
// more matches were found.
|
||||
if (typeof query != "string") { // Regexp match
|
||||
if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
|
||||
this.matches = function(reverse, pos) {
|
||||
if (reverse) {
|
||||
query.lastIndex = 0;
|
||||
var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
|
||||
for (;;) {
|
||||
query.lastIndex = cutOff;
|
||||
var newMatch = query.exec(line);
|
||||
if (!newMatch) break;
|
||||
match = newMatch;
|
||||
start = match.index;
|
||||
cutOff = match.index + (match[0].length || 1);
|
||||
if (cutOff == line.length) break;
|
||||
}
|
||||
var matchLen = (match && match[0].length) || 0;
|
||||
if (!matchLen) {
|
||||
if (start == 0 && line.length == 0) {match = undefined;}
|
||||
else if (start != doc.getLine(pos.line).length) {
|
||||
matchLen++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query.lastIndex = pos.ch;
|
||||
var line = doc.getLine(pos.line), match = query.exec(line);
|
||||
var matchLen = (match && match[0].length) || 0;
|
||||
var start = match && match.index;
|
||||
if (start + matchLen != line.length && !matchLen) matchLen = 1;
|
||||
}
|
||||
if (match && matchLen)
|
||||
return {from: Pos(pos.line, start),
|
||||
to: Pos(pos.line, start + matchLen),
|
||||
match: match};
|
||||
};
|
||||
} else { // String query
|
||||
var origQuery = query;
|
||||
if (caseFold) query = query.toLowerCase();
|
||||
var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
|
||||
var target = query.split("\n");
|
||||
// Different methods for single-line and multi-line queries
|
||||
if (target.length == 1) {
|
||||
if (!query.length) {
|
||||
// Empty string would match anything and never progress, so
|
||||
// we define it to match nothing instead.
|
||||
this.matches = function() {};
|
||||
} else {
|
||||
this.matches = function(reverse, pos) {
|
||||
if (reverse) {
|
||||
var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
|
||||
var match = line.lastIndexOf(query);
|
||||
if (match > -1) {
|
||||
match = adjustPos(orig, line, match);
|
||||
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
||||
}
|
||||
} else {
|
||||
var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
|
||||
var match = line.indexOf(query);
|
||||
if (match > -1) {
|
||||
match = adjustPos(orig, line, match) + pos.ch;
|
||||
return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var origTarget = origQuery.split("\n");
|
||||
this.matches = function(reverse, pos) {
|
||||
var last = target.length - 1;
|
||||
if (reverse) {
|
||||
if (pos.line - (target.length - 1) < doc.firstLine()) return;
|
||||
if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
|
||||
var to = Pos(pos.line, origTarget[last].length);
|
||||
for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
|
||||
if (target[i] != fold(doc.getLine(ln))) return;
|
||||
var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
|
||||
if (fold(line.slice(cut)) != target[0]) return;
|
||||
return {from: Pos(ln, cut), to: to};
|
||||
} else {
|
||||
if (pos.line + (target.length - 1) > doc.lastLine()) return;
|
||||
var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
|
||||
if (fold(line.slice(cut)) != target[0]) return;
|
||||
var from = Pos(pos.line, cut);
|
||||
for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
|
||||
if (target[i] != fold(doc.getLine(ln))) return;
|
||||
if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
|
||||
return {from: from, to: Pos(ln, origTarget[last].length)};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchCursor.prototype = {
|
||||
findNext: function() {return this.find(false);},
|
||||
findPrevious: function() {return this.find(true);},
|
||||
|
||||
find: function(reverse) {
|
||||
var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
|
||||
function savePosAndFail(line) {
|
||||
var pos = Pos(line, 0);
|
||||
self.pos = {from: pos, to: pos};
|
||||
self.atOccurrence = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (this.pos = this.matches(reverse, pos)) {
|
||||
this.atOccurrence = true;
|
||||
return this.pos.match || true;
|
||||
}
|
||||
if (reverse) {
|
||||
if (!pos.line) return savePosAndFail(0);
|
||||
pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
|
||||
}
|
||||
else {
|
||||
var maxLine = this.doc.lineCount();
|
||||
if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
|
||||
pos = Pos(pos.line + 1, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
from: function() {if (this.atOccurrence) return this.pos.from;},
|
||||
to: function() {if (this.atOccurrence) return this.pos.to;},
|
||||
|
||||
replace: function(newText, origin) {
|
||||
if (!this.atOccurrence) return;
|
||||
var lines = CodeMirror.splitLines(newText);
|
||||
this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin);
|
||||
this.pos.to = Pos(this.pos.from.line + lines.length - 1,
|
||||
lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
|
||||
}
|
||||
};
|
||||
|
||||
// Maps a position in a case-folded line back to a position in the original line
|
||||
// (compensating for codepoints increasing in number during folding)
|
||||
function adjustPos(orig, folded, pos) {
|
||||
if (orig.length == folded.length) return pos;
|
||||
for (var pos1 = Math.min(pos, orig.length);;) {
|
||||
var len1 = orig.slice(0, pos1).toLowerCase().length;
|
||||
if (len1 < pos) ++pos1;
|
||||
else if (len1 > pos) --pos1;
|
||||
else return pos1;
|
||||
}
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
|
||||
return new SearchCursor(this.doc, query, pos, caseFold);
|
||||
});
|
||||
CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
|
||||
return new SearchCursor(this, query, pos, caseFold);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
|
||||
var ranges = [];
|
||||
var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
|
||||
while (cur.findNext()) {
|
||||
if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break;
|
||||
ranges.push({anchor: cur.from(), head: cur.to()});
|
||||
}
|
||||
if (ranges.length)
|
||||
this.setSelections(ranges, 0);
|
||||
});
|
||||
});
|
144
BrowserMark/js/codemirror/addon/wrap/hardwrap.js
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
|
||||
function findParagraph(cm, pos, options) {
|
||||
var startRE = options.paragraphStart || cm.getHelper(pos, "paragraphStart");
|
||||
for (var start = pos.line, first = cm.firstLine(); start > first; --start) {
|
||||
var line = cm.getLine(start);
|
||||
if (startRE && startRE.test(line)) break;
|
||||
if (!/\S/.test(line)) { ++start; break; }
|
||||
}
|
||||
var endRE = options.paragraphEnd || cm.getHelper(pos, "paragraphEnd");
|
||||
for (var end = pos.line + 1, last = cm.lastLine(); end <= last; ++end) {
|
||||
var line = cm.getLine(end);
|
||||
if (endRE && endRE.test(line)) { ++end; break; }
|
||||
if (!/\S/.test(line)) break;
|
||||
}
|
||||
return {from: start, to: end};
|
||||
}
|
||||
|
||||
function findBreakPoint(text, column, wrapOn, killTrailingSpace) {
|
||||
var at = column
|
||||
while (at < text.length && text.charAt(at) == " ") at++
|
||||
for (; at > 0; --at)
|
||||
if (wrapOn.test(text.slice(at - 1, at + 1))) break;
|
||||
for (var first = true;; first = false) {
|
||||
var endOfText = at;
|
||||
if (killTrailingSpace)
|
||||
while (text.charAt(endOfText - 1) == " ") --endOfText;
|
||||
if (endOfText == 0 && first) at = column;
|
||||
else return {from: endOfText, to: at};
|
||||
}
|
||||
}
|
||||
|
||||
function wrapRange(cm, from, to, options) {
|
||||
from = cm.clipPos(from); to = cm.clipPos(to);
|
||||
var column = options.column || 80;
|
||||
var wrapOn = options.wrapOn || /\s\S|-[^\.\d]/;
|
||||
var killTrailing = options.killTrailingSpace !== false;
|
||||
var changes = [], curLine = "", curNo = from.line;
|
||||
var lines = cm.getRange(from, to, false);
|
||||
if (!lines.length) return null;
|
||||
var leadingSpace = lines[0].match(/^[ \t]*/)[0];
|
||||
|
||||
for (var i = 0; i < lines.length; ++i) {
|
||||
var text = lines[i], oldLen = curLine.length, spaceInserted = 0;
|
||||
if (curLine && text && !wrapOn.test(curLine.charAt(curLine.length - 1) + text.charAt(0))) {
|
||||
curLine += " ";
|
||||
spaceInserted = 1;
|
||||
}
|
||||
var spaceTrimmed = "";
|
||||
if (i) {
|
||||
spaceTrimmed = text.match(/^\s*/)[0];
|
||||
text = text.slice(spaceTrimmed.length);
|
||||
}
|
||||
curLine += text;
|
||||
if (i) {
|
||||
var firstBreak = curLine.length > column && leadingSpace == spaceTrimmed &&
|
||||
findBreakPoint(curLine, column, wrapOn, killTrailing);
|
||||
// If this isn't broken, or is broken at a different point, remove old break
|
||||
if (!firstBreak || firstBreak.from != oldLen || firstBreak.to != oldLen + spaceInserted) {
|
||||
changes.push({text: [spaceInserted ? " " : ""],
|
||||
from: Pos(curNo, oldLen),
|
||||
to: Pos(curNo + 1, spaceTrimmed.length)});
|
||||
} else {
|
||||
curLine = leadingSpace + text;
|
||||
++curNo;
|
||||
}
|
||||
}
|
||||
while (curLine.length > column) {
|
||||
var bp = findBreakPoint(curLine, column, wrapOn, killTrailing);
|
||||
changes.push({text: ["", leadingSpace],
|
||||
from: Pos(curNo, bp.from),
|
||||
to: Pos(curNo, bp.to)});
|
||||
curLine = leadingSpace + curLine.slice(bp.to);
|
||||
++curNo;
|
||||
}
|
||||
}
|
||||
if (changes.length) cm.operation(function() {
|
||||
for (var i = 0; i < changes.length; ++i) {
|
||||
var change = changes[i];
|
||||
if (change.text || CodeMirror.cmpPos(change.from, change.to))
|
||||
cm.replaceRange(change.text, change.from, change.to);
|
||||
}
|
||||
});
|
||||
return changes.length ? {from: changes[0].from, to: CodeMirror.changeEnd(changes[changes.length - 1])} : null;
|
||||
}
|
||||
|
||||
CodeMirror.defineExtension("wrapParagraph", function(pos, options) {
|
||||
options = options || {};
|
||||
if (!pos) pos = this.getCursor();
|
||||
var para = findParagraph(this, pos, options);
|
||||
return wrapRange(this, Pos(para.from, 0), Pos(para.to - 1), options);
|
||||
});
|
||||
|
||||
CodeMirror.commands.wrapLines = function(cm) {
|
||||
cm.operation(function() {
|
||||
var ranges = cm.listSelections(), at = cm.lastLine() + 1;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var range = ranges[i], span;
|
||||
if (range.empty()) {
|
||||
var para = findParagraph(cm, range.head, {});
|
||||
span = {from: Pos(para.from, 0), to: Pos(para.to - 1)};
|
||||
} else {
|
||||
span = {from: range.from(), to: range.to()};
|
||||
}
|
||||
if (span.to.line >= at) continue;
|
||||
at = span.from.line;
|
||||
wrapRange(cm, span.from, span.to, {});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension("wrapRange", function(from, to, options) {
|
||||
return wrapRange(this, from, to, options || {});
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension("wrapParagraphsInRange", function(from, to, options) {
|
||||
options = options || {};
|
||||
var cm = this, paras = [];
|
||||
for (var line = from.line; line <= to.line;) {
|
||||
var para = findParagraph(cm, Pos(line, 0), options);
|
||||
paras.push(para);
|
||||
line = para.to;
|
||||
}
|
||||
var madeChange = false;
|
||||
if (paras.length) cm.operation(function() {
|
||||
for (var i = paras.length - 1; i >= 0; --i)
|
||||
madeChange = madeChange || wrapRange(cm, Pos(paras[i].from, 0), Pos(paras[i].to - 1), options);
|
||||
});
|
||||
return madeChange;
|
||||
});
|
||||
});
|
412
BrowserMark/js/codemirror/keymap/emacs.js
vendored
Normal file
@ -0,0 +1,412 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var Pos = CodeMirror.Pos;
|
||||
function posEq(a, b) { return a.line == b.line && a.ch == b.ch; }
|
||||
|
||||
// Kill 'ring'
|
||||
|
||||
var killRing = [];
|
||||
function addToRing(str) {
|
||||
killRing.push(str);
|
||||
if (killRing.length > 50) killRing.shift();
|
||||
}
|
||||
function growRingTop(str) {
|
||||
if (!killRing.length) return addToRing(str);
|
||||
killRing[killRing.length - 1] += str;
|
||||
}
|
||||
function getFromRing(n) { return killRing[killRing.length - (n ? Math.min(n, 1) : 1)] || ""; }
|
||||
function popFromRing() { if (killRing.length > 1) killRing.pop(); return getFromRing(); }
|
||||
|
||||
var lastKill = null;
|
||||
|
||||
function kill(cm, from, to, mayGrow, text) {
|
||||
if (text == null) text = cm.getRange(from, to);
|
||||
|
||||
if (mayGrow && lastKill && lastKill.cm == cm && posEq(from, lastKill.pos) && cm.isClean(lastKill.gen))
|
||||
growRingTop(text);
|
||||
else
|
||||
addToRing(text);
|
||||
cm.replaceRange("", from, to, "+delete");
|
||||
|
||||
if (mayGrow) lastKill = {cm: cm, pos: from, gen: cm.changeGeneration()};
|
||||
else lastKill = null;
|
||||
}
|
||||
|
||||
// Boundaries of various units
|
||||
|
||||
function byChar(cm, pos, dir) {
|
||||
return cm.findPosH(pos, dir, "char", true);
|
||||
}
|
||||
|
||||
function byWord(cm, pos, dir) {
|
||||
return cm.findPosH(pos, dir, "word", true);
|
||||
}
|
||||
|
||||
function byLine(cm, pos, dir) {
|
||||
return cm.findPosV(pos, dir, "line", cm.doc.sel.goalColumn);
|
||||
}
|
||||
|
||||
function byPage(cm, pos, dir) {
|
||||
return cm.findPosV(pos, dir, "page", cm.doc.sel.goalColumn);
|
||||
}
|
||||
|
||||
function byParagraph(cm, pos, dir) {
|
||||
var no = pos.line, line = cm.getLine(no);
|
||||
var sawText = /\S/.test(dir < 0 ? line.slice(0, pos.ch) : line.slice(pos.ch));
|
||||
var fst = cm.firstLine(), lst = cm.lastLine();
|
||||
for (;;) {
|
||||
no += dir;
|
||||
if (no < fst || no > lst)
|
||||
return cm.clipPos(Pos(no - dir, dir < 0 ? 0 : null));
|
||||
line = cm.getLine(no);
|
||||
var hasText = /\S/.test(line);
|
||||
if (hasText) sawText = true;
|
||||
else if (sawText) return Pos(no, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function bySentence(cm, pos, dir) {
|
||||
var line = pos.line, ch = pos.ch;
|
||||
var text = cm.getLine(pos.line), sawWord = false;
|
||||
for (;;) {
|
||||
var next = text.charAt(ch + (dir < 0 ? -1 : 0));
|
||||
if (!next) { // End/beginning of line reached
|
||||
if (line == (dir < 0 ? cm.firstLine() : cm.lastLine())) return Pos(line, ch);
|
||||
text = cm.getLine(line + dir);
|
||||
if (!/\S/.test(text)) return Pos(line, ch);
|
||||
line += dir;
|
||||
ch = dir < 0 ? text.length : 0;
|
||||
continue;
|
||||
}
|
||||
if (sawWord && /[!?.]/.test(next)) return Pos(line, ch + (dir > 0 ? 1 : 0));
|
||||
if (!sawWord) sawWord = /\w/.test(next);
|
||||
ch += dir;
|
||||
}
|
||||
}
|
||||
|
||||
function byExpr(cm, pos, dir) {
|
||||
var wrap;
|
||||
if (cm.findMatchingBracket && (wrap = cm.findMatchingBracket(pos, true))
|
||||
&& wrap.match && (wrap.forward ? 1 : -1) == dir)
|
||||
return dir > 0 ? Pos(wrap.to.line, wrap.to.ch + 1) : wrap.to;
|
||||
|
||||
for (var first = true;; first = false) {
|
||||
var token = cm.getTokenAt(pos);
|
||||
var after = Pos(pos.line, dir < 0 ? token.start : token.end);
|
||||
if (first && dir > 0 && token.end == pos.ch || !/\w/.test(token.string)) {
|
||||
var newPos = cm.findPosH(after, dir, "char");
|
||||
if (posEq(after, newPos)) return pos;
|
||||
else pos = newPos;
|
||||
} else {
|
||||
return after;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prefixes (only crudely supported)
|
||||
|
||||
function getPrefix(cm, precise) {
|
||||
var digits = cm.state.emacsPrefix;
|
||||
if (!digits) return precise ? null : 1;
|
||||
clearPrefix(cm);
|
||||
return digits == "-" ? -1 : Number(digits);
|
||||
}
|
||||
|
||||
function repeated(cmd) {
|
||||
var f = typeof cmd == "string" ? function(cm) { cm.execCommand(cmd); } : cmd;
|
||||
return function(cm) {
|
||||
var prefix = getPrefix(cm);
|
||||
f(cm);
|
||||
for (var i = 1; i < prefix; ++i) f(cm);
|
||||
};
|
||||
}
|
||||
|
||||
function findEnd(cm, pos, by, dir) {
|
||||
var prefix = getPrefix(cm);
|
||||
if (prefix < 0) { dir = -dir; prefix = -prefix; }
|
||||
for (var i = 0; i < prefix; ++i) {
|
||||
var newPos = by(cm, pos, dir);
|
||||
if (posEq(newPos, pos)) break;
|
||||
pos = newPos;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
function move(by, dir) {
|
||||
var f = function(cm) {
|
||||
cm.extendSelection(findEnd(cm, cm.getCursor(), by, dir));
|
||||
};
|
||||
f.motion = true;
|
||||
return f;
|
||||
}
|
||||
|
||||
function killTo(cm, by, dir) {
|
||||
var selections = cm.listSelections(), cursor;
|
||||
var i = selections.length;
|
||||
while (i--) {
|
||||
cursor = selections[i].head;
|
||||
kill(cm, cursor, findEnd(cm, cursor, by, dir), true);
|
||||
}
|
||||
}
|
||||
|
||||
function killRegion(cm) {
|
||||
if (cm.somethingSelected()) {
|
||||
var selections = cm.listSelections(), selection;
|
||||
var i = selections.length;
|
||||
while (i--) {
|
||||
selection = selections[i];
|
||||
kill(cm, selection.anchor, selection.head);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function addPrefix(cm, digit) {
|
||||
if (cm.state.emacsPrefix) {
|
||||
if (digit != "-") cm.state.emacsPrefix += digit;
|
||||
return;
|
||||
}
|
||||
// Not active yet
|
||||
cm.state.emacsPrefix = digit;
|
||||
cm.on("keyHandled", maybeClearPrefix);
|
||||
cm.on("inputRead", maybeDuplicateInput);
|
||||
}
|
||||
|
||||
var prefixPreservingKeys = {"Alt-G": true, "Ctrl-X": true, "Ctrl-Q": true, "Ctrl-U": true};
|
||||
|
||||
function maybeClearPrefix(cm, arg) {
|
||||
if (!cm.state.emacsPrefixMap && !prefixPreservingKeys.hasOwnProperty(arg))
|
||||
clearPrefix(cm);
|
||||
}
|
||||
|
||||
function clearPrefix(cm) {
|
||||
cm.state.emacsPrefix = null;
|
||||
cm.off("keyHandled", maybeClearPrefix);
|
||||
cm.off("inputRead", maybeDuplicateInput);
|
||||
}
|
||||
|
||||
function maybeDuplicateInput(cm, event) {
|
||||
var dup = getPrefix(cm);
|
||||
if (dup > 1 && event.origin == "+input") {
|
||||
var one = event.text.join("\n"), txt = "";
|
||||
for (var i = 1; i < dup; ++i) txt += one;
|
||||
cm.replaceSelection(txt);
|
||||
}
|
||||
}
|
||||
|
||||
function addPrefixMap(cm) {
|
||||
cm.state.emacsPrefixMap = true;
|
||||
cm.addKeyMap(prefixMap);
|
||||
cm.on("keyHandled", maybeRemovePrefixMap);
|
||||
cm.on("inputRead", maybeRemovePrefixMap);
|
||||
}
|
||||
|
||||
function maybeRemovePrefixMap(cm, arg) {
|
||||
if (typeof arg == "string" && (/^\d$/.test(arg) || arg == "Ctrl-U")) return;
|
||||
cm.removeKeyMap(prefixMap);
|
||||
cm.state.emacsPrefixMap = false;
|
||||
cm.off("keyHandled", maybeRemovePrefixMap);
|
||||
cm.off("inputRead", maybeRemovePrefixMap);
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
function setMark(cm) {
|
||||
cm.setCursor(cm.getCursor());
|
||||
cm.setExtending(!cm.getExtending());
|
||||
cm.on("change", function() { cm.setExtending(false); });
|
||||
}
|
||||
|
||||
function clearMark(cm) {
|
||||
cm.setExtending(false);
|
||||
cm.setCursor(cm.getCursor());
|
||||
}
|
||||
|
||||
function getInput(cm, msg, f) {
|
||||
if (cm.openDialog)
|
||||
cm.openDialog(msg + ": <input type=\"text\" style=\"width: 10em\"/>", f, {bottom: true});
|
||||
else
|
||||
f(prompt(msg, ""));
|
||||
}
|
||||
|
||||
function operateOnWord(cm, op) {
|
||||
var start = cm.getCursor(), end = cm.findPosH(start, 1, "word");
|
||||
cm.replaceRange(op(cm.getRange(start, end)), start, end);
|
||||
cm.setCursor(end);
|
||||
}
|
||||
|
||||
function toEnclosingExpr(cm) {
|
||||
var pos = cm.getCursor(), line = pos.line, ch = pos.ch;
|
||||
var stack = [];
|
||||
while (line >= cm.firstLine()) {
|
||||
var text = cm.getLine(line);
|
||||
for (var i = ch == null ? text.length : ch; i > 0;) {
|
||||
var ch = text.charAt(--i);
|
||||
if (ch == ")")
|
||||
stack.push("(");
|
||||
else if (ch == "]")
|
||||
stack.push("[");
|
||||
else if (ch == "}")
|
||||
stack.push("{");
|
||||
else if (/[\(\{\[]/.test(ch) && (!stack.length || stack.pop() != ch))
|
||||
return cm.extendSelection(Pos(line, i));
|
||||
}
|
||||
--line; ch = null;
|
||||
}
|
||||
}
|
||||
|
||||
function quit(cm) {
|
||||
cm.execCommand("clearSearch");
|
||||
clearMark(cm);
|
||||
}
|
||||
|
||||
// Actual keymap
|
||||
|
||||
var keyMap = CodeMirror.keyMap.emacs = CodeMirror.normalizeKeyMap({
|
||||
"Ctrl-W": function(cm) {kill(cm, cm.getCursor("start"), cm.getCursor("end"));},
|
||||
"Ctrl-K": repeated(function(cm) {
|
||||
var start = cm.getCursor(), end = cm.clipPos(Pos(start.line));
|
||||
var text = cm.getRange(start, end);
|
||||
if (!/\S/.test(text)) {
|
||||
text += "\n";
|
||||
end = Pos(start.line + 1, 0);
|
||||
}
|
||||
kill(cm, start, end, true, text);
|
||||
}),
|
||||
"Alt-W": function(cm) {
|
||||
addToRing(cm.getSelection());
|
||||
clearMark(cm);
|
||||
},
|
||||
"Ctrl-Y": function(cm) {
|
||||
var start = cm.getCursor();
|
||||
cm.replaceRange(getFromRing(getPrefix(cm)), start, start, "paste");
|
||||
cm.setSelection(start, cm.getCursor());
|
||||
},
|
||||
"Alt-Y": function(cm) {cm.replaceSelection(popFromRing(), "around", "paste");},
|
||||
|
||||
"Ctrl-Space": setMark, "Ctrl-Shift-2": setMark,
|
||||
|
||||
"Ctrl-F": move(byChar, 1), "Ctrl-B": move(byChar, -1),
|
||||
"Right": move(byChar, 1), "Left": move(byChar, -1),
|
||||
"Ctrl-D": function(cm) { killTo(cm, byChar, 1); },
|
||||
"Delete": function(cm) { killRegion(cm) || killTo(cm, byChar, 1); },
|
||||
"Ctrl-H": function(cm) { killTo(cm, byChar, -1); },
|
||||
"Backspace": function(cm) { killRegion(cm) || killTo(cm, byChar, -1); },
|
||||
|
||||
"Alt-F": move(byWord, 1), "Alt-B": move(byWord, -1),
|
||||
"Alt-D": function(cm) { killTo(cm, byWord, 1); },
|
||||
"Alt-Backspace": function(cm) { killTo(cm, byWord, -1); },
|
||||
|
||||
"Ctrl-N": move(byLine, 1), "Ctrl-P": move(byLine, -1),
|
||||
"Down": move(byLine, 1), "Up": move(byLine, -1),
|
||||
"Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
|
||||
"End": "goLineEnd", "Home": "goLineStart",
|
||||
|
||||
"Alt-V": move(byPage, -1), "Ctrl-V": move(byPage, 1),
|
||||
"PageUp": move(byPage, -1), "PageDown": move(byPage, 1),
|
||||
|
||||
"Ctrl-Up": move(byParagraph, -1), "Ctrl-Down": move(byParagraph, 1),
|
||||
|
||||
"Alt-A": move(bySentence, -1), "Alt-E": move(bySentence, 1),
|
||||
"Alt-K": function(cm) { killTo(cm, bySentence, 1); },
|
||||
|
||||
"Ctrl-Alt-K": function(cm) { killTo(cm, byExpr, 1); },
|
||||
"Ctrl-Alt-Backspace": function(cm) { killTo(cm, byExpr, -1); },
|
||||
"Ctrl-Alt-F": move(byExpr, 1), "Ctrl-Alt-B": move(byExpr, -1),
|
||||
|
||||
"Shift-Ctrl-Alt-2": function(cm) {
|
||||
var cursor = cm.getCursor();
|
||||
cm.setSelection(findEnd(cm, cursor, byExpr, 1), cursor);
|
||||
},
|
||||
"Ctrl-Alt-T": function(cm) {
|
||||
var leftStart = byExpr(cm, cm.getCursor(), -1), leftEnd = byExpr(cm, leftStart, 1);
|
||||
var rightEnd = byExpr(cm, leftEnd, 1), rightStart = byExpr(cm, rightEnd, -1);
|
||||
cm.replaceRange(cm.getRange(rightStart, rightEnd) + cm.getRange(leftEnd, rightStart) +
|
||||
cm.getRange(leftStart, leftEnd), leftStart, rightEnd);
|
||||
},
|
||||
"Ctrl-Alt-U": repeated(toEnclosingExpr),
|
||||
|
||||
"Alt-Space": function(cm) {
|
||||
var pos = cm.getCursor(), from = pos.ch, to = pos.ch, text = cm.getLine(pos.line);
|
||||
while (from && /\s/.test(text.charAt(from - 1))) --from;
|
||||
while (to < text.length && /\s/.test(text.charAt(to))) ++to;
|
||||
cm.replaceRange(" ", Pos(pos.line, from), Pos(pos.line, to));
|
||||
},
|
||||
"Ctrl-O": repeated(function(cm) { cm.replaceSelection("\n", "start"); }),
|
||||
"Ctrl-T": repeated(function(cm) {
|
||||
cm.execCommand("transposeChars");
|
||||
}),
|
||||
|
||||
"Alt-C": repeated(function(cm) {
|
||||
operateOnWord(cm, function(w) {
|
||||
var letter = w.search(/\w/);
|
||||
if (letter == -1) return w;
|
||||
return w.slice(0, letter) + w.charAt(letter).toUpperCase() + w.slice(letter + 1).toLowerCase();
|
||||
});
|
||||
}),
|
||||
"Alt-U": repeated(function(cm) {
|
||||
operateOnWord(cm, function(w) { return w.toUpperCase(); });
|
||||
}),
|
||||
"Alt-L": repeated(function(cm) {
|
||||
operateOnWord(cm, function(w) { return w.toLowerCase(); });
|
||||
}),
|
||||
|
||||
"Alt-;": "toggleComment",
|
||||
|
||||
"Ctrl-/": repeated("undo"), "Shift-Ctrl--": repeated("undo"),
|
||||
"Ctrl-Z": repeated("undo"), "Cmd-Z": repeated("undo"),
|
||||
"Shift-Alt-,": "goDocStart", "Shift-Alt-.": "goDocEnd",
|
||||
"Ctrl-S": "findNext", "Ctrl-R": "findPrev", "Ctrl-G": quit, "Shift-Alt-5": "replace",
|
||||
"Alt-/": "autocomplete",
|
||||
"Ctrl-J": "newlineAndIndent", "Enter": false, "Tab": "indentAuto",
|
||||
|
||||
"Alt-G G": function(cm) {
|
||||
var prefix = getPrefix(cm, true);
|
||||
if (prefix != null && prefix > 0) return cm.setCursor(prefix - 1);
|
||||
|
||||
getInput(cm, "Goto line", function(str) {
|
||||
var num;
|
||||
if (str && !isNaN(num = Number(str)) && num == (num|0) && num > 0)
|
||||
cm.setCursor(num - 1);
|
||||
});
|
||||
},
|
||||
|
||||
"Ctrl-X Tab": function(cm) {
|
||||
cm.indentSelection(getPrefix(cm, true) || cm.getOption("indentUnit"));
|
||||
},
|
||||
"Ctrl-X Ctrl-X": function(cm) {
|
||||
cm.setSelection(cm.getCursor("head"), cm.getCursor("anchor"));
|
||||
},
|
||||
"Ctrl-X Ctrl-S": "save",
|
||||
"Ctrl-X Ctrl-W": "save",
|
||||
"Ctrl-X S": "saveAll",
|
||||
"Ctrl-X F": "open",
|
||||
"Ctrl-X U": repeated("undo"),
|
||||
"Ctrl-X K": "close",
|
||||
"Ctrl-X Delete": function(cm) { kill(cm, cm.getCursor(), bySentence(cm, cm.getCursor(), 1), true); },
|
||||
"Ctrl-X H": "selectAll",
|
||||
|
||||
"Ctrl-Q Tab": repeated("insertTab"),
|
||||
"Ctrl-U": addPrefixMap
|
||||
});
|
||||
|
||||
var prefixMap = {"Ctrl-G": clearPrefix};
|
||||
function regPrefix(d) {
|
||||
prefixMap[d] = function(cm) { addPrefix(cm, d); };
|
||||
keyMap["Ctrl-" + d] = function(cm) { addPrefix(cm, d); };
|
||||
prefixPreservingKeys["Ctrl-" + d] = true;
|
||||
}
|
||||
for (var i = 0; i < 10; ++i) regPrefix(String(i));
|
||||
regPrefix("-");
|
||||
});
|
582
BrowserMark/js/codemirror/keymap/sublime.js
vendored
Normal file
@ -0,0 +1,582 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
// A rough approximation of Sublime Text's keybindings
|
||||
// Depends on addon/search/searchcursor.js and optionally addon/dialog/dialogs.js
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../lib/codemirror"), require("../addon/search/searchcursor"), require("../addon/edit/matchbrackets"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../lib/codemirror", "../addon/search/searchcursor", "../addon/edit/matchbrackets"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var map = CodeMirror.keyMap.sublime = {fallthrough: "default"};
|
||||
var cmds = CodeMirror.commands;
|
||||
var Pos = CodeMirror.Pos;
|
||||
var mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault;
|
||||
var ctrl = mac ? "Cmd-" : "Ctrl-";
|
||||
|
||||
// This is not exactly Sublime's algorithm. I couldn't make heads or tails of that.
|
||||
function findPosSubword(doc, start, dir) {
|
||||
if (dir < 0 && start.ch == 0) return doc.clipPos(Pos(start.line - 1));
|
||||
var line = doc.getLine(start.line);
|
||||
if (dir > 0 && start.ch >= line.length) return doc.clipPos(Pos(start.line + 1, 0));
|
||||
var state = "start", type;
|
||||
for (var pos = start.ch, e = dir < 0 ? 0 : line.length, i = 0; pos != e; pos += dir, i++) {
|
||||
var next = line.charAt(dir < 0 ? pos - 1 : pos);
|
||||
var cat = next != "_" && CodeMirror.isWordChar(next) ? "w" : "o";
|
||||
if (cat == "w" && next.toUpperCase() == next) cat = "W";
|
||||
if (state == "start") {
|
||||
if (cat != "o") { state = "in"; type = cat; }
|
||||
} else if (state == "in") {
|
||||
if (type != cat) {
|
||||
if (type == "w" && cat == "W" && dir < 0) pos--;
|
||||
if (type == "W" && cat == "w" && dir > 0) { type = "w"; continue; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Pos(start.line, pos);
|
||||
}
|
||||
|
||||
function moveSubword(cm, dir) {
|
||||
cm.extendSelectionsBy(function(range) {
|
||||
if (cm.display.shift || cm.doc.extend || range.empty())
|
||||
return findPosSubword(cm.doc, range.head, dir);
|
||||
else
|
||||
return dir < 0 ? range.from() : range.to();
|
||||
});
|
||||
}
|
||||
|
||||
var goSubwordCombo = mac ? "Ctrl-" : "Alt-";
|
||||
|
||||
cmds[map[goSubwordCombo + "Left"] = "goSubwordLeft"] = function(cm) { moveSubword(cm, -1); };
|
||||
cmds[map[goSubwordCombo + "Right"] = "goSubwordRight"] = function(cm) { moveSubword(cm, 1); };
|
||||
|
||||
if (mac) map["Cmd-Left"] = "goLineStartSmart";
|
||||
|
||||
var scrollLineCombo = mac ? "Ctrl-Alt-" : "Ctrl-";
|
||||
|
||||
cmds[map[scrollLineCombo + "Up"] = "scrollLineUp"] = function(cm) {
|
||||
var info = cm.getScrollInfo();
|
||||
if (!cm.somethingSelected()) {
|
||||
var visibleBottomLine = cm.lineAtHeight(info.top + info.clientHeight, "local");
|
||||
if (cm.getCursor().line >= visibleBottomLine)
|
||||
cm.execCommand("goLineUp");
|
||||
}
|
||||
cm.scrollTo(null, info.top - cm.defaultTextHeight());
|
||||
};
|
||||
cmds[map[scrollLineCombo + "Down"] = "scrollLineDown"] = function(cm) {
|
||||
var info = cm.getScrollInfo();
|
||||
if (!cm.somethingSelected()) {
|
||||
var visibleTopLine = cm.lineAtHeight(info.top, "local")+1;
|
||||
if (cm.getCursor().line <= visibleTopLine)
|
||||
cm.execCommand("goLineDown");
|
||||
}
|
||||
cm.scrollTo(null, info.top + cm.defaultTextHeight());
|
||||
};
|
||||
|
||||
cmds[map["Shift-" + ctrl + "L"] = "splitSelectionByLine"] = function(cm) {
|
||||
var ranges = cm.listSelections(), lineRanges = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var from = ranges[i].from(), to = ranges[i].to();
|
||||
for (var line = from.line; line <= to.line; ++line)
|
||||
if (!(to.line > from.line && line == to.line && to.ch == 0))
|
||||
lineRanges.push({anchor: line == from.line ? from : Pos(line, 0),
|
||||
head: line == to.line ? to : Pos(line)});
|
||||
}
|
||||
cm.setSelections(lineRanges, 0);
|
||||
};
|
||||
|
||||
map["Shift-Tab"] = "indentLess";
|
||||
|
||||
cmds[map["Esc"] = "singleSelectionTop"] = function(cm) {
|
||||
var range = cm.listSelections()[0];
|
||||
cm.setSelection(range.anchor, range.head, {scroll: false});
|
||||
};
|
||||
|
||||
cmds[map[ctrl + "L"] = "selectLine"] = function(cm) {
|
||||
var ranges = cm.listSelections(), extended = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
extended.push({anchor: Pos(range.from().line, 0),
|
||||
head: Pos(range.to().line + 1, 0)});
|
||||
}
|
||||
cm.setSelections(extended);
|
||||
};
|
||||
|
||||
map["Shift-Ctrl-K"] = "deleteLine";
|
||||
|
||||
function insertLine(cm, above) {
|
||||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||||
cm.operation(function() {
|
||||
var len = cm.listSelections().length, newSelection = [], last = -1;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var head = cm.listSelections()[i].head;
|
||||
if (head.line <= last) continue;
|
||||
var at = Pos(head.line + (above ? 0 : 1), 0);
|
||||
cm.replaceRange("\n", at, null, "+insertLine");
|
||||
cm.indentLine(at.line, null, true);
|
||||
newSelection.push({head: at, anchor: at});
|
||||
last = head.line + 1;
|
||||
}
|
||||
cm.setSelections(newSelection);
|
||||
});
|
||||
cm.execCommand("indentAuto");
|
||||
}
|
||||
|
||||
cmds[map[ctrl + "Enter"] = "insertLineAfter"] = function(cm) { return insertLine(cm, false); };
|
||||
|
||||
cmds[map["Shift-" + ctrl + "Enter"] = "insertLineBefore"] = function(cm) { return insertLine(cm, true); };
|
||||
|
||||
function wordAt(cm, pos) {
|
||||
var start = pos.ch, end = start, line = cm.getLine(pos.line);
|
||||
while (start && CodeMirror.isWordChar(line.charAt(start - 1))) --start;
|
||||
while (end < line.length && CodeMirror.isWordChar(line.charAt(end))) ++end;
|
||||
return {from: Pos(pos.line, start), to: Pos(pos.line, end), word: line.slice(start, end)};
|
||||
}
|
||||
|
||||
cmds[map[ctrl + "D"] = "selectNextOccurrence"] = function(cm) {
|
||||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||||
var fullWord = cm.state.sublimeFindFullWord == cm.doc.sel;
|
||||
if (CodeMirror.cmpPos(from, to) == 0) {
|
||||
var word = wordAt(cm, from);
|
||||
if (!word.word) return;
|
||||
cm.setSelection(word.from, word.to);
|
||||
fullWord = true;
|
||||
} else {
|
||||
var text = cm.getRange(from, to);
|
||||
var query = fullWord ? new RegExp("\\b" + text + "\\b") : text;
|
||||
var cur = cm.getSearchCursor(query, to);
|
||||
if (cur.findNext()) {
|
||||
cm.addSelection(cur.from(), cur.to());
|
||||
} else {
|
||||
cur = cm.getSearchCursor(query, Pos(cm.firstLine(), 0));
|
||||
if (cur.findNext())
|
||||
cm.addSelection(cur.from(), cur.to());
|
||||
}
|
||||
}
|
||||
if (fullWord)
|
||||
cm.state.sublimeFindFullWord = cm.doc.sel;
|
||||
};
|
||||
|
||||
var mirror = "(){}[]";
|
||||
function selectBetweenBrackets(cm) {
|
||||
var pos = cm.getCursor(), opening = cm.scanForBracket(pos, -1);
|
||||
if (!opening) return;
|
||||
for (;;) {
|
||||
var closing = cm.scanForBracket(pos, 1);
|
||||
if (!closing) return;
|
||||
if (closing.ch == mirror.charAt(mirror.indexOf(opening.ch) + 1)) {
|
||||
cm.setSelection(Pos(opening.pos.line, opening.pos.ch + 1), closing.pos, false);
|
||||
return true;
|
||||
}
|
||||
pos = Pos(closing.pos.line, closing.pos.ch + 1);
|
||||
}
|
||||
}
|
||||
|
||||
cmds[map["Shift-" + ctrl + "Space"] = "selectScope"] = function(cm) {
|
||||
selectBetweenBrackets(cm) || cm.execCommand("selectAll");
|
||||
};
|
||||
cmds[map["Shift-" + ctrl + "M"] = "selectBetweenBrackets"] = function(cm) {
|
||||
if (!selectBetweenBrackets(cm)) return CodeMirror.Pass;
|
||||
};
|
||||
|
||||
cmds[map[ctrl + "M"] = "goToBracket"] = function(cm) {
|
||||
cm.extendSelectionsBy(function(range) {
|
||||
var next = cm.scanForBracket(range.head, 1);
|
||||
if (next && CodeMirror.cmpPos(next.pos, range.head) != 0) return next.pos;
|
||||
var prev = cm.scanForBracket(range.head, -1);
|
||||
return prev && Pos(prev.pos.line, prev.pos.ch + 1) || range.head;
|
||||
});
|
||||
};
|
||||
|
||||
var swapLineCombo = mac ? "Cmd-Ctrl-" : "Shift-Ctrl-";
|
||||
|
||||
cmds[map[swapLineCombo + "Up"] = "swapLineUp"] = function(cm) {
|
||||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||||
var ranges = cm.listSelections(), linesToMove = [], at = cm.firstLine() - 1, newSels = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i], from = range.from().line - 1, to = range.to().line;
|
||||
newSels.push({anchor: Pos(range.anchor.line - 1, range.anchor.ch),
|
||||
head: Pos(range.head.line - 1, range.head.ch)});
|
||||
if (range.to().ch == 0 && !range.empty()) --to;
|
||||
if (from > at) linesToMove.push(from, to);
|
||||
else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to;
|
||||
at = to;
|
||||
}
|
||||
cm.operation(function() {
|
||||
for (var i = 0; i < linesToMove.length; i += 2) {
|
||||
var from = linesToMove[i], to = linesToMove[i + 1];
|
||||
var line = cm.getLine(from);
|
||||
cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine");
|
||||
if (to > cm.lastLine())
|
||||
cm.replaceRange("\n" + line, Pos(cm.lastLine()), null, "+swapLine");
|
||||
else
|
||||
cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine");
|
||||
}
|
||||
cm.setSelections(newSels);
|
||||
cm.scrollIntoView();
|
||||
});
|
||||
};
|
||||
|
||||
cmds[map[swapLineCombo + "Down"] = "swapLineDown"] = function(cm) {
|
||||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||||
var ranges = cm.listSelections(), linesToMove = [], at = cm.lastLine() + 1;
|
||||
for (var i = ranges.length - 1; i >= 0; i--) {
|
||||
var range = ranges[i], from = range.to().line + 1, to = range.from().line;
|
||||
if (range.to().ch == 0 && !range.empty()) from--;
|
||||
if (from < at) linesToMove.push(from, to);
|
||||
else if (linesToMove.length) linesToMove[linesToMove.length - 1] = to;
|
||||
at = to;
|
||||
}
|
||||
cm.operation(function() {
|
||||
for (var i = linesToMove.length - 2; i >= 0; i -= 2) {
|
||||
var from = linesToMove[i], to = linesToMove[i + 1];
|
||||
var line = cm.getLine(from);
|
||||
if (from == cm.lastLine())
|
||||
cm.replaceRange("", Pos(from - 1), Pos(from), "+swapLine");
|
||||
else
|
||||
cm.replaceRange("", Pos(from, 0), Pos(from + 1, 0), "+swapLine");
|
||||
cm.replaceRange(line + "\n", Pos(to, 0), null, "+swapLine");
|
||||
}
|
||||
cm.scrollIntoView();
|
||||
});
|
||||
};
|
||||
|
||||
cmds[map[ctrl + "/"] = "toggleCommentIndented"] = function(cm) {
|
||||
cm.toggleComment({ indent: true });
|
||||
}
|
||||
|
||||
cmds[map[ctrl + "J"] = "joinLines"] = function(cm) {
|
||||
var ranges = cm.listSelections(), joined = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i], from = range.from();
|
||||
var start = from.line, end = range.to().line;
|
||||
while (i < ranges.length - 1 && ranges[i + 1].from().line == end)
|
||||
end = ranges[++i].to().line;
|
||||
joined.push({start: start, end: end, anchor: !range.empty() && from});
|
||||
}
|
||||
cm.operation(function() {
|
||||
var offset = 0, ranges = [];
|
||||
for (var i = 0; i < joined.length; i++) {
|
||||
var obj = joined[i];
|
||||
var anchor = obj.anchor && Pos(obj.anchor.line - offset, obj.anchor.ch), head;
|
||||
for (var line = obj.start; line <= obj.end; line++) {
|
||||
var actual = line - offset;
|
||||
if (line == obj.end) head = Pos(actual, cm.getLine(actual).length + 1);
|
||||
if (actual < cm.lastLine()) {
|
||||
cm.replaceRange(" ", Pos(actual), Pos(actual + 1, /^\s*/.exec(cm.getLine(actual + 1))[0].length));
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
ranges.push({anchor: anchor || head, head: head});
|
||||
}
|
||||
cm.setSelections(ranges, 0);
|
||||
});
|
||||
};
|
||||
|
||||
cmds[map["Shift-" + ctrl + "D"] = "duplicateLine"] = function(cm) {
|
||||
cm.operation(function() {
|
||||
var rangeCount = cm.listSelections().length;
|
||||
for (var i = 0; i < rangeCount; i++) {
|
||||
var range = cm.listSelections()[i];
|
||||
if (range.empty())
|
||||
cm.replaceRange(cm.getLine(range.head.line) + "\n", Pos(range.head.line, 0));
|
||||
else
|
||||
cm.replaceRange(cm.getRange(range.from(), range.to()), range.from());
|
||||
}
|
||||
cm.scrollIntoView();
|
||||
});
|
||||
};
|
||||
|
||||
if (!mac) map[ctrl + "T"] = "transposeChars";
|
||||
|
||||
function sortLines(cm, caseSensitive) {
|
||||
if (cm.isReadOnly()) return CodeMirror.Pass
|
||||
var ranges = cm.listSelections(), toSort = [], selected;
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (range.empty()) continue;
|
||||
var from = range.from().line, to = range.to().line;
|
||||
while (i < ranges.length - 1 && ranges[i + 1].from().line == to)
|
||||
to = range[++i].to().line;
|
||||
toSort.push(from, to);
|
||||
}
|
||||
if (toSort.length) selected = true;
|
||||
else toSort.push(cm.firstLine(), cm.lastLine());
|
||||
|
||||
cm.operation(function() {
|
||||
var ranges = [];
|
||||
for (var i = 0; i < toSort.length; i += 2) {
|
||||
var from = toSort[i], to = toSort[i + 1];
|
||||
var start = Pos(from, 0), end = Pos(to);
|
||||
var lines = cm.getRange(start, end, false);
|
||||
if (caseSensitive)
|
||||
lines.sort();
|
||||
else
|
||||
lines.sort(function(a, b) {
|
||||
var au = a.toUpperCase(), bu = b.toUpperCase();
|
||||
if (au != bu) { a = au; b = bu; }
|
||||
return a < b ? -1 : a == b ? 0 : 1;
|
||||
});
|
||||
cm.replaceRange(lines, start, end);
|
||||
if (selected) ranges.push({anchor: start, head: end});
|
||||
}
|
||||
if (selected) cm.setSelections(ranges, 0);
|
||||
});
|
||||
}
|
||||
|
||||
cmds[map["F9"] = "sortLines"] = function(cm) { sortLines(cm, true); };
|
||||
cmds[map[ctrl + "F9"] = "sortLinesInsensitive"] = function(cm) { sortLines(cm, false); };
|
||||
|
||||
cmds[map["F2"] = "nextBookmark"] = function(cm) {
|
||||
var marks = cm.state.sublimeBookmarks;
|
||||
if (marks) while (marks.length) {
|
||||
var current = marks.shift();
|
||||
var found = current.find();
|
||||
if (found) {
|
||||
marks.push(current);
|
||||
return cm.setSelection(found.from, found.to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cmds[map["Shift-F2"] = "prevBookmark"] = function(cm) {
|
||||
var marks = cm.state.sublimeBookmarks;
|
||||
if (marks) while (marks.length) {
|
||||
marks.unshift(marks.pop());
|
||||
var found = marks[marks.length - 1].find();
|
||||
if (!found)
|
||||
marks.pop();
|
||||
else
|
||||
return cm.setSelection(found.from, found.to);
|
||||
}
|
||||
};
|
||||
|
||||
cmds[map[ctrl + "F2"] = "toggleBookmark"] = function(cm) {
|
||||
var ranges = cm.listSelections();
|
||||
var marks = cm.state.sublimeBookmarks || (cm.state.sublimeBookmarks = []);
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var from = ranges[i].from(), to = ranges[i].to();
|
||||
var found = cm.findMarks(from, to);
|
||||
for (var j = 0; j < found.length; j++) {
|
||||
if (found[j].sublimeBookmark) {
|
||||
found[j].clear();
|
||||
for (var k = 0; k < marks.length; k++)
|
||||
if (marks[k] == found[j])
|
||||
marks.splice(k--, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == found.length)
|
||||
marks.push(cm.markText(from, to, {sublimeBookmark: true, clearWhenEmpty: false}));
|
||||
}
|
||||
};
|
||||
|
||||
cmds[map["Shift-" + ctrl + "F2"] = "clearBookmarks"] = function(cm) {
|
||||
var marks = cm.state.sublimeBookmarks;
|
||||
if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear();
|
||||
marks.length = 0;
|
||||
};
|
||||
|
||||
cmds[map["Alt-F2"] = "selectBookmarks"] = function(cm) {
|
||||
var marks = cm.state.sublimeBookmarks, ranges = [];
|
||||
if (marks) for (var i = 0; i < marks.length; i++) {
|
||||
var found = marks[i].find();
|
||||
if (!found)
|
||||
marks.splice(i--, 0);
|
||||
else
|
||||
ranges.push({anchor: found.from, head: found.to});
|
||||
}
|
||||
if (ranges.length)
|
||||
cm.setSelections(ranges, 0);
|
||||
};
|
||||
|
||||
map["Alt-Q"] = "wrapLines";
|
||||
|
||||
var cK = ctrl + "K ";
|
||||
|
||||
function modifyWordOrSelection(cm, mod) {
|
||||
cm.operation(function() {
|
||||
var ranges = cm.listSelections(), indices = [], replacements = [];
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (range.empty()) { indices.push(i); replacements.push(""); }
|
||||
else replacements.push(mod(cm.getRange(range.from(), range.to())));
|
||||
}
|
||||
cm.replaceSelections(replacements, "around", "case");
|
||||
for (var i = indices.length - 1, at; i >= 0; i--) {
|
||||
var range = ranges[indices[i]];
|
||||
if (at && CodeMirror.cmpPos(range.head, at) > 0) continue;
|
||||
var word = wordAt(cm, range.head);
|
||||
at = word.from;
|
||||
cm.replaceRange(mod(word.word), word.from, word.to);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map[cK + ctrl + "Backspace"] = "delLineLeft";
|
||||
|
||||
cmds[map["Backspace"] = "smartBackspace"] = function(cm) {
|
||||
if (cm.somethingSelected()) return CodeMirror.Pass;
|
||||
|
||||
cm.operation(function() {
|
||||
var cursors = cm.listSelections();
|
||||
var indentUnit = cm.getOption("indentUnit");
|
||||
|
||||
for (var i = cursors.length - 1; i >= 0; i--) {
|
||||
var cursor = cursors[i].head;
|
||||
var toStartOfLine = cm.getRange({line: cursor.line, ch: 0}, cursor);
|
||||
var column = CodeMirror.countColumn(toStartOfLine, null, cm.getOption("tabSize"));
|
||||
|
||||
// Delete by one character by default
|
||||
var deletePos = cm.findPosH(cursor, -1, "char", false);
|
||||
|
||||
if (toStartOfLine && !/\S/.test(toStartOfLine) && column % indentUnit == 0) {
|
||||
var prevIndent = new Pos(cursor.line,
|
||||
CodeMirror.findColumn(toStartOfLine, column - indentUnit, indentUnit));
|
||||
|
||||
// Smart delete only if we found a valid prevIndent location
|
||||
if (prevIndent.ch != cursor.ch) deletePos = prevIndent;
|
||||
}
|
||||
|
||||
cm.replaceRange("", deletePos, cursor, "+delete");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
cmds[map[cK + ctrl + "K"] = "delLineRight"] = function(cm) {
|
||||
cm.operation(function() {
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = ranges.length - 1; i >= 0; i--)
|
||||
cm.replaceRange("", ranges[i].anchor, Pos(ranges[i].to().line), "+delete");
|
||||
cm.scrollIntoView();
|
||||
});
|
||||
};
|
||||
|
||||
cmds[map[cK + ctrl + "U"] = "upcaseAtCursor"] = function(cm) {
|
||||
modifyWordOrSelection(cm, function(str) { return str.toUpperCase(); });
|
||||
};
|
||||
cmds[map[cK + ctrl + "L"] = "downcaseAtCursor"] = function(cm) {
|
||||
modifyWordOrSelection(cm, function(str) { return str.toLowerCase(); });
|
||||
};
|
||||
|
||||
cmds[map[cK + ctrl + "Space"] = "setSublimeMark"] = function(cm) {
|
||||
if (cm.state.sublimeMark) cm.state.sublimeMark.clear();
|
||||
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
|
||||
};
|
||||
cmds[map[cK + ctrl + "A"] = "selectToSublimeMark"] = function(cm) {
|
||||
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
|
||||
if (found) cm.setSelection(cm.getCursor(), found);
|
||||
};
|
||||
cmds[map[cK + ctrl + "W"] = "deleteToSublimeMark"] = function(cm) {
|
||||
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
|
||||
if (found) {
|
||||
var from = cm.getCursor(), to = found;
|
||||
if (CodeMirror.cmpPos(from, to) > 0) { var tmp = to; to = from; from = tmp; }
|
||||
cm.state.sublimeKilled = cm.getRange(from, to);
|
||||
cm.replaceRange("", from, to);
|
||||
}
|
||||
};
|
||||
cmds[map[cK + ctrl + "X"] = "swapWithSublimeMark"] = function(cm) {
|
||||
var found = cm.state.sublimeMark && cm.state.sublimeMark.find();
|
||||
if (found) {
|
||||
cm.state.sublimeMark.clear();
|
||||
cm.state.sublimeMark = cm.setBookmark(cm.getCursor());
|
||||
cm.setCursor(found);
|
||||
}
|
||||
};
|
||||
cmds[map[cK + ctrl + "Y"] = "sublimeYank"] = function(cm) {
|
||||
if (cm.state.sublimeKilled != null)
|
||||
cm.replaceSelection(cm.state.sublimeKilled, null, "paste");
|
||||
};
|
||||
|
||||
map[cK + ctrl + "G"] = "clearBookmarks";
|
||||
cmds[map[cK + ctrl + "C"] = "showInCenter"] = function(cm) {
|
||||
var pos = cm.cursorCoords(null, "local");
|
||||
cm.scrollTo(null, (pos.top + pos.bottom) / 2 - cm.getScrollInfo().clientHeight / 2);
|
||||
};
|
||||
|
||||
var selectLinesCombo = mac ? "Ctrl-Shift-" : "Ctrl-Alt-";
|
||||
cmds[map[selectLinesCombo + "Up"] = "selectLinesUpward"] = function(cm) {
|
||||
cm.operation(function() {
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (range.head.line > cm.firstLine())
|
||||
cm.addSelection(Pos(range.head.line - 1, range.head.ch));
|
||||
}
|
||||
});
|
||||
};
|
||||
cmds[map[selectLinesCombo + "Down"] = "selectLinesDownward"] = function(cm) {
|
||||
cm.operation(function() {
|
||||
var ranges = cm.listSelections();
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
var range = ranges[i];
|
||||
if (range.head.line < cm.lastLine())
|
||||
cm.addSelection(Pos(range.head.line + 1, range.head.ch));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function getTarget(cm) {
|
||||
var from = cm.getCursor("from"), to = cm.getCursor("to");
|
||||
if (CodeMirror.cmpPos(from, to) == 0) {
|
||||
var word = wordAt(cm, from);
|
||||
if (!word.word) return;
|
||||
from = word.from;
|
||||
to = word.to;
|
||||
}
|
||||
return {from: from, to: to, query: cm.getRange(from, to), word: word};
|
||||
}
|
||||
|
||||
function findAndGoTo(cm, forward) {
|
||||
var target = getTarget(cm);
|
||||
if (!target) return;
|
||||
var query = target.query;
|
||||
var cur = cm.getSearchCursor(query, forward ? target.to : target.from);
|
||||
|
||||
if (forward ? cur.findNext() : cur.findPrevious()) {
|
||||
cm.setSelection(cur.from(), cur.to());
|
||||
} else {
|
||||
cur = cm.getSearchCursor(query, forward ? Pos(cm.firstLine(), 0)
|
||||
: cm.clipPos(Pos(cm.lastLine())));
|
||||
if (forward ? cur.findNext() : cur.findPrevious())
|
||||
cm.setSelection(cur.from(), cur.to());
|
||||
else if (target.word)
|
||||
cm.setSelection(target.from, target.to);
|
||||
}
|
||||
};
|
||||
cmds[map[ctrl + "F3"] = "findUnder"] = function(cm) { findAndGoTo(cm, true); };
|
||||
cmds[map["Shift-" + ctrl + "F3"] = "findUnderPrevious"] = function(cm) { findAndGoTo(cm,false); };
|
||||
cmds[map["Alt-F3"] = "findAllUnder"] = function(cm) {
|
||||
var target = getTarget(cm);
|
||||
if (!target) return;
|
||||
var cur = cm.getSearchCursor(target.query);
|
||||
var matches = [];
|
||||
var primaryIndex = -1;
|
||||
while (cur.findNext()) {
|
||||
matches.push({anchor: cur.from(), head: cur.to()});
|
||||
if (cur.from().line <= target.from.line && cur.from().ch <= target.from.ch)
|
||||
primaryIndex++;
|
||||
}
|
||||
cm.setSelections(matches, primaryIndex);
|
||||
};
|
||||
|
||||
map["Shift-" + ctrl + "["] = "fold";
|
||||
map["Shift-" + ctrl + "]"] = "unfold";
|
||||
map[cK + ctrl + "0"] = map[cK + ctrl + "J"] = "unfoldAll";
|
||||
|
||||
map[ctrl + "I"] = "findIncremental";
|
||||
map["Shift-" + ctrl + "I"] = "findIncrementalReverse";
|
||||
map[ctrl + "H"] = "replace";
|
||||
map["F3"] = "findNext";
|
||||
map["Shift-F3"] = "findPrev";
|
||||
|
||||
CodeMirror.normalizeKeyMap(map);
|
||||
});
|
5088
BrowserMark/js/codemirror/keymap/vim.js
vendored
Normal file
341
BrowserMark/js/codemirror/lib/codemirror.css
vendored
Normal file
@ -0,0 +1,341 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 280px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0 !important;
|
||||
background: #7e7;
|
||||
}
|
||||
.cm-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cm-animate-fat-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
-webkit-animation: blink 1.06s steps(1) infinite;
|
||||
-moz-animation: blink 1.06s steps(1) infinite;
|
||||
animation: blink 1.06s steps(1) infinite;
|
||||
background-color: #7e7;
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror-overwrite .CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-rulers {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: -50px; bottom: -20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
top: 0; bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3 {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
.CodeMirror-composing { border-bottom: 2px solid; }
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actual scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
min-height: 100%;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-bottom: -30px;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.CodeMirror-gutter-background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
-webkit-font-variant-ligatures: none;
|
||||
font-variant-ligatures: none;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-code {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Force content-box sizing for the elements where we expect it */
|
||||
.CodeMirror-scroll,
|
||||
.CodeMirror-sizer,
|
||||
.CodeMirror-gutter,
|
||||
.CodeMirror-gutters,
|
||||
.CodeMirror-linenumber {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
div.CodeMirror-dragcursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
||||
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* See issue #2901 */
|
||||
.cm-tab-wrap-hack:after { content: ''; }
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
9109
BrowserMark/js/codemirror/lib/codemirror.js
vendored
Normal file
361
BrowserMark/js/codemirror/mode/markdown/index.html
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
<!doctype html>
|
||||
|
||||
<title>CodeMirror: Markdown mode</title>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel=stylesheet href="../../doc/docs.css">
|
||||
|
||||
<link rel="stylesheet" href="../../lib/codemirror.css">
|
||||
<script src="../../lib/codemirror.js"></script>
|
||||
<script src="../../addon/edit/continuelist.js"></script>
|
||||
<!-- <script src="../xml/xml.js"></script> -->
|
||||
<script src="markdown.js"></script>
|
||||
<!-- <style type="text/css">
|
||||
.CodeMirror {border-top: 1px solid black; border-bottom: 1px solid black;}
|
||||
.cm-s-default .cm-trailing-space-a:before,
|
||||
.cm-s-default .cm-trailing-space-b:before {position: absolute; content: "\00B7"; color: #777;}
|
||||
.cm-s-default .cm-trailing-space-new-line:before {position: absolute; content: "\21B5"; color: #777;}
|
||||
</style> -->
|
||||
<!-- <div id=nav>
|
||||
<a href="http://codemirror.net"><h1>CodeMirror</h1><img id=logo src="../../doc/logo.png"></a>
|
||||
|
||||
<ul>
|
||||
<li><a href="../../index.html">Home</a>
|
||||
<li><a href="../../doc/manual.html">Manual</a>
|
||||
<li><a href="https://github.com/codemirror/codemirror">Code</a>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="../index.html">Language modes</a>
|
||||
<li><a class=active href="#">Markdown</a>
|
||||
</ul>
|
||||
</div> -->
|
||||
|
||||
<article>
|
||||
<h2>Markdown mode</h2>
|
||||
<form><textarea id="code" name="code">
|
||||
Markdown: Basics
|
||||
================
|
||||
|
||||
<ul id="ProjectSubmenu">
|
||||
<li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
|
||||
<li><a class="selected" title="Markdown Basics">Basics</a></li>
|
||||
<li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
|
||||
<li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
|
||||
<li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
Getting the Gist of Markdown's Formatting Syntax
|
||||
------------------------------------------------
|
||||
|
||||
This page offers a brief overview of what it's like to use Markdown.
|
||||
The [syntax page] [s] provides complete, detailed documentation for
|
||||
every feature, but Markdown should be very easy to pick up simply by
|
||||
looking at a few examples of it in action. The examples on this page
|
||||
are written in a before/after style, showing example syntax and the
|
||||
HTML output produced by Markdown.
|
||||
|
||||
It's also helpful to simply try Markdown out; the [Dingus] [d] is a
|
||||
web application that allows you type your own Markdown-formatted text
|
||||
and translate it to XHTML.
|
||||
|
||||
**Note:** This document is itself written using Markdown; you
|
||||
can [see the source for it by adding '.text' to the URL] [src].
|
||||
|
||||
[s]: /projects/markdown/syntax "Markdown Syntax"
|
||||
[d]: /projects/markdown/dingus "Markdown Dingus"
|
||||
[src]: /projects/markdown/basics.text
|
||||
|
||||
|
||||
## Paragraphs, Headers, Blockquotes ##
|
||||
|
||||
A paragraph is simply one or more consecutive lines of text, separated
|
||||
by one or more blank lines. (A blank line is any line that looks like
|
||||
a blank line -- a line containing nothing but spaces or tabs is
|
||||
considered blank.) Normal paragraphs should not be indented with
|
||||
spaces or tabs.
|
||||
|
||||
Markdown offers two styles of headers: *Setext* and *atx*.
|
||||
Setext-style headers for `<h1>` and `<h2>` are created by
|
||||
"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
|
||||
To create an atx-style header, you put 1-6 hash marks (`#`) at the
|
||||
beginning of the line -- the number of hashes equals the resulting
|
||||
HTML header level.
|
||||
|
||||
Blockquotes are indicated using email-style '`>`' angle brackets.
|
||||
|
||||
Markdown:
|
||||
|
||||
A First Level Header
|
||||
====================
|
||||
|
||||
A Second Level Header
|
||||
---------------------
|
||||
|
||||
Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.
|
||||
|
||||
The quick brown fox jumped over the lazy
|
||||
dog's back.
|
||||
|
||||
### Header 3
|
||||
|
||||
> This is a blockquote.
|
||||
>
|
||||
> This is the second paragraph in the blockquote.
|
||||
>
|
||||
> ## This is an H2 in a blockquote
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
<h1>A First Level Header</h1>
|
||||
|
||||
<h2>A Second Level Header</h2>
|
||||
|
||||
<p>Now is the time for all good men to come to
|
||||
the aid of their country. This is just a
|
||||
regular paragraph.</p>
|
||||
|
||||
<p>The quick brown fox jumped over the lazy
|
||||
dog's back.</p>
|
||||
|
||||
<h3>Header 3</h3>
|
||||
|
||||
<blockquote>
|
||||
<p>This is a blockquote.</p>
|
||||
|
||||
<p>This is the second paragraph in the blockquote.</p>
|
||||
|
||||
<h2>This is an H2 in a blockquote</h2>
|
||||
</blockquote>
|
||||
|
||||
|
||||
|
||||
### Phrase Emphasis ###
|
||||
|
||||
Markdown uses asterisks and underscores to indicate spans of emphasis.
|
||||
|
||||
Markdown:
|
||||
|
||||
Some of these words *are emphasized*.
|
||||
Some of these words _are emphasized also_.
|
||||
|
||||
Use two asterisks for **strong emphasis**.
|
||||
Or, if you prefer, __use two underscores instead__.
|
||||
|
||||
Output:
|
||||
|
||||
<p>Some of these words <em>are emphasized</em>.
|
||||
Some of these words <em>are emphasized also</em>.</p>
|
||||
|
||||
<p>Use two asterisks for <strong>strong emphasis</strong>.
|
||||
Or, if you prefer, <strong>use two underscores instead</strong>.</p>
|
||||
|
||||
|
||||
|
||||
## Lists ##
|
||||
|
||||
Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
|
||||
`+`, and `-`) as list markers. These three markers are
|
||||
interchangable; this:
|
||||
|
||||
* Candy.
|
||||
* Gum.
|
||||
* Booze.
|
||||
|
||||
this:
|
||||
|
||||
+ Candy.
|
||||
+ Gum.
|
||||
+ Booze.
|
||||
|
||||
and this:
|
||||
|
||||
- Candy.
|
||||
- Gum.
|
||||
- Booze.
|
||||
|
||||
all produce the same output:
|
||||
|
||||
<ul>
|
||||
<li>Candy.</li>
|
||||
<li>Gum.</li>
|
||||
<li>Booze.</li>
|
||||
</ul>
|
||||
|
||||
Ordered (numbered) lists use regular numbers, followed by periods, as
|
||||
list markers:
|
||||
|
||||
1. Red
|
||||
2. Green
|
||||
3. Blue
|
||||
|
||||
Output:
|
||||
|
||||
<ol>
|
||||
<li>Red</li>
|
||||
<li>Green</li>
|
||||
<li>Blue</li>
|
||||
</ol>
|
||||
|
||||
If you put blank lines between items, you'll get `<p>` tags for the
|
||||
list item text. You can create multi-paragraph list items by indenting
|
||||
the paragraphs by 4 spaces or 1 tab:
|
||||
|
||||
* A list item.
|
||||
|
||||
With multiple paragraphs.
|
||||
|
||||
* Another item in the list.
|
||||
|
||||
Output:
|
||||
|
||||
<ul>
|
||||
<li><p>A list item.</p>
|
||||
<p>With multiple paragraphs.</p></li>
|
||||
<li><p>Another item in the list.</p></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
### Links ###
|
||||
|
||||
Markdown supports two styles for creating links: *inline* and
|
||||
*reference*. With both styles, you use square brackets to delimit the
|
||||
text you want to turn into a link.
|
||||
|
||||
Inline-style links use parentheses immediately after the link text.
|
||||
For example:
|
||||
|
||||
This is an [example link](http://example.com/).
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/">
|
||||
example link</a>.</p>
|
||||
|
||||
Optionally, you may include a title attribute in the parentheses:
|
||||
|
||||
This is an [example link](http://example.com/ "With a Title").
|
||||
|
||||
Output:
|
||||
|
||||
<p>This is an <a href="http://example.com/" title="With a Title">
|
||||
example link</a>.</p>
|
||||
|
||||
Reference-style links allow you to refer to your links by names, which
|
||||
you define elsewhere in your document:
|
||||
|
||||
I get 10 times more traffic from [Google][1] than from
|
||||
[Yahoo][2] or [MSN][3].
|
||||
|
||||
[1]: http://google.com/ "Google"
|
||||
[2]: http://search.yahoo.com/ "Yahoo Search"
|
||||
[3]: http://search.msn.com/ "MSN Search"
|
||||
|
||||
Output:
|
||||
|
||||
<p>I get 10 times more traffic from <a href="http://google.com/"
|
||||
title="Google">Google</a> than from <a href="http://search.yahoo.com/"
|
||||
title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
|
||||
title="MSN Search">MSN</a>.</p>
|
||||
|
||||
The title attribute is optional. Link names may contain letters,
|
||||
numbers and spaces, but are *not* case sensitive:
|
||||
|
||||
I start my morning with a cup of coffee and
|
||||
[The New York Times][NY Times].
|
||||
|
||||
[ny times]: http://www.nytimes.com/
|
||||
|
||||
Output:
|
||||
|
||||
<p>I start my morning with a cup of coffee and
|
||||
<a href="http://www.nytimes.com/">The New York Times</a>.</p>
|
||||
|
||||
|
||||
### Images ###
|
||||
|
||||
Image syntax is very much like link syntax.
|
||||
|
||||
Inline (titles are optional):
|
||||
|
||||

|
||||
|
||||
Reference-style:
|
||||
|
||||
![alt text][id]
|
||||
|
||||
[id]: /path/to/img.jpg "Title"
|
||||
|
||||
Both of the above examples produce the same output:
|
||||
|
||||
<img src="/path/to/img.jpg" alt="alt text" title="Title" />
|
||||
|
||||
|
||||
|
||||
### Code ###
|
||||
|
||||
In a regular paragraph, you can create code span by wrapping text in
|
||||
backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
|
||||
`>`) will automatically be translated into HTML entities. This makes
|
||||
it easy to use Markdown to write about HTML example code:
|
||||
|
||||
I strongly recommend against using any `<blink>` tags.
|
||||
|
||||
I wish SmartyPants used named entities like `&mdash;`
|
||||
instead of decimal-encoded entites like `&#8212;`.
|
||||
|
||||
Output:
|
||||
|
||||
<p>I strongly recommend against using any
|
||||
<code>&lt;blink&gt;</code> tags.</p>
|
||||
|
||||
<p>I wish SmartyPants used named entities like
|
||||
<code>&amp;mdash;</code> instead of decimal-encoded
|
||||
entites like <code>&amp;#8212;</code>.</p>
|
||||
|
||||
|
||||
To specify an entire block of pre-formatted code, indent every line of
|
||||
the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
|
||||
and `>` characters will be escaped automatically.
|
||||
|
||||
Markdown:
|
||||
|
||||
If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:
|
||||
|
||||
<blockquote>
|
||||
<p>For example.</p>
|
||||
</blockquote>
|
||||
|
||||
Output:
|
||||
|
||||
<p>If you want your page to validate under XHTML 1.0 Strict,
|
||||
you've got to put paragraph tags in your blockquotes:</p>
|
||||
|
||||
<pre><code>&lt;blockquote&gt;
|
||||
&lt;p&gt;For example.&lt;/p&gt;
|
||||
&lt;/blockquote&gt;
|
||||
</code></pre>
|
||||
</textarea></form>
|
||||
|
||||
<script>
|
||||
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
|
||||
mode: 'markdown',
|
||||
lineNumbers: true,
|
||||
theme: "default",
|
||||
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
|
||||
});
|
||||
</script>
|
||||
|
||||
<p>You might want to use the <a href="../gfm/index.html">Github-Flavored Markdown mode</a> instead, which adds support for fenced code blocks and a few other things.</p>
|
||||
|
||||
<p>Optionally depends on the XML mode for properly highlighted inline XML blocks.</p>
|
||||
|
||||
<p><strong>MIME types defined:</strong> <code>text/x-markdown</code>.</p>
|
||||
|
||||
<p><strong>Parsing/Highlighting Tests:</strong> <a href="../../test/index.html#markdown_*">normal</a>, <a href="../../test/index.html#verbose,markdown_*">verbose</a>.</p>
|
||||
|
||||
</article>
|
813
BrowserMark/js/codemirror/mode/markdown/markdown.js
vendored
Normal file
@ -0,0 +1,813 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
|
||||
|
||||
var htmlMode = CodeMirror.getMode(cmCfg, "text/html");
|
||||
var htmlModeMissing = htmlMode.name == "null"
|
||||
|
||||
function getMode(name) {
|
||||
if (CodeMirror.findModeByName) {
|
||||
var found = CodeMirror.findModeByName(name);
|
||||
if (found) name = found.mime || found.mimes[0];
|
||||
}
|
||||
var mode = CodeMirror.getMode(cmCfg, name);
|
||||
return mode.name == "null" ? null : mode;
|
||||
}
|
||||
|
||||
// Should characters that affect highlighting be highlighted separate?
|
||||
// Does not include characters that will be output (such as `1.` and `-` for lists)
|
||||
if (modeCfg.highlightFormatting === undefined)
|
||||
modeCfg.highlightFormatting = false;
|
||||
|
||||
// Maximum number of nested blockquotes. Set to 0 for infinite nesting.
|
||||
// Excess `>` will emit `error` token.
|
||||
if (modeCfg.maxBlockquoteDepth === undefined)
|
||||
modeCfg.maxBlockquoteDepth = 0;
|
||||
|
||||
// Should underscores in words open/close em/strong?
|
||||
if (modeCfg.underscoresBreakWords === undefined)
|
||||
modeCfg.underscoresBreakWords = true;
|
||||
|
||||
// Use `fencedCodeBlocks` to configure fenced code blocks. false to
|
||||
// disable, string to specify a precise regexp that the fence should
|
||||
// match, and true to allow three or more backticks or tildes (as
|
||||
// per CommonMark).
|
||||
|
||||
// Turn on task lists? ("- [ ] " and "- [x] ")
|
||||
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
|
||||
|
||||
// Turn on strikethrough syntax
|
||||
if (modeCfg.strikethrough === undefined)
|
||||
modeCfg.strikethrough = false;
|
||||
|
||||
// Allow token types to be overridden by user-provided token types.
|
||||
if (modeCfg.tokenTypeOverrides === undefined)
|
||||
modeCfg.tokenTypeOverrides = {};
|
||||
|
||||
var tokenTypes = {
|
||||
header: "header",
|
||||
code: "comment",
|
||||
quote: "quote",
|
||||
list1: "variable-2",
|
||||
list2: "variable-3",
|
||||
list3: "keyword",
|
||||
hr: "hr",
|
||||
image: "image",
|
||||
imageAltText: "image-alt-text",
|
||||
imageMarker: "image-marker",
|
||||
formatting: "formatting",
|
||||
linkInline: "link",
|
||||
linkEmail: "link",
|
||||
linkText: "link",
|
||||
linkHref: "string",
|
||||
em: "em",
|
||||
strong: "strong",
|
||||
strikethrough: "strikethrough"
|
||||
};
|
||||
|
||||
for (var tokenType in tokenTypes) {
|
||||
if (tokenTypes.hasOwnProperty(tokenType) && modeCfg.tokenTypeOverrides[tokenType]) {
|
||||
tokenTypes[tokenType] = modeCfg.tokenTypeOverrides[tokenType];
|
||||
}
|
||||
}
|
||||
|
||||
var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
|
||||
, listRE = /^(?:[*\-+]|^[0-9]+([.)]))\s+/
|
||||
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow listRE
|
||||
, atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
|
||||
, setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
|
||||
, textRE = /^[^#!\[\]*_\\<>` "'(~]+/
|
||||
, fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) +
|
||||
")[ \\t]*([\\w+#\-]*)");
|
||||
|
||||
function switchInline(stream, state, f) {
|
||||
state.f = state.inline = f;
|
||||
return f(stream, state);
|
||||
}
|
||||
|
||||
function switchBlock(stream, state, f) {
|
||||
state.f = state.block = f;
|
||||
return f(stream, state);
|
||||
}
|
||||
|
||||
function lineIsEmpty(line) {
|
||||
return !line || !/\S/.test(line.string)
|
||||
}
|
||||
|
||||
// Blocks
|
||||
|
||||
function blankLine(state) {
|
||||
// Reset linkTitle state
|
||||
state.linkTitle = false;
|
||||
// Reset EM state
|
||||
state.em = false;
|
||||
// Reset STRONG state
|
||||
state.strong = false;
|
||||
// Reset strikethrough state
|
||||
state.strikethrough = false;
|
||||
// Reset state.quote
|
||||
state.quote = 0;
|
||||
// Reset state.indentedCode
|
||||
state.indentedCode = false;
|
||||
if (htmlModeMissing && state.f == htmlBlock) {
|
||||
state.f = inlineNormal;
|
||||
state.block = blockNormal;
|
||||
}
|
||||
// Reset state.trailingSpace
|
||||
state.trailingSpace = 0;
|
||||
state.trailingSpaceNewLine = false;
|
||||
// Mark this line as blank
|
||||
state.prevLine = state.thisLine
|
||||
state.thisLine = null
|
||||
return null;
|
||||
}
|
||||
|
||||
function blockNormal(stream, state) {
|
||||
|
||||
var sol = stream.sol();
|
||||
|
||||
var prevLineIsList = state.list !== false,
|
||||
prevLineIsIndentedCode = state.indentedCode;
|
||||
|
||||
state.indentedCode = false;
|
||||
|
||||
if (prevLineIsList) {
|
||||
if (state.indentationDiff >= 0) { // Continued list
|
||||
if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
|
||||
state.indentation -= state.indentationDiff;
|
||||
}
|
||||
state.list = null;
|
||||
} else if (state.indentation > 0) {
|
||||
state.list = null;
|
||||
} else { // No longer a list
|
||||
state.list = false;
|
||||
}
|
||||
}
|
||||
|
||||
var match = null;
|
||||
if (state.indentationDiff >= 4) {
|
||||
stream.skipToEnd();
|
||||
if (prevLineIsIndentedCode || lineIsEmpty(state.prevLine)) {
|
||||
state.indentation -= 4;
|
||||
state.indentedCode = true;
|
||||
return tokenTypes.code;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (stream.eatSpace()) {
|
||||
return null;
|
||||
} else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) {
|
||||
state.header = match[1].length;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "header";
|
||||
state.f = state.inline;
|
||||
return getType(state);
|
||||
} else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList &&
|
||||
!prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) {
|
||||
state.header = match[0].charAt(0) == '=' ? 1 : 2;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "header";
|
||||
state.f = state.inline;
|
||||
return getType(state);
|
||||
} else if (stream.eat('>')) {
|
||||
state.quote = sol ? 1 : state.quote + 1;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "quote";
|
||||
stream.eatSpace();
|
||||
return getType(state);
|
||||
} else if (stream.peek() === '[') {
|
||||
return switchInline(stream, state, footnoteLink);
|
||||
} else if (stream.match(hrRE, true)) {
|
||||
state.hr = true;
|
||||
return tokenTypes.hr;
|
||||
} else if (match = stream.match(listRE)) {
|
||||
var listType = match[1] ? "ol" : "ul";
|
||||
state.indentation = stream.column() + stream.current().length;
|
||||
state.list = true;
|
||||
|
||||
// While this list item's marker's indentation
|
||||
// is less than the deepest list item's content's indentation,
|
||||
// pop the deepest list item indentation off the stack.
|
||||
while (state.listStack && stream.column() < state.listStack[state.listStack.length - 1]) {
|
||||
state.listStack.pop();
|
||||
}
|
||||
|
||||
// Add this list item's content's indentation to the stack
|
||||
state.listStack.push(state.indentation);
|
||||
|
||||
if (modeCfg.taskLists && stream.match(taskListRE, false)) {
|
||||
state.taskList = true;
|
||||
}
|
||||
state.f = state.inline;
|
||||
if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
|
||||
return getType(state);
|
||||
} else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) {
|
||||
state.fencedChars = match[1]
|
||||
// try switching mode
|
||||
state.localMode = getMode(match[2]);
|
||||
if (state.localMode) state.localState = CodeMirror.startState(state.localMode);
|
||||
state.f = state.block = local;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "code-block";
|
||||
state.code = -1
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
return switchInline(stream, state, state.inline);
|
||||
}
|
||||
|
||||
function htmlBlock(stream, state) {
|
||||
var style = htmlMode.token(stream, state.htmlState);
|
||||
if (!htmlModeMissing) {
|
||||
var inner = CodeMirror.innerMode(htmlMode, state.htmlState)
|
||||
if ((inner.mode.name == "xml" && inner.state.tagStart === null &&
|
||||
(!inner.state.context && inner.state.tokenize.isInText)) ||
|
||||
(state.md_inside && stream.current().indexOf(">") > -1)) {
|
||||
state.f = inlineNormal;
|
||||
state.block = blockNormal;
|
||||
state.htmlState = null;
|
||||
}
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
function local(stream, state) {
|
||||
if (state.fencedChars && stream.match(state.fencedChars, false)) {
|
||||
state.localMode = state.localState = null;
|
||||
state.f = state.block = leavingLocal;
|
||||
return null;
|
||||
} else if (state.localMode) {
|
||||
return state.localMode.token(stream, state.localState);
|
||||
} else {
|
||||
stream.skipToEnd();
|
||||
return tokenTypes.code;
|
||||
}
|
||||
}
|
||||
|
||||
function leavingLocal(stream, state) {
|
||||
stream.match(state.fencedChars);
|
||||
state.block = blockNormal;
|
||||
state.f = inlineNormal;
|
||||
state.fencedChars = null;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "code-block";
|
||||
state.code = 1
|
||||
var returnType = getType(state);
|
||||
state.code = 0
|
||||
return returnType;
|
||||
}
|
||||
|
||||
// Inline
|
||||
function getType(state) {
|
||||
var styles = [];
|
||||
|
||||
if (state.formatting) {
|
||||
styles.push(tokenTypes.formatting);
|
||||
|
||||
if (typeof state.formatting === "string") state.formatting = [state.formatting];
|
||||
|
||||
for (var i = 0; i < state.formatting.length; i++) {
|
||||
styles.push(tokenTypes.formatting + "-" + state.formatting[i]);
|
||||
|
||||
if (state.formatting[i] === "header") {
|
||||
styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.header);
|
||||
}
|
||||
|
||||
// Add `formatting-quote` and `formatting-quote-#` for blockquotes
|
||||
// Add `error` instead if the maximum blockquote nesting depth is passed
|
||||
if (state.formatting[i] === "quote") {
|
||||
if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
|
||||
styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.quote);
|
||||
} else {
|
||||
styles.push("error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.taskOpen) {
|
||||
styles.push("meta");
|
||||
return styles.length ? styles.join(' ') : null;
|
||||
}
|
||||
if (state.taskClosed) {
|
||||
styles.push("property");
|
||||
return styles.length ? styles.join(' ') : null;
|
||||
}
|
||||
|
||||
if (state.linkHref) {
|
||||
styles.push(tokenTypes.linkHref, "url");
|
||||
} else { // Only apply inline styles to non-url text
|
||||
if (state.strong) { styles.push(tokenTypes.strong); }
|
||||
if (state.em) { styles.push(tokenTypes.em); }
|
||||
if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
|
||||
if (state.linkText) { styles.push(tokenTypes.linkText); }
|
||||
if (state.code) { styles.push(tokenTypes.code); }
|
||||
if (state.image) { styles.push(tokenTypes.image); }
|
||||
if (state.imageAltText) { styles.push(tokenTypes.imageAltText, "link"); }
|
||||
if (state.imageMarker) { styles.push(tokenTypes.imageMarker); }
|
||||
}
|
||||
|
||||
if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
|
||||
|
||||
if (state.quote) {
|
||||
styles.push(tokenTypes.quote);
|
||||
|
||||
// Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
|
||||
if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
|
||||
styles.push(tokenTypes.quote + "-" + state.quote);
|
||||
} else {
|
||||
styles.push(tokenTypes.quote + "-" + modeCfg.maxBlockquoteDepth);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.list !== false) {
|
||||
var listMod = (state.listStack.length - 1) % 3;
|
||||
if (!listMod) {
|
||||
styles.push(tokenTypes.list1);
|
||||
} else if (listMod === 1) {
|
||||
styles.push(tokenTypes.list2);
|
||||
} else {
|
||||
styles.push(tokenTypes.list3);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.trailingSpaceNewLine) {
|
||||
styles.push("trailing-space-new-line");
|
||||
} else if (state.trailingSpace) {
|
||||
styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
|
||||
}
|
||||
|
||||
return styles.length ? styles.join(' ') : null;
|
||||
}
|
||||
|
||||
function handleText(stream, state) {
|
||||
if (stream.match(textRE, true)) {
|
||||
return getType(state);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inlineNormal(stream, state) {
|
||||
var style = state.text(stream, state);
|
||||
if (typeof style !== 'undefined')
|
||||
return style;
|
||||
|
||||
if (state.list) { // List marker (*, +, -, 1., etc)
|
||||
state.list = null;
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
if (state.taskList) {
|
||||
var taskOpen = stream.match(taskListRE, true)[1] !== "x";
|
||||
if (taskOpen) state.taskOpen = true;
|
||||
else state.taskClosed = true;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "task";
|
||||
state.taskList = false;
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
state.taskOpen = false;
|
||||
state.taskClosed = false;
|
||||
|
||||
if (state.header && stream.match(/^#+$/, true)) {
|
||||
if (modeCfg.highlightFormatting) state.formatting = "header";
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
// Get sol() value now, before character is consumed
|
||||
var sol = stream.sol();
|
||||
|
||||
var ch = stream.next();
|
||||
|
||||
// Matches link titles present on next line
|
||||
if (state.linkTitle) {
|
||||
state.linkTitle = false;
|
||||
var matchCh = ch;
|
||||
if (ch === '(') {
|
||||
matchCh = ')';
|
||||
}
|
||||
matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
|
||||
var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
|
||||
if (stream.match(new RegExp(regex), true)) {
|
||||
return tokenTypes.linkHref;
|
||||
}
|
||||
}
|
||||
|
||||
// If this block is changed, it may need to be updated in GFM mode
|
||||
if (ch === '`') {
|
||||
var previousFormatting = state.formatting;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "code";
|
||||
stream.eatWhile('`');
|
||||
var count = stream.current().length
|
||||
if (state.code == 0) {
|
||||
state.code = count
|
||||
return getType(state)
|
||||
} else if (count == state.code) { // Must be exact
|
||||
var t = getType(state)
|
||||
state.code = 0
|
||||
return t
|
||||
} else {
|
||||
state.formatting = previousFormatting
|
||||
return getType(state)
|
||||
}
|
||||
} else if (state.code) {
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
if (ch === '\\') {
|
||||
stream.next();
|
||||
if (modeCfg.highlightFormatting) {
|
||||
var type = getType(state);
|
||||
var formattingEscape = tokenTypes.formatting + "-escape";
|
||||
return type ? type + " " + formattingEscape : formattingEscape;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
|
||||
state.imageMarker = true;
|
||||
state.image = true;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "image";
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
if (ch === '[' && state.imageMarker) {
|
||||
state.imageMarker = false;
|
||||
state.imageAltText = true
|
||||
if (modeCfg.highlightFormatting) state.formatting = "image";
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
if (ch === ']' && state.imageAltText) {
|
||||
if (modeCfg.highlightFormatting) state.formatting = "image";
|
||||
var type = getType(state);
|
||||
state.imageAltText = false;
|
||||
state.image = false;
|
||||
state.inline = state.f = linkHref;
|
||||
return type;
|
||||
}
|
||||
|
||||
if (ch === '[' && stream.match(/[^\]]*\](\(.*\)| ?\[.*?\])/, false) && !state.image) {
|
||||
state.linkText = true;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
if (ch === ']' && state.linkText && stream.match(/\(.*?\)| ?\[.*?\]/, false)) {
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
var type = getType(state);
|
||||
state.linkText = false;
|
||||
state.inline = state.f = linkHref;
|
||||
return type;
|
||||
}
|
||||
|
||||
if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
|
||||
state.f = state.inline = linkInline;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
var type = getType(state);
|
||||
if (type){
|
||||
type += " ";
|
||||
} else {
|
||||
type = "";
|
||||
}
|
||||
return type + tokenTypes.linkInline;
|
||||
}
|
||||
|
||||
if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
|
||||
state.f = state.inline = linkInline;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
var type = getType(state);
|
||||
if (type){
|
||||
type += " ";
|
||||
} else {
|
||||
type = "";
|
||||
}
|
||||
return type + tokenTypes.linkEmail;
|
||||
}
|
||||
|
||||
if (ch === '<' && stream.match(/^(!--|\w)/, false)) {
|
||||
var end = stream.string.indexOf(">", stream.pos);
|
||||
if (end != -1) {
|
||||
var atts = stream.string.substring(stream.start, end);
|
||||
if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) state.md_inside = true;
|
||||
}
|
||||
stream.backUp(1);
|
||||
state.htmlState = CodeMirror.startState(htmlMode);
|
||||
return switchBlock(stream, state, htmlBlock);
|
||||
}
|
||||
|
||||
if (ch === '<' && stream.match(/^\/\w*?>/)) {
|
||||
state.md_inside = false;
|
||||
return "tag";
|
||||
}
|
||||
|
||||
var ignoreUnderscore = false;
|
||||
if (!modeCfg.underscoresBreakWords) {
|
||||
if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
|
||||
var prevPos = stream.pos - 2;
|
||||
if (prevPos >= 0) {
|
||||
var prevCh = stream.string.charAt(prevPos);
|
||||
if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
|
||||
ignoreUnderscore = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
|
||||
if (sol && stream.peek() === ' ') {
|
||||
// Do nothing, surrounded by newline and space
|
||||
} else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
|
||||
if (modeCfg.highlightFormatting) state.formatting = "strong";
|
||||
var t = getType(state);
|
||||
state.strong = false;
|
||||
return t;
|
||||
} else if (!state.strong && stream.eat(ch)) { // Add STRONG
|
||||
state.strong = ch;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "strong";
|
||||
return getType(state);
|
||||
} else if (state.em === ch) { // Remove EM
|
||||
if (modeCfg.highlightFormatting) state.formatting = "em";
|
||||
var t = getType(state);
|
||||
state.em = false;
|
||||
return t;
|
||||
} else if (!state.em) { // Add EM
|
||||
state.em = ch;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "em";
|
||||
return getType(state);
|
||||
}
|
||||
} else if (ch === ' ') {
|
||||
if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
|
||||
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
|
||||
return getType(state);
|
||||
} else { // Not surrounded by spaces, back up pointer
|
||||
stream.backUp(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modeCfg.strikethrough) {
|
||||
if (ch === '~' && stream.eatWhile(ch)) {
|
||||
if (state.strikethrough) {// Remove strikethrough
|
||||
if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
|
||||
var t = getType(state);
|
||||
state.strikethrough = false;
|
||||
return t;
|
||||
} else if (stream.match(/^[^\s]/, false)) {// Add strikethrough
|
||||
state.strikethrough = true;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
|
||||
return getType(state);
|
||||
}
|
||||
} else if (ch === ' ') {
|
||||
if (stream.match(/^~~/, true)) { // Probably surrounded by space
|
||||
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
|
||||
return getType(state);
|
||||
} else { // Not surrounded by spaces, back up pointer
|
||||
stream.backUp(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ch === ' ') {
|
||||
if (stream.match(/ +$/, false)) {
|
||||
state.trailingSpace++;
|
||||
} else if (state.trailingSpace) {
|
||||
state.trailingSpaceNewLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
return getType(state);
|
||||
}
|
||||
|
||||
function linkInline(stream, state) {
|
||||
var ch = stream.next();
|
||||
|
||||
if (ch === ">") {
|
||||
state.f = state.inline = inlineNormal;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
var type = getType(state);
|
||||
if (type){
|
||||
type += " ";
|
||||
} else {
|
||||
type = "";
|
||||
}
|
||||
return type + tokenTypes.linkInline;
|
||||
}
|
||||
|
||||
stream.match(/^[^>]+/, true);
|
||||
|
||||
return tokenTypes.linkInline;
|
||||
}
|
||||
|
||||
function linkHref(stream, state) {
|
||||
// Check if space, and return NULL if so (to avoid marking the space)
|
||||
if(stream.eatSpace()){
|
||||
return null;
|
||||
}
|
||||
var ch = stream.next();
|
||||
if (ch === '(' || ch === '[') {
|
||||
state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]", 0);
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link-string";
|
||||
state.linkHref = true;
|
||||
return getType(state);
|
||||
}
|
||||
return 'error';
|
||||
}
|
||||
|
||||
var linkRE = {
|
||||
")": /^(?:[^\\\(\)]|\\.|\((?:[^\\\(\)]|\\.)*\))*?(?=\))/,
|
||||
"]": /^(?:[^\\\[\]]|\\.|\[(?:[^\\\[\\]]|\\.)*\])*?(?=\])/
|
||||
}
|
||||
|
||||
function getLinkHrefInside(endChar) {
|
||||
return function(stream, state) {
|
||||
var ch = stream.next();
|
||||
|
||||
if (ch === endChar) {
|
||||
state.f = state.inline = inlineNormal;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link-string";
|
||||
var returnState = getType(state);
|
||||
state.linkHref = false;
|
||||
return returnState;
|
||||
}
|
||||
|
||||
stream.match(linkRE[endChar])
|
||||
state.linkHref = true;
|
||||
return getType(state);
|
||||
};
|
||||
}
|
||||
|
||||
function footnoteLink(stream, state) {
|
||||
if (stream.match(/^([^\]\\]|\\.)*\]:/, false)) {
|
||||
state.f = footnoteLinkInside;
|
||||
stream.next(); // Consume [
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
state.linkText = true;
|
||||
return getType(state);
|
||||
}
|
||||
return switchInline(stream, state, inlineNormal);
|
||||
}
|
||||
|
||||
function footnoteLinkInside(stream, state) {
|
||||
if (stream.match(/^\]:/, true)) {
|
||||
state.f = state.inline = footnoteUrl;
|
||||
if (modeCfg.highlightFormatting) state.formatting = "link";
|
||||
var returnType = getType(state);
|
||||
state.linkText = false;
|
||||
return returnType;
|
||||
}
|
||||
|
||||
stream.match(/^([^\]\\]|\\.)+/, true);
|
||||
|
||||
return tokenTypes.linkText;
|
||||
}
|
||||
|
||||
function footnoteUrl(stream, state) {
|
||||
// Check if space, and return NULL if so (to avoid marking the space)
|
||||
if(stream.eatSpace()){
|
||||
return null;
|
||||
}
|
||||
// Match URL
|
||||
stream.match(/^[^\s]+/, true);
|
||||
// Check for link title
|
||||
if (stream.peek() === undefined) { // End of line, set flag to check next line
|
||||
state.linkTitle = true;
|
||||
} else { // More content on line, check if link title
|
||||
stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
|
||||
}
|
||||
state.f = state.inline = inlineNormal;
|
||||
return tokenTypes.linkHref + " url";
|
||||
}
|
||||
|
||||
var mode = {
|
||||
startState: function() {
|
||||
return {
|
||||
f: blockNormal,
|
||||
|
||||
prevLine: null,
|
||||
thisLine: null,
|
||||
|
||||
block: blockNormal,
|
||||
htmlState: null,
|
||||
indentation: 0,
|
||||
|
||||
inline: inlineNormal,
|
||||
text: handleText,
|
||||
|
||||
formatting: false,
|
||||
linkText: false,
|
||||
linkHref: false,
|
||||
linkTitle: false,
|
||||
code: 0,
|
||||
em: false,
|
||||
strong: false,
|
||||
header: 0,
|
||||
hr: false,
|
||||
taskList: false,
|
||||
list: false,
|
||||
listStack: [],
|
||||
quote: 0,
|
||||
trailingSpace: 0,
|
||||
trailingSpaceNewLine: false,
|
||||
strikethrough: false,
|
||||
fencedChars: null
|
||||
};
|
||||
},
|
||||
|
||||
copyState: function(s) {
|
||||
return {
|
||||
f: s.f,
|
||||
|
||||
prevLine: s.prevLine,
|
||||
thisLine: s.thisLine,
|
||||
|
||||
block: s.block,
|
||||
htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
|
||||
indentation: s.indentation,
|
||||
|
||||
localMode: s.localMode,
|
||||
localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
|
||||
|
||||
inline: s.inline,
|
||||
text: s.text,
|
||||
formatting: false,
|
||||
linkTitle: s.linkTitle,
|
||||
code: s.code,
|
||||
em: s.em,
|
||||
strong: s.strong,
|
||||
strikethrough: s.strikethrough,
|
||||
header: s.header,
|
||||
hr: s.hr,
|
||||
taskList: s.taskList,
|
||||
list: s.list,
|
||||
listStack: s.listStack.slice(0),
|
||||
quote: s.quote,
|
||||
indentedCode: s.indentedCode,
|
||||
trailingSpace: s.trailingSpace,
|
||||
trailingSpaceNewLine: s.trailingSpaceNewLine,
|
||||
md_inside: s.md_inside,
|
||||
fencedChars: s.fencedChars
|
||||
};
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
|
||||
// Reset state.formatting
|
||||
state.formatting = false;
|
||||
|
||||
if (stream != state.thisLine) {
|
||||
var forceBlankLine = state.header || state.hr;
|
||||
|
||||
// Reset state.header and state.hr
|
||||
state.header = 0;
|
||||
state.hr = false;
|
||||
|
||||
if (stream.match(/^\s*$/, true) || forceBlankLine) {
|
||||
blankLine(state);
|
||||
if (!forceBlankLine) return null
|
||||
state.prevLine = null
|
||||
}
|
||||
|
||||
state.prevLine = state.thisLine
|
||||
state.thisLine = stream
|
||||
|
||||
// Reset state.taskList
|
||||
state.taskList = false;
|
||||
|
||||
// Reset state.trailingSpace
|
||||
state.trailingSpace = 0;
|
||||
state.trailingSpaceNewLine = false;
|
||||
|
||||
state.f = state.block;
|
||||
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
|
||||
state.indentationDiff = Math.min(indentation - state.indentation, 4);
|
||||
state.indentation = state.indentation + state.indentationDiff;
|
||||
if (indentation > 0) return null;
|
||||
}
|
||||
return state.f(stream, state);
|
||||
},
|
||||
|
||||
innerMode: function(state) {
|
||||
if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
|
||||
if (state.localState) return {state: state.localState, mode: state.localMode};
|
||||
return {state: state, mode: mode};
|
||||
},
|
||||
|
||||
blankLine: blankLine,
|
||||
|
||||
getType: getType,
|
||||
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
fold: "markdown"
|
||||
};
|
||||
return mode;
|
||||
}, "xml");
|
||||
|
||||
CodeMirror.defineMIME("text/x-markdown", "markdown");
|
||||
|
||||
});
|
989
BrowserMark/js/codemirror/mode/markdown/test.js
vendored
Normal file
@ -0,0 +1,989 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function() {
|
||||
var mode = CodeMirror.getMode({tabSize: 4}, "markdown");
|
||||
function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); }
|
||||
var modeHighlightFormatting = CodeMirror.getMode({tabSize: 4}, {name: "markdown", highlightFormatting: true});
|
||||
function FT(name) { test.mode(name, modeHighlightFormatting, Array.prototype.slice.call(arguments, 1)); }
|
||||
var modeAtxNoSpace = CodeMirror.getMode({tabSize: 4}, {name: "markdown", allowAtxHeaderWithoutSpace: true});
|
||||
function AtxNoSpaceTest(name) { test.mode(name, modeAtxNoSpace, Array.prototype.slice.call(arguments, 1)); }
|
||||
var modeFenced = CodeMirror.getMode({tabSize: 4}, {name: "markdown", fencedCodeBlocks: true});
|
||||
function FencedTest(name) { test.mode(name, modeFenced, Array.prototype.slice.call(arguments, 1)); }
|
||||
var modeOverrideClasses = CodeMirror.getMode({tabsize: 4}, {
|
||||
name: "markdown",
|
||||
strikethrough: true,
|
||||
tokenTypeOverrides: {
|
||||
"header" : "override-header",
|
||||
"code" : "override-code",
|
||||
"quote" : "override-quote",
|
||||
"list1" : "override-list1",
|
||||
"list2" : "override-list2",
|
||||
"list3" : "override-list3",
|
||||
"hr" : "override-hr",
|
||||
"image" : "override-image",
|
||||
"imageAltText": "override-image-alt-text",
|
||||
"imageMarker": "override-image-marker",
|
||||
"linkInline" : "override-link-inline",
|
||||
"linkEmail" : "override-link-email",
|
||||
"linkText" : "override-link-text",
|
||||
"linkHref" : "override-link-href",
|
||||
"em" : "override-em",
|
||||
"strong" : "override-strong",
|
||||
"strikethrough" : "override-strikethrough"
|
||||
}});
|
||||
function TokenTypeOverrideTest(name) { test.mode(name, modeOverrideClasses, Array.prototype.slice.call(arguments, 1)); }
|
||||
var modeFormattingOverride = CodeMirror.getMode({tabsize: 4}, {
|
||||
name: "markdown",
|
||||
highlightFormatting: true,
|
||||
tokenTypeOverrides: {
|
||||
"formatting" : "override-formatting"
|
||||
}});
|
||||
function FormatTokenTypeOverrideTest(name) { test.mode(name, modeFormattingOverride, Array.prototype.slice.call(arguments, 1)); }
|
||||
|
||||
|
||||
FT("formatting_emAsterisk",
|
||||
"[em&formatting&formatting-em *][em foo][em&formatting&formatting-em *]");
|
||||
|
||||
FT("formatting_emUnderscore",
|
||||
"[em&formatting&formatting-em _][em foo][em&formatting&formatting-em _]");
|
||||
|
||||
FT("formatting_strongAsterisk",
|
||||
"[strong&formatting&formatting-strong **][strong foo][strong&formatting&formatting-strong **]");
|
||||
|
||||
FT("formatting_strongUnderscore",
|
||||
"[strong&formatting&formatting-strong __][strong foo][strong&formatting&formatting-strong __]");
|
||||
|
||||
FT("formatting_codeBackticks",
|
||||
"[comment&formatting&formatting-code `][comment foo][comment&formatting&formatting-code `]");
|
||||
|
||||
FT("formatting_doubleBackticks",
|
||||
"[comment&formatting&formatting-code ``][comment foo ` bar][comment&formatting&formatting-code ``]");
|
||||
|
||||
FT("formatting_atxHeader",
|
||||
"[header&header-1&formatting&formatting-header&formatting-header-1 # ][header&header-1 foo # bar ][header&header-1&formatting&formatting-header&formatting-header-1 #]");
|
||||
|
||||
FT("formatting_setextHeader",
|
||||
"foo",
|
||||
"[header&header-1&formatting&formatting-header&formatting-header-1 =]");
|
||||
|
||||
FT("formatting_blockquote",
|
||||
"[quote"e-1&formatting&formatting-quote&formatting-quote-1 > ][quote"e-1 foo]");
|
||||
|
||||
FT("formatting_list",
|
||||
"[variable-2&formatting&formatting-list&formatting-list-ul - ][variable-2 foo]");
|
||||
FT("formatting_list",
|
||||
"[variable-2&formatting&formatting-list&formatting-list-ol 1. ][variable-2 foo]");
|
||||
|
||||
FT("formatting_link",
|
||||
"[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url (][string&url http://example.com/][string&formatting&formatting-link-string&url )]");
|
||||
|
||||
FT("formatting_linkReference",
|
||||
"[link&formatting&formatting-link [][link foo][link&formatting&formatting-link ]]][string&formatting&formatting-link-string&url [][string&url bar][string&formatting&formatting-link-string&url ]]]",
|
||||
"[link&formatting&formatting-link [][link bar][link&formatting&formatting-link ]]:] [string&url http://example.com/]");
|
||||
|
||||
FT("formatting_linkWeb",
|
||||
"[link&formatting&formatting-link <][link http://example.com/][link&formatting&formatting-link >]");
|
||||
|
||||
FT("formatting_linkEmail",
|
||||
"[link&formatting&formatting-link <][link user@example.com][link&formatting&formatting-link >]");
|
||||
|
||||
FT("formatting_escape",
|
||||
"[formatting-escape \\*]");
|
||||
|
||||
FT("formatting_image",
|
||||
"[formatting&formatting-image&image&image-marker !][formatting&formatting-image&image&image-alt-text&link [[][image&image-alt-text&link alt text][formatting&formatting-image&image&image-alt-text&link ]]][formatting&formatting-link-string&string&url (][url&string http://link.to/image.jpg][formatting&formatting-link-string&string&url )]");
|
||||
|
||||
MT("plainText",
|
||||
"foo");
|
||||
|
||||
// Don't style single trailing space
|
||||
MT("trailingSpace1",
|
||||
"foo ");
|
||||
|
||||
// Two or more trailing spaces should be styled with line break character
|
||||
MT("trailingSpace2",
|
||||
"foo[trailing-space-a ][trailing-space-new-line ]");
|
||||
|
||||
MT("trailingSpace3",
|
||||
"foo[trailing-space-a ][trailing-space-b ][trailing-space-new-line ]");
|
||||
|
||||
MT("trailingSpace4",
|
||||
"foo[trailing-space-a ][trailing-space-b ][trailing-space-a ][trailing-space-new-line ]");
|
||||
|
||||
// Code blocks using 4 spaces (regardless of CodeMirror.tabSize value)
|
||||
MT("codeBlocksUsing4Spaces",
|
||||
" [comment foo]");
|
||||
|
||||
// Code blocks using 4 spaces with internal indentation
|
||||
MT("codeBlocksUsing4SpacesIndentation",
|
||||
" [comment bar]",
|
||||
" [comment hello]",
|
||||
" [comment world]",
|
||||
" [comment foo]",
|
||||
"bar");
|
||||
|
||||
// Code blocks should end even after extra indented lines
|
||||
MT("codeBlocksWithTrailingIndentedLine",
|
||||
" [comment foo]",
|
||||
" [comment bar]",
|
||||
" [comment baz]",
|
||||
" ",
|
||||
"hello");
|
||||
|
||||
// Code blocks using 1 tab (regardless of CodeMirror.indentWithTabs value)
|
||||
MT("codeBlocksUsing1Tab",
|
||||
"\t[comment foo]");
|
||||
|
||||
// No code blocks directly after paragraph
|
||||
// http://spec.commonmark.org/0.19/#example-65
|
||||
MT("noCodeBlocksAfterParagraph",
|
||||
"Foo",
|
||||
" Bar");
|
||||
|
||||
// Inline code using backticks
|
||||
MT("inlineCodeUsingBackticks",
|
||||
"foo [comment `bar`]");
|
||||
|
||||
// Block code using single backtick (shouldn't work)
|
||||
MT("blockCodeSingleBacktick",
|
||||
"[comment `]",
|
||||
"[comment foo]",
|
||||
"[comment `]");
|
||||
|
||||
// Unclosed backticks
|
||||
// Instead of simply marking as CODE, it would be nice to have an
|
||||
// incomplete flag for CODE, that is styled slightly different.
|
||||
MT("unclosedBackticks",
|
||||
"foo [comment `bar]");
|
||||
|
||||
// Per documentation: "To include a literal backtick character within a
|
||||
// code span, you can use multiple backticks as the opening and closing
|
||||
// delimiters"
|
||||
MT("doubleBackticks",
|
||||
"[comment ``foo ` bar``]");
|
||||
|
||||
// Tests based on Dingus
|
||||
// http://daringfireball.net/projects/markdown/dingus
|
||||
//
|
||||
// Multiple backticks within an inline code block
|
||||
MT("consecutiveBackticks",
|
||||
"[comment `foo```bar`]");
|
||||
|
||||
// Multiple backticks within an inline code block with a second code block
|
||||
MT("consecutiveBackticks",
|
||||
"[comment `foo```bar`] hello [comment `world`]");
|
||||
|
||||
// Unclosed with several different groups of backticks
|
||||
MT("unclosedBackticks",
|
||||
"[comment ``foo ``` bar` hello]");
|
||||
|
||||
// Closed with several different groups of backticks
|
||||
MT("closedBackticks",
|
||||
"[comment ``foo ``` bar` hello``] world");
|
||||
|
||||
// atx headers
|
||||
// http://daringfireball.net/projects/markdown/syntax#header
|
||||
|
||||
MT("atxH1",
|
||||
"[header&header-1 # foo]");
|
||||
|
||||
MT("atxH2",
|
||||
"[header&header-2 ## foo]");
|
||||
|
||||
MT("atxH3",
|
||||
"[header&header-3 ### foo]");
|
||||
|
||||
MT("atxH4",
|
||||
"[header&header-4 #### foo]");
|
||||
|
||||
MT("atxH5",
|
||||
"[header&header-5 ##### foo]");
|
||||
|
||||
MT("atxH6",
|
||||
"[header&header-6 ###### foo]");
|
||||
|
||||
// http://spec.commonmark.org/0.19/#example-24
|
||||
MT("noAtxH7",
|
||||
"####### foo");
|
||||
|
||||
// http://spec.commonmark.org/0.19/#example-25
|
||||
MT("noAtxH1WithoutSpace",
|
||||
"#5 bolt");
|
||||
|
||||
// CommonMark requires a space after # but most parsers don't
|
||||
AtxNoSpaceTest("atxNoSpaceAllowed_H1NoSpace",
|
||||
"[header&header-1 #foo]");
|
||||
|
||||
AtxNoSpaceTest("atxNoSpaceAllowed_H4NoSpace",
|
||||
"[header&header-4 ####foo]");
|
||||
|
||||
AtxNoSpaceTest("atxNoSpaceAllowed_H1Space",
|
||||
"[header&header-1 # foo]");
|
||||
|
||||
// Inline styles should be parsed inside headers
|
||||
MT("atxH1inline",
|
||||
"[header&header-1 # foo ][header&header-1&em *bar*]");
|
||||
|
||||
// Setext headers - H1, H2
|
||||
// Per documentation, "Any number of underlining =’s or -’s will work."
|
||||
// http://daringfireball.net/projects/markdown/syntax#header
|
||||
// Ideally, the text would be marked as `header` as well, but this is
|
||||
// not really feasible at the moment. So, instead, we're testing against
|
||||
// what works today, to avoid any regressions.
|
||||
//
|
||||
// Check if single underlining = works
|
||||
MT("setextH1",
|
||||
"foo",
|
||||
"[header&header-1 =]");
|
||||
|
||||
// Check if 3+ ='s work
|
||||
MT("setextH1",
|
||||
"foo",
|
||||
"[header&header-1 ===]");
|
||||
|
||||
// Check if single underlining - works
|
||||
MT("setextH2",
|
||||
"foo",
|
||||
"[header&header-2 -]");
|
||||
|
||||
// Check if 3+ -'s work
|
||||
MT("setextH2",
|
||||
"foo",
|
||||
"[header&header-2 ---]");
|
||||
|
||||
// http://spec.commonmark.org/0.19/#example-45
|
||||
MT("setextH2AllowSpaces",
|
||||
"foo",
|
||||
" [header&header-2 ---- ]");
|
||||
|
||||
// http://spec.commonmark.org/0.19/#example-44
|
||||
MT("noSetextAfterIndentedCodeBlock",
|
||||
" [comment foo]",
|
||||
"[hr ---]");
|
||||
|
||||
// http://spec.commonmark.org/0.19/#example-51
|
||||
MT("noSetextAfterQuote",
|
||||
"[quote"e-1 > foo]",
|
||||
"[hr ---]");
|
||||
|
||||
MT("noSetextAfterList",
|
||||
"[variable-2 - foo]",
|
||||
"[hr ---]");
|
||||
|
||||
// Single-line blockquote with trailing space
|
||||
MT("blockquoteSpace",
|
||||
"[quote"e-1 > foo]");
|
||||
|
||||
// Single-line blockquote
|
||||
MT("blockquoteNoSpace",
|
||||
"[quote"e-1 >foo]");
|
||||
|
||||
// No blank line before blockquote
|
||||
MT("blockquoteNoBlankLine",
|
||||
"foo",
|
||||
"[quote"e-1 > bar]");
|
||||
|
||||
// Nested blockquote
|
||||
MT("blockquoteSpace",
|
||||
"[quote"e-1 > foo]",
|
||||
"[quote"e-1 >][quote"e-2 > foo]",
|
||||
"[quote"e-1 >][quote"e-2 >][quote"e-3 > foo]");
|
||||
|
||||
// Single-line blockquote followed by normal paragraph
|
||||
MT("blockquoteThenParagraph",
|
||||
"[quote"e-1 >foo]",
|
||||
"",
|
||||
"bar");
|
||||
|
||||
// Multi-line blockquote (lazy mode)
|
||||
MT("multiBlockquoteLazy",
|
||||
"[quote"e-1 >foo]",
|
||||
"[quote"e-1 bar]");
|
||||
|
||||
// Multi-line blockquote followed by normal paragraph (lazy mode)
|
||||
MT("multiBlockquoteLazyThenParagraph",
|
||||
"[quote"e-1 >foo]",
|
||||
"[quote"e-1 bar]",
|
||||
"",
|
||||
"hello");
|
||||
|
||||
// Multi-line blockquote (non-lazy mode)
|
||||
MT("multiBlockquote",
|
||||
"[quote"e-1 >foo]",
|
||||
"[quote"e-1 >bar]");
|
||||
|
||||
// Multi-line blockquote followed by normal paragraph (non-lazy mode)
|
||||
MT("multiBlockquoteThenParagraph",
|
||||
"[quote"e-1 >foo]",
|
||||
"[quote"e-1 >bar]",
|
||||
"",
|
||||
"hello");
|
||||
|
||||
// Header with leading space after continued blockquote (#3287, negative indentation)
|
||||
MT("headerAfterContinuedBlockquote",
|
||||
"[quote"e-1 > foo]",
|
||||
"[quote"e-1 bar]",
|
||||
"",
|
||||
" [header&header-1 # hello]");
|
||||
|
||||
// Check list types
|
||||
|
||||
MT("listAsterisk",
|
||||
"foo",
|
||||
"bar",
|
||||
"",
|
||||
"[variable-2 * foo]",
|
||||
"[variable-2 * bar]");
|
||||
|
||||
MT("listPlus",
|
||||
"foo",
|
||||
"bar",
|
||||
"",
|
||||
"[variable-2 + foo]",
|
||||
"[variable-2 + bar]");
|
||||
|
||||
MT("listDash",
|
||||
"foo",
|
||||
"bar",
|
||||
"",
|
||||
"[variable-2 - foo]",
|
||||
"[variable-2 - bar]");
|
||||
|
||||
MT("listNumber",
|
||||
"foo",
|
||||
"bar",
|
||||
"",
|
||||
"[variable-2 1. foo]",
|
||||
"[variable-2 2. bar]");
|
||||
|
||||
MT("listFromParagraph",
|
||||
"foo",
|
||||
"[variable-2 1. bar]",
|
||||
"[variable-2 2. hello]");
|
||||
|
||||
// List after hr
|
||||
MT("listAfterHr",
|
||||
"[hr ---]",
|
||||
"[variable-2 - bar]");
|
||||
|
||||
// List after header
|
||||
MT("listAfterHeader",
|
||||
"[header&header-1 # foo]",
|
||||
"[variable-2 - bar]");
|
||||
|
||||
// hr after list
|
||||
MT("hrAfterList",
|
||||
"[variable-2 - foo]",
|
||||
"[hr -----]");
|
||||
|
||||
// Formatting in lists (*)
|
||||
MT("listAsteriskFormatting",
|
||||
"[variable-2 * ][variable-2&em *foo*][variable-2 bar]",
|
||||
"[variable-2 * ][variable-2&strong **foo**][variable-2 bar]",
|
||||
"[variable-2 * ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
|
||||
"[variable-2 * ][variable-2&comment `foo`][variable-2 bar]");
|
||||
|
||||
// Formatting in lists (+)
|
||||
MT("listPlusFormatting",
|
||||
"[variable-2 + ][variable-2&em *foo*][variable-2 bar]",
|
||||
"[variable-2 + ][variable-2&strong **foo**][variable-2 bar]",
|
||||
"[variable-2 + ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
|
||||
"[variable-2 + ][variable-2&comment `foo`][variable-2 bar]");
|
||||
|
||||
// Formatting in lists (-)
|
||||
MT("listDashFormatting",
|
||||
"[variable-2 - ][variable-2&em *foo*][variable-2 bar]",
|
||||
"[variable-2 - ][variable-2&strong **foo**][variable-2 bar]",
|
||||
"[variable-2 - ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
|
||||
"[variable-2 - ][variable-2&comment `foo`][variable-2 bar]");
|
||||
|
||||
// Formatting in lists (1.)
|
||||
MT("listNumberFormatting",
|
||||
"[variable-2 1. ][variable-2&em *foo*][variable-2 bar]",
|
||||
"[variable-2 2. ][variable-2&strong **foo**][variable-2 bar]",
|
||||
"[variable-2 3. ][variable-2&strong **][variable-2&em&strong *foo**][variable-2&em *][variable-2 bar]",
|
||||
"[variable-2 4. ][variable-2&comment `foo`][variable-2 bar]");
|
||||
|
||||
// Paragraph lists
|
||||
MT("listParagraph",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]");
|
||||
|
||||
// Multi-paragraph lists
|
||||
//
|
||||
// 4 spaces
|
||||
MT("listMultiParagraph",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
" [variable-2 hello]");
|
||||
|
||||
// 4 spaces, extra blank lines (should still be list, per Dingus)
|
||||
MT("listMultiParagraphExtra",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
"",
|
||||
" [variable-2 hello]");
|
||||
|
||||
// 4 spaces, plus 1 space (should still be list, per Dingus)
|
||||
MT("listMultiParagraphExtraSpace",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
" [variable-2 hello]",
|
||||
"",
|
||||
" [variable-2 world]");
|
||||
|
||||
// 1 tab
|
||||
MT("listTab",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
"\t[variable-2 hello]");
|
||||
|
||||
// No indent
|
||||
MT("listNoIndent",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
"hello");
|
||||
|
||||
MT("listCommonMarkIndentationCode",
|
||||
"[variable-2 * Code blocks also affect]",
|
||||
" [variable-3 * The next level starts where the contents start.]",
|
||||
" [variable-3 * Anything less than that will keep the item on the same level.]",
|
||||
" [variable-3 * Each list item can indent the first level further and further.]",
|
||||
" [variable-3 * For the most part, this makes sense while writing a list.]",
|
||||
" [keyword * This means two items with same indentation can be different levels.]",
|
||||
" [keyword * Each level has an indent requirement that can change between items.]",
|
||||
" [keyword * A list item that meets this will be part of the next level.]",
|
||||
" [variable-3 * Otherwise, it will be part of the level where it does meet this.]",
|
||||
" [variable-2 * World]");
|
||||
|
||||
// Blockquote
|
||||
MT("blockquote",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
" [variable-2"e"e-1 > hello]");
|
||||
|
||||
// Code block
|
||||
MT("blockquoteCode",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
"[variable-2 * bar]",
|
||||
"",
|
||||
" [comment > hello]",
|
||||
"",
|
||||
" [variable-2 world]");
|
||||
|
||||
// Code block followed by text
|
||||
MT("blockquoteCodeText",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-2 bar]",
|
||||
"",
|
||||
" [comment hello]",
|
||||
"",
|
||||
" [variable-2 world]");
|
||||
|
||||
// Nested list
|
||||
|
||||
MT("listAsteriskNested",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-3 * bar]");
|
||||
|
||||
MT("listPlusNested",
|
||||
"[variable-2 + foo]",
|
||||
"",
|
||||
" [variable-3 + bar]");
|
||||
|
||||
MT("listDashNested",
|
||||
"[variable-2 - foo]",
|
||||
"",
|
||||
" [variable-3 - bar]");
|
||||
|
||||
MT("listNumberNested",
|
||||
"[variable-2 1. foo]",
|
||||
"",
|
||||
" [variable-3 2. bar]");
|
||||
|
||||
MT("listMixed",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-3 + bar]",
|
||||
"",
|
||||
" [keyword - hello]",
|
||||
"",
|
||||
" [variable-2 1. world]");
|
||||
|
||||
MT("listBlockquote",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-3 + bar]",
|
||||
"",
|
||||
" [quote"e-1&variable-3 > hello]");
|
||||
|
||||
MT("listCode",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-3 + bar]",
|
||||
"",
|
||||
" [comment hello]");
|
||||
|
||||
// Code with internal indentation
|
||||
MT("listCodeIndentation",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [comment bar]",
|
||||
" [comment hello]",
|
||||
" [comment world]",
|
||||
" [comment foo]",
|
||||
" [variable-2 bar]");
|
||||
|
||||
// List nesting edge cases
|
||||
MT("listNested",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-3 * bar]",
|
||||
"",
|
||||
" [variable-3 hello]"
|
||||
);
|
||||
MT("listNested",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [variable-3 * bar]",
|
||||
"",
|
||||
" [keyword * foo]"
|
||||
);
|
||||
|
||||
// Code followed by text
|
||||
MT("listCodeText",
|
||||
"[variable-2 * foo]",
|
||||
"",
|
||||
" [comment bar]",
|
||||
"",
|
||||
"hello");
|
||||
|
||||
// Following tests directly from official Markdown documentation
|
||||
// http://daringfireball.net/projects/markdown/syntax#hr
|
||||
|
||||
MT("hrSpace",
|
||||
"[hr * * *]");
|
||||
|
||||
MT("hr",
|
||||
"[hr ***]");
|
||||
|
||||
MT("hrLong",
|
||||
"[hr *****]");
|
||||
|
||||
MT("hrSpaceDash",
|
||||
"[hr - - -]");
|
||||
|
||||
MT("hrDashLong",
|
||||
"[hr ---------------------------------------]");
|
||||
|
||||
//Images
|
||||
MT("Images",
|
||||
"[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)]")
|
||||
|
||||
//Images with highlight alt text
|
||||
MT("imageEm",
|
||||
"[image&image-marker !][image&image-alt-text&link [[][image-alt-text&em&image&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
|
||||
|
||||
MT("imageStrong",
|
||||
"[image&image-marker !][image&image-alt-text&link [[][image-alt-text&strong&image&link **alt text**][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
|
||||
|
||||
MT("imageEmStrong",
|
||||
"[image&image-marker !][image&image-alt-text&link [[][image-alt-text&image&strong&link **][image&image-alt-text&em&strong&link *alt text**][image&image-alt-text&em&link *][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)]");
|
||||
|
||||
// Inline link with title
|
||||
MT("linkTitle",
|
||||
"[link [[foo]]][string&url (http://example.com/ \"bar\")] hello");
|
||||
|
||||
// Inline link without title
|
||||
MT("linkNoTitle",
|
||||
"[link [[foo]]][string&url (http://example.com/)] bar");
|
||||
|
||||
// Inline link with image
|
||||
MT("linkImage",
|
||||
"[link [[][link&image&image-marker !][link&image&image-alt-text&link [[alt text]]][string&url (http://link.to/image.jpg)][link ]]][string&url (http://example.com/)] bar");
|
||||
|
||||
// Inline link with Em
|
||||
MT("linkEm",
|
||||
"[link [[][link&em *foo*][link ]]][string&url (http://example.com/)] bar");
|
||||
|
||||
// Inline link with Strong
|
||||
MT("linkStrong",
|
||||
"[link [[][link&strong **foo**][link ]]][string&url (http://example.com/)] bar");
|
||||
|
||||
// Inline link with EmStrong
|
||||
MT("linkEmStrong",
|
||||
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url (http://example.com/)] bar");
|
||||
|
||||
// Image with title
|
||||
MT("imageTitle",
|
||||
"[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/ \"bar\")] hello");
|
||||
|
||||
// Image without title
|
||||
MT("imageNoTitle",
|
||||
"[image&image-marker !][image&image-alt-text&link [[alt text]]][string&url (http://example.com/)] bar");
|
||||
|
||||
// Image with asterisks
|
||||
MT("imageAsterisks",
|
||||
"[image&image-marker !][image&image-alt-text&link [[ ][image&image-alt-text&em&link *alt text*][image&image-alt-text&link ]]][string&url (http://link.to/image.jpg)] bar");
|
||||
|
||||
// Not a link. Should be normal text due to square brackets being used
|
||||
// regularly in text, especially in quoted material, and no space is allowed
|
||||
// between square brackets and parentheses (per Dingus).
|
||||
MT("notALink",
|
||||
"[[foo]] (bar)");
|
||||
|
||||
// Reference-style links
|
||||
MT("linkReference",
|
||||
"[link [[foo]]][string&url [[bar]]] hello");
|
||||
|
||||
// Reference-style links with Em
|
||||
MT("linkReferenceEm",
|
||||
"[link [[][link&em *foo*][link ]]][string&url [[bar]]] hello");
|
||||
|
||||
// Reference-style links with Strong
|
||||
MT("linkReferenceStrong",
|
||||
"[link [[][link&strong **foo**][link ]]][string&url [[bar]]] hello");
|
||||
|
||||
// Reference-style links with EmStrong
|
||||
MT("linkReferenceEmStrong",
|
||||
"[link [[][link&strong **][link&em&strong *foo**][link&em *][link ]]][string&url [[bar]]] hello");
|
||||
|
||||
// Reference-style links with optional space separator (per documentation)
|
||||
// "You can optionally use a space to separate the sets of brackets"
|
||||
MT("linkReferenceSpace",
|
||||
"[link [[foo]]] [string&url [[bar]]] hello");
|
||||
|
||||
// Should only allow a single space ("...use *a* space...")
|
||||
MT("linkReferenceDoubleSpace",
|
||||
"[[foo]] [[bar]] hello");
|
||||
|
||||
// Reference-style links with implicit link name
|
||||
MT("linkImplicit",
|
||||
"[link [[foo]]][string&url [[]]] hello");
|
||||
|
||||
// @todo It would be nice if, at some point, the document was actually
|
||||
// checked to see if the referenced link exists
|
||||
|
||||
// Link label, for reference-style links (taken from documentation)
|
||||
|
||||
MT("labelNoTitle",
|
||||
"[link [[foo]]:] [string&url http://example.com/]");
|
||||
|
||||
MT("labelIndented",
|
||||
" [link [[foo]]:] [string&url http://example.com/]");
|
||||
|
||||
MT("labelSpaceTitle",
|
||||
"[link [[foo bar]]:] [string&url http://example.com/ \"hello\"]");
|
||||
|
||||
MT("labelDoubleTitle",
|
||||
"[link [[foo bar]]:] [string&url http://example.com/ \"hello\"] \"world\"");
|
||||
|
||||
MT("labelTitleDoubleQuotes",
|
||||
"[link [[foo]]:] [string&url http://example.com/ \"bar\"]");
|
||||
|
||||
MT("labelTitleSingleQuotes",
|
||||
"[link [[foo]]:] [string&url http://example.com/ 'bar']");
|
||||
|
||||
MT("labelTitleParentheses",
|
||||
"[link [[foo]]:] [string&url http://example.com/ (bar)]");
|
||||
|
||||
MT("labelTitleInvalid",
|
||||
"[link [[foo]]:] [string&url http://example.com/] bar");
|
||||
|
||||
MT("labelLinkAngleBrackets",
|
||||
"[link [[foo]]:] [string&url <http://example.com/> \"bar\"]");
|
||||
|
||||
MT("labelTitleNextDoubleQuotes",
|
||||
"[link [[foo]]:] [string&url http://example.com/]",
|
||||
"[string \"bar\"] hello");
|
||||
|
||||
MT("labelTitleNextSingleQuotes",
|
||||
"[link [[foo]]:] [string&url http://example.com/]",
|
||||
"[string 'bar'] hello");
|
||||
|
||||
MT("labelTitleNextParentheses",
|
||||
"[link [[foo]]:] [string&url http://example.com/]",
|
||||
"[string (bar)] hello");
|
||||
|
||||
MT("labelTitleNextMixed",
|
||||
"[link [[foo]]:] [string&url http://example.com/]",
|
||||
"(bar\" hello");
|
||||
|
||||
MT("labelEscape",
|
||||
"[link [[foo \\]] ]]:] [string&url http://example.com/]");
|
||||
|
||||
MT("labelEscapeColon",
|
||||
"[link [[foo \\]]: bar]]:] [string&url http://example.com/]");
|
||||
|
||||
MT("labelEscapeEnd",
|
||||
"[[foo\\]]: http://example.com/");
|
||||
|
||||
MT("linkWeb",
|
||||
"[link <http://example.com/>] foo");
|
||||
|
||||
MT("linkWebDouble",
|
||||
"[link <http://example.com/>] foo [link <http://example.com/>]");
|
||||
|
||||
MT("linkEmail",
|
||||
"[link <user@example.com>] foo");
|
||||
|
||||
MT("linkEmailDouble",
|
||||
"[link <user@example.com>] foo [link <user@example.com>]");
|
||||
|
||||
MT("emAsterisk",
|
||||
"[em *foo*] bar");
|
||||
|
||||
MT("emUnderscore",
|
||||
"[em _foo_] bar");
|
||||
|
||||
MT("emInWordAsterisk",
|
||||
"foo[em *bar*]hello");
|
||||
|
||||
MT("emInWordUnderscore",
|
||||
"foo[em _bar_]hello");
|
||||
|
||||
// Per documentation: "...surround an * or _ with spaces, it’ll be
|
||||
// treated as a literal asterisk or underscore."
|
||||
|
||||
MT("emEscapedBySpaceIn",
|
||||
"foo [em _bar _ hello_] world");
|
||||
|
||||
MT("emEscapedBySpaceOut",
|
||||
"foo _ bar[em _hello_]world");
|
||||
|
||||
MT("emEscapedByNewline",
|
||||
"foo",
|
||||
"_ bar[em _hello_]world");
|
||||
|
||||
// Unclosed emphasis characters
|
||||
// Instead of simply marking as EM / STRONG, it would be nice to have an
|
||||
// incomplete flag for EM and STRONG, that is styled slightly different.
|
||||
MT("emIncompleteAsterisk",
|
||||
"foo [em *bar]");
|
||||
|
||||
MT("emIncompleteUnderscore",
|
||||
"foo [em _bar]");
|
||||
|
||||
MT("strongAsterisk",
|
||||
"[strong **foo**] bar");
|
||||
|
||||
MT("strongUnderscore",
|
||||
"[strong __foo__] bar");
|
||||
|
||||
MT("emStrongAsterisk",
|
||||
"[em *foo][em&strong **bar*][strong hello**] world");
|
||||
|
||||
MT("emStrongUnderscore",
|
||||
"[em _foo][em&strong __bar_][strong hello__] world");
|
||||
|
||||
// "...same character must be used to open and close an emphasis span.""
|
||||
MT("emStrongMixed",
|
||||
"[em _foo][em&strong **bar*hello__ world]");
|
||||
|
||||
MT("emStrongMixed",
|
||||
"[em *foo][em&strong __bar_hello** world]");
|
||||
|
||||
MT("linkWithNestedParens",
|
||||
"[link [[foo]]][string&url (bar(baz))]")
|
||||
|
||||
// These characters should be escaped:
|
||||
// \ backslash
|
||||
// ` backtick
|
||||
// * asterisk
|
||||
// _ underscore
|
||||
// {} curly braces
|
||||
// [] square brackets
|
||||
// () parentheses
|
||||
// # hash mark
|
||||
// + plus sign
|
||||
// - minus sign (hyphen)
|
||||
// . dot
|
||||
// ! exclamation mark
|
||||
|
||||
MT("escapeBacktick",
|
||||
"foo \\`bar\\`");
|
||||
|
||||
MT("doubleEscapeBacktick",
|
||||
"foo \\\\[comment `bar\\\\`]");
|
||||
|
||||
MT("escapeAsterisk",
|
||||
"foo \\*bar\\*");
|
||||
|
||||
MT("doubleEscapeAsterisk",
|
||||
"foo \\\\[em *bar\\\\*]");
|
||||
|
||||
MT("escapeUnderscore",
|
||||
"foo \\_bar\\_");
|
||||
|
||||
MT("doubleEscapeUnderscore",
|
||||
"foo \\\\[em _bar\\\\_]");
|
||||
|
||||
MT("escapeHash",
|
||||
"\\# foo");
|
||||
|
||||
MT("doubleEscapeHash",
|
||||
"\\\\# foo");
|
||||
|
||||
MT("escapeNewline",
|
||||
"\\",
|
||||
"[em *foo*]");
|
||||
|
||||
// Class override tests
|
||||
TokenTypeOverrideTest("overrideHeader1",
|
||||
"[override-header&override-header-1 # Foo]");
|
||||
|
||||
TokenTypeOverrideTest("overrideHeader2",
|
||||
"[override-header&override-header-2 ## Foo]");
|
||||
|
||||
TokenTypeOverrideTest("overrideHeader3",
|
||||
"[override-header&override-header-3 ### Foo]");
|
||||
|
||||
TokenTypeOverrideTest("overrideHeader4",
|
||||
"[override-header&override-header-4 #### Foo]");
|
||||
|
||||
TokenTypeOverrideTest("overrideHeader5",
|
||||
"[override-header&override-header-5 ##### Foo]");
|
||||
|
||||
TokenTypeOverrideTest("overrideHeader6",
|
||||
"[override-header&override-header-6 ###### Foo]");
|
||||
|
||||
TokenTypeOverrideTest("overrideCode",
|
||||
"[override-code `foo`]");
|
||||
|
||||
TokenTypeOverrideTest("overrideCodeBlock",
|
||||
"[override-code ```]",
|
||||
"[override-code foo]",
|
||||
"[override-code ```]");
|
||||
|
||||
TokenTypeOverrideTest("overrideQuote",
|
||||
"[override-quote&override-quote-1 > foo]",
|
||||
"[override-quote&override-quote-1 > bar]");
|
||||
|
||||
TokenTypeOverrideTest("overrideQuoteNested",
|
||||
"[override-quote&override-quote-1 > foo]",
|
||||
"[override-quote&override-quote-1 >][override-quote&override-quote-2 > bar]",
|
||||
"[override-quote&override-quote-1 >][override-quote&override-quote-2 >][override-quote&override-quote-3 > baz]");
|
||||
|
||||
TokenTypeOverrideTest("overrideLists",
|
||||
"[override-list1 - foo]",
|
||||
"",
|
||||
" [override-list2 + bar]",
|
||||
"",
|
||||
" [override-list3 * baz]",
|
||||
"",
|
||||
" [override-list1 1. qux]",
|
||||
"",
|
||||
" [override-list2 - quux]");
|
||||
|
||||
TokenTypeOverrideTest("overrideHr",
|
||||
"[override-hr * * *]");
|
||||
|
||||
TokenTypeOverrideTest("overrideImage",
|
||||
"[override-image&override-image-marker !][override-image&override-image-alt-text&link [[alt text]]][override-link-href&url (http://link.to/image.jpg)]");
|
||||
|
||||
TokenTypeOverrideTest("overrideLinkText",
|
||||
"[override-link-text [[foo]]][override-link-href&url (http://example.com)]");
|
||||
|
||||
TokenTypeOverrideTest("overrideLinkEmailAndInline",
|
||||
"[override-link-email <][override-link-inline foo@example.com>]");
|
||||
|
||||
TokenTypeOverrideTest("overrideEm",
|
||||
"[override-em *foo*]");
|
||||
|
||||
TokenTypeOverrideTest("overrideStrong",
|
||||
"[override-strong **foo**]");
|
||||
|
||||
TokenTypeOverrideTest("overrideStrikethrough",
|
||||
"[override-strikethrough ~~foo~~]");
|
||||
|
||||
FormatTokenTypeOverrideTest("overrideFormatting",
|
||||
"[override-formatting-escape \\*]");
|
||||
|
||||
// Tests to make sure GFM-specific things aren't getting through
|
||||
|
||||
MT("taskList",
|
||||
"[variable-2 * [ ]] bar]");
|
||||
|
||||
MT("noFencedCodeBlocks",
|
||||
"~~~",
|
||||
"foo",
|
||||
"~~~");
|
||||
|
||||
FencedTest("fencedCodeBlocks",
|
||||
"[comment ```]",
|
||||
"[comment foo]",
|
||||
"[comment ```]",
|
||||
"bar");
|
||||
|
||||
FencedTest("fencedCodeBlocksMultipleChars",
|
||||
"[comment `````]",
|
||||
"[comment foo]",
|
||||
"[comment ```]",
|
||||
"[comment foo]",
|
||||
"[comment `````]",
|
||||
"bar");
|
||||
|
||||
FencedTest("fencedCodeBlocksTildes",
|
||||
"[comment ~~~]",
|
||||
"[comment foo]",
|
||||
"[comment ~~~]",
|
||||
"bar");
|
||||
|
||||
FencedTest("fencedCodeBlocksTildesMultipleChars",
|
||||
"[comment ~~~~~]",
|
||||
"[comment ~~~]",
|
||||
"[comment foo]",
|
||||
"[comment ~~~~~]",
|
||||
"bar");
|
||||
|
||||
FencedTest("fencedCodeBlocksMultipleChars",
|
||||
"[comment `````]",
|
||||
"[comment foo]",
|
||||
"[comment ```]",
|
||||
"[comment foo]",
|
||||
"[comment `````]",
|
||||
"bar");
|
||||
|
||||
FencedTest("fencedCodeBlocksMixed",
|
||||
"[comment ~~~]",
|
||||
"[comment ```]",
|
||||
"[comment foo]",
|
||||
"[comment ~~~]",
|
||||
"bar");
|
||||
|
||||
// Tests that require XML mode
|
||||
|
||||
MT("xmlMode",
|
||||
"[tag&bracket <][tag div][tag&bracket >]",
|
||||
"*foo*",
|
||||
"[tag&bracket <][tag http://github.com][tag&bracket />]",
|
||||
"[tag&bracket </][tag div][tag&bracket >]",
|
||||
"[link <http://github.com/>]");
|
||||
|
||||
MT("xmlModeWithMarkdownInside",
|
||||
"[tag&bracket <][tag div] [attribute markdown]=[string 1][tag&bracket >]",
|
||||
"[em *foo*]",
|
||||
"[link <http://github.com/>]",
|
||||
"[tag </div>]",
|
||||
"[link <http://github.com/>]",
|
||||
"[tag&bracket <][tag div][tag&bracket >]",
|
||||
"[tag&bracket </][tag div][tag&bracket >]");
|
||||
|
||||
})();
|
37
BrowserMark/js/codemirror/theme/lucario.css
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Name: lucario
|
||||
Author: Raphael Amorim
|
||||
|
||||
Original Lucario color scheme (https://github.com/raphamorim/lucario)
|
||||
*/
|
||||
|
||||
.cm-s-lucario.CodeMirror, .cm-s-lucario .CodeMirror-gutters {
|
||||
background-color: #2b3e50 !important;
|
||||
color: #f8f8f2 !important;
|
||||
border: none;
|
||||
}
|
||||
.cm-s-lucario .CodeMirror-gutters { color: #2b3e50; }
|
||||
.cm-s-lucario .CodeMirror-cursor { border-left: solid thin #E6C845; }
|
||||
.cm-s-lucario .CodeMirror-linenumber { color: #f8f8f2; }
|
||||
.cm-s-lucario .CodeMirror-selected { background: #243443; }
|
||||
.cm-s-lucario .CodeMirror-line::selection, .cm-s-lucario .CodeMirror-line > span::selection, .cm-s-lucario .CodeMirror-line > span > span::selection { background: #243443; }
|
||||
.cm-s-lucario .CodeMirror-line::-moz-selection, .cm-s-lucario .CodeMirror-line > span::-moz-selection, .cm-s-lucario .CodeMirror-line > span > span::-moz-selection { background: #243443; }
|
||||
.cm-s-lucario span.cm-comment { color: #5c98cd; }
|
||||
.cm-s-lucario span.cm-string, .cm-s-lucario span.cm-string-2 { color: #E6DB74; }
|
||||
.cm-s-lucario span.cm-number { color: #ca94ff; }
|
||||
.cm-s-lucario span.cm-variable { color: #f8f8f2; }
|
||||
.cm-s-lucario span.cm-variable-2 { color: #f8f8f2; }
|
||||
.cm-s-lucario span.cm-def { color: #72C05D; }
|
||||
.cm-s-lucario span.cm-operator { color: #66D9EF; }
|
||||
.cm-s-lucario span.cm-keyword { color: #ff6541; }
|
||||
.cm-s-lucario span.cm-atom { color: #bd93f9; }
|
||||
.cm-s-lucario span.cm-meta { color: #f8f8f2; }
|
||||
.cm-s-lucario span.cm-tag { color: #ff6541; }
|
||||
.cm-s-lucario span.cm-attribute { color: #66D9EF; }
|
||||
.cm-s-lucario span.cm-qualifier { color: #72C05D; }
|
||||
.cm-s-lucario span.cm-property { color: #f8f8f2; }
|
||||
.cm-s-lucario span.cm-builtin { color: #72C05D; }
|
||||
.cm-s-lucario span.cm-variable-3, .cm-s-lucario span.cm-type { color: #ffb86c; }
|
||||
|
||||
.cm-s-lucario .CodeMirror-activeline-background { background: #243443; }
|
||||
.cm-s-lucario .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }
|
53
BrowserMark/js/codemirror/theme/material.css
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
Name: material
|
||||
Author: Michael Kaminsky (http://github.com/mkaminsky11)
|
||||
|
||||
Original material color scheme by Mattia Astorino (https://github.com/equinusocio/material-theme)
|
||||
|
||||
*/
|
||||
|
||||
.cm-s-material {
|
||||
background-color: #263238;
|
||||
color: rgba(233, 237, 237, 1);
|
||||
}
|
||||
.cm-s-material .CodeMirror-gutters {
|
||||
background: #263238;
|
||||
color: rgb(83,127,126);
|
||||
border: none;
|
||||
}
|
||||
.cm-s-material .CodeMirror-guttermarker, .cm-s-material .CodeMirror-guttermarker-subtle, .cm-s-material .CodeMirror-linenumber { color: rgb(83,127,126); }
|
||||
.cm-s-material .CodeMirror-cursor { border-left: 1px solid #f8f8f0; }
|
||||
.cm-s-material div.CodeMirror-selected { background: rgba(255, 255, 255, 0.15); }
|
||||
.cm-s-material.CodeMirror-focused div.CodeMirror-selected { background: rgba(255, 255, 255, 0.10); }
|
||||
.cm-s-material .CodeMirror-line::selection, .cm-s-material .CodeMirror-line > span::selection, .cm-s-material .CodeMirror-line > span > span::selection { background: rgba(255, 255, 255, 0.10); }
|
||||
.cm-s-material .CodeMirror-line::-moz-selection, .cm-s-material .CodeMirror-line > span::-moz-selection, .cm-s-material .CodeMirror-line > span > span::-moz-selection { background: rgba(255, 255, 255, 0.10); }
|
||||
|
||||
.cm-s-material .CodeMirror-activeline-background { background: rgba(0, 0, 0, 0); }
|
||||
.cm-s-material .cm-keyword { color: rgba(199, 146, 234, 1); }
|
||||
.cm-s-material .cm-operator { color: rgba(233, 237, 237, 1); }
|
||||
.cm-s-material .cm-variable-2 { color: #80CBC4; }
|
||||
.cm-s-material .cm-variable-3 { color: #82B1FF; }
|
||||
.cm-s-material .cm-builtin { color: #DECB6B; }
|
||||
.cm-s-material .cm-atom { color: #F77669; }
|
||||
.cm-s-material .cm-number { color: #F77669; }
|
||||
.cm-s-material .cm-def { color: rgba(233, 237, 237, 1); }
|
||||
.cm-s-material .cm-string { color: #C3E88D; }
|
||||
.cm-s-material .cm-string-2 { color: #80CBC4; }
|
||||
.cm-s-material .cm-comment { color: #546E7A; }
|
||||
.cm-s-material .cm-variable { color: #82B1FF; }
|
||||
.cm-s-material .cm-tag { color: #80CBC4; }
|
||||
.cm-s-material .cm-meta { color: #80CBC4; }
|
||||
.cm-s-material .cm-attribute { color: #FFCB6B; }
|
||||
.cm-s-material .cm-property { color: #80CBAE; }
|
||||
.cm-s-material .cm-qualifier { color: #DECB6B; }
|
||||
.cm-s-material .cm-variable-3 { color: #DECB6B; }
|
||||
.cm-s-material .cm-tag { color: rgba(255, 83, 112, 1); }
|
||||
.cm-s-material .cm-error {
|
||||
color: rgba(255, 255, 255, 1.0);
|
||||
background-color: #EC5F67;
|
||||
}
|
||||
.cm-s-material .CodeMirror-matchingbracket {
|
||||
text-decoration: underline;
|
||||
color: white !important;
|
||||
}
|
1498
BrowserMark/js/lib/backbone.js
Normal file
914
BrowserMark/js/lib/extract-content.js
Normal file
@ -0,0 +1,914 @@
|
||||
if (typeof ExtractContentJS == 'undefined') {
|
||||
var ExtractContentJS = {};
|
||||
}
|
||||
if (typeof ExtractContentJS.Lib == 'undefined') {
|
||||
ExtractContentJS.Lib = {};
|
||||
}
|
||||
|
||||
ExtractContentJS.Lib.Util = (function() {
|
||||
var Util = {};
|
||||
Util.BenchmarkTimer = function() {
|
||||
var now = function() {
|
||||
var d = new Date();
|
||||
var t = 0;
|
||||
t = d.getHours();
|
||||
t = t * 60 + d.getMinutes();
|
||||
t = t * 60 + d.getSeconds();
|
||||
t = t * 1000 + d.getMilliseconds();
|
||||
return t;
|
||||
};
|
||||
var Timer = function() {
|
||||
var self = {
|
||||
elapsed: 0
|
||||
};
|
||||
self.reset = function() {
|
||||
self.elapsed = 0;
|
||||
return self
|
||||
};
|
||||
self.start = function() {
|
||||
self.msec = now();
|
||||
return self
|
||||
};
|
||||
self.stop = function() {
|
||||
self.elapsed += now() - self.msec;
|
||||
return self;
|
||||
};
|
||||
return self.start();
|
||||
};
|
||||
|
||||
var self = {
|
||||
timers: {}
|
||||
};
|
||||
self.get = function(name) {
|
||||
if (!self.timers[name]) {
|
||||
self.timers[name] = new Timer();
|
||||
}
|
||||
return self.timers[name];
|
||||
};
|
||||
self.reset = function(name) {
|
||||
return self.get(name).reset();
|
||||
};
|
||||
self.start = function(name) {
|
||||
return self.get(name).start();
|
||||
};
|
||||
self.stop = function(name) {
|
||||
return self.get(name).stop();
|
||||
};
|
||||
return self;
|
||||
};
|
||||
Util.Token = function(word) {
|
||||
var regex = {
|
||||
// hiragana: /[あ-んが-ぼぁ-ょゎっー]/,
|
||||
hiragana: /[\u3042-\u3093\u304C-\u307C\u3041-\u3087\u308E\u3063\u30FC]/,
|
||||
// katakana: /[ア-ンガ-ボァ-ョヮッー]/,
|
||||
katakana: /[\u30A2-\u30F3\u30AC-\u30DC\u30A1-\u30E7\u30EE\u30C3\u30FC]/,
|
||||
kanji: {
|
||||
test: function(w) {
|
||||
// return '一' <= w && w <= '龠' || w === '々';
|
||||
return '\u4E00' <= w && w <= '\u9FA0' || w === '\u3005';
|
||||
}
|
||||
},
|
||||
alphabet: /[a-zA-Z]/,
|
||||
digit: /[0-9]/
|
||||
};
|
||||
var tests = function(w) {
|
||||
var match = {};
|
||||
for (var r in regex) {
|
||||
if (regex[r].test(w)) {
|
||||
match[r] = regex[r];
|
||||
}
|
||||
}
|
||||
return match;
|
||||
};
|
||||
var self = {
|
||||
first: tests(word.charAt(0)),
|
||||
last: tests(word.charAt(word.length - 1))
|
||||
};
|
||||
self.isTokenized = function(prev, next) {
|
||||
var p = prev.length ? prev.charAt(prev.length - 1) : '';
|
||||
var n = next.length ? next.charAt(0) : '';
|
||||
var check = function(w, test) {
|
||||
if (w.length) {
|
||||
for (var t in test) {
|
||||
if (test[t].test(w)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
return check(p, self.first) && check(n, self.last);
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
Util.inherit = function(child, parent) {
|
||||
var obj = child || {};
|
||||
for (var prop in parent) {
|
||||
if (typeof obj[prop] == 'undefined') {
|
||||
obj[prop] = parent[prop];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
Util.countMatch = function(text, regex) {
|
||||
return text.split(regex).length - 1;
|
||||
// var n=0;
|
||||
// for (var i=0;;) {
|
||||
// i = text.search(regex);
|
||||
// if (i < 0) break;
|
||||
// n++;
|
||||
// text = text.substr(i+1);
|
||||
// }
|
||||
// return n;
|
||||
};
|
||||
Util.countMatchTokenized = function(text, word) {
|
||||
var count = 0;
|
||||
var prev = null;
|
||||
var tok = new Util.Token(word);
|
||||
var texts = text.split(word);
|
||||
var len = texts.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (prev && tok.isTokenized(prev, texts[i])) count++;
|
||||
prev = texts[i]
|
||||
}
|
||||
return count;
|
||||
};
|
||||
Util.indexOfTokenized = function(text, word) {
|
||||
var index = text.indexOf(word);
|
||||
if (index >= 0) {
|
||||
var tok = new Util.Token(word);
|
||||
var p = index > 1 ? text.substr(index - 1, 1) : '';
|
||||
var n = text.substr(index + word.length, 1);
|
||||
if (tok.isTokenized(p, n)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
Util.dump = function(obj) {
|
||||
if (typeof obj == 'undefined') return 'undefined';
|
||||
if (typeof obj == 'string') return '"' + obj + '"';
|
||||
if (typeof obj != 'object') return '' + obj;
|
||||
if (obj === null) return 'null';
|
||||
if (obj instanceof Array) {
|
||||
return '[' + obj.map(function(v) {
|
||||
return 'obj' /*Util.dump(v)*/
|
||||
;
|
||||
}).join(',') + ']';
|
||||
} else {
|
||||
var arr = [];
|
||||
for (var prop in obj) {
|
||||
arr.push(prop + ':' + 'obj' /*Util.dump(obj[prop])*/ );
|
||||
}
|
||||
return '{' + arr.join(',') + '}';
|
||||
}
|
||||
};
|
||||
return Util;
|
||||
})();
|
||||
|
||||
ExtractContentJS.Lib.A = (function() {
|
||||
var A = {};
|
||||
A.indexOf = Array.indexOf || function(self, elt /*, from*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
var from = Number(arguments[argi++]) || 0;
|
||||
from = (from < 0) ? Math.ceil(from) : Math.floor(from);
|
||||
if (from < 0) from += len;
|
||||
for (; from < len; from++) {
|
||||
if (from in self && self[from] === elt) return from;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
A.filter = Array.filter || function(self, fun /*, thisp*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
if (typeof fun != "function") {
|
||||
throw new TypeError('A.filter: not a function');
|
||||
}
|
||||
var rv = new Array();
|
||||
var thisp = arguments[argi++];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in self) {
|
||||
var val = self[i]; // in case fun mutates this
|
||||
if (fun.call(thisp, val, i, self)) rv.push(val);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
A.forEach = Array.forEach || function(self, fun /*, thisp*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
if (typeof fun != 'function') {
|
||||
throw new TypeError('A.forEach: not a function');
|
||||
}
|
||||
var thisp = arguments[argi++];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in self) fun.call(thisp, self[i], i, self);
|
||||
}
|
||||
};
|
||||
A.every = Array.every || function(self, fun /*, thisp*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
if (typeof fun != 'function') {
|
||||
throw new TypeError('A.every: not a function');
|
||||
}
|
||||
var thisp = arguments[argi++];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in self && !fun.call(thisp, self[i], i, self)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
A.map = Array.map || function(self, fun /*, thisp*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
if (typeof fun != 'function') {
|
||||
throw new TypeError('A.map: not a function');
|
||||
}
|
||||
var rv = new Array(len);
|
||||
var thisp = arguments[argi++];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in self) {
|
||||
rv[i] = fun.call(thisp, self[i], i, self);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
A.some = Array.some || function(self, fun /*, thisp*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
if (typeof fun != "function") {
|
||||
throw new TypeError('A.some: not a function');
|
||||
}
|
||||
var thisp = arguments[argi++];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in self && fun.call(thisp, self[i], i, self)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
A.reduce = Array.reduce || function(self, fun /*, initial*/ ) {
|
||||
var argi = 2;
|
||||
var len = self.length;
|
||||
if (typeof fun != 'function') {
|
||||
throw TypeError('A.reduce: not a function ');
|
||||
}
|
||||
var i = 0;
|
||||
var prev;
|
||||
if (arguments.length > argi) {
|
||||
var rv = arguments[argi++];
|
||||
} else {
|
||||
do {
|
||||
if (i in self) {
|
||||
rv = self[i++];
|
||||
break;
|
||||
}
|
||||
if (++i >= len) {
|
||||
throw new TypeError('A.reduce: empty array');
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
for (; i < len; i++) {
|
||||
if (i in self) rv = fun.call(null, rv, self[i], i, self);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
A.zip = function(self) {
|
||||
if (self[0] instanceof Array) {
|
||||
var l = self[0].length;
|
||||
var len = self.length;
|
||||
var z = new Array(l);
|
||||
for (var i = 0; i < l; i++) {
|
||||
z[i] = [];
|
||||
for (var j = 0; j < len; j++) {
|
||||
z[i].push(self[j][i]);
|
||||
}
|
||||
}
|
||||
return z;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
A.first = function(self) {
|
||||
return self ? self[0] : null;
|
||||
};
|
||||
A.last = function(self) {
|
||||
return self ? self[self.length - 1] : null;
|
||||
};
|
||||
A.push = function(self, other) {
|
||||
return Array.prototype.push.apply(self, other);
|
||||
};
|
||||
return A;
|
||||
})();
|
||||
|
||||
ExtractContentJS.Lib.DOM = (function() {
|
||||
var A = ExtractContentJS.Lib.A;
|
||||
var DOM = {};
|
||||
DOM.getElementStyle = function(elem, prop) {
|
||||
var style = elem.style ? elem.style[prop] : null;
|
||||
if (!style) {
|
||||
var dv = elem.ownerDocument.defaultView;
|
||||
if (dv && dv.getComputedStyle) {
|
||||
try {
|
||||
var styles = dv.getComputedStyle(elem, null);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
prop = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
||||
style = styles ? styles.getPropertyValue(prop) : null;
|
||||
} else if (elem.currentStyle) {
|
||||
style = elem.currentStyle[prop];
|
||||
}
|
||||
}
|
||||
return style;
|
||||
};
|
||||
DOM.text = function(node) {
|
||||
if (typeof node.textContent != 'undefined') {
|
||||
return node.textContent;
|
||||
} else if (node.nodeName == '#text') {
|
||||
return node.nodeValue;
|
||||
} else if (typeof node.innerText != 'undefined') {
|
||||
return node.innerText; // IE
|
||||
}
|
||||
return null;
|
||||
};
|
||||
DOM.ancestors = function(e) {
|
||||
var body = e.ownerDocument.body;
|
||||
var r = [];
|
||||
var it = e;
|
||||
while (it != body) {
|
||||
r.push(it);
|
||||
it = it.parentNode;
|
||||
}
|
||||
r.push(body);
|
||||
return r; // [e .. document.body]
|
||||
};
|
||||
DOM.commonAncestor = function(e1, e2) {
|
||||
var a1 = DOM.ancestors(e1).reverse();
|
||||
var a2 = DOM.ancestors(e2).reverse();
|
||||
var r = null;
|
||||
for (var i = 0; a1[i] && a2[i] && a1[i] == a2[i]; i++) {
|
||||
r = a1[i];
|
||||
}
|
||||
return r;
|
||||
};
|
||||
DOM.countMatchTagAttr = function(node, tag, attr, regexs) {
|
||||
var test = function(v) {
|
||||
return v.test(node[attr]);
|
||||
};
|
||||
if ((node.tagName || '').toLowerCase() == tag && A.some(regexs, test)) {
|
||||
return 1;
|
||||
}
|
||||
var n = 0;
|
||||
var children = node.childNodes;
|
||||
for (var i = 0, len = children.length; i < len; i++) {
|
||||
n += DOM.countMatchTagAttr(children[i], tag, attr, regexs);
|
||||
}
|
||||
return n;
|
||||
};
|
||||
DOM.matchTag = function(node, pat) {
|
||||
return A.some(pat, function(v) {
|
||||
if (typeof v == 'string') {
|
||||
try {
|
||||
return v == (node.tagName || '').toLowerCase();
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
} else if (v instanceof Array) {
|
||||
return v[0] == (node.tagName || '').toLowerCase() && DOM.matchAttr(node, v[1]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
DOM.matchAttr = function(node, pat) {
|
||||
var test = function(pat, val) {
|
||||
if (typeof pat == 'string') {
|
||||
return pat == val;
|
||||
} else if (pat instanceof RegExp) {
|
||||
return pat.test(val);
|
||||
} else if (pat instanceof Array) {
|
||||
return A.some(pat, function(v) {
|
||||
return test(v, val);
|
||||
});
|
||||
} else if (pat instanceof Object) {
|
||||
for (var prop in pat) {
|
||||
var n = node[prop];
|
||||
if (n && DOM.matchAttr(n, pat[prop])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (var prop in pat) {
|
||||
var attr = node[prop];
|
||||
var ar = pat[prop];
|
||||
if (attr) {
|
||||
return test(ar, attr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
DOM.matchStyle = function(node, pat) {
|
||||
var test = function(pat, val) {
|
||||
if (typeof pat == 'string') {
|
||||
return pat == val;
|
||||
} else if (pat instanceof RegExp) {
|
||||
return pat.test(val);
|
||||
} else if (pat instanceof Array) {
|
||||
return A.some(pat, function(v) {
|
||||
return test(v, val);
|
||||
});
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (var prop in pat) {
|
||||
if (test(pat[prop], DOM.getElementStyle(node, prop))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
return DOM;
|
||||
})();
|
||||
|
||||
if (typeof ExtractContentJS == 'undefined') {
|
||||
var ExtractContentJS = {};
|
||||
}
|
||||
|
||||
(function(ns) {
|
||||
var Util = ns.Lib.Util;
|
||||
var A = ns.Lib.A;
|
||||
var DOM = ns.Lib.DOM;
|
||||
|
||||
var Leaf = Util.inherit(function(node /*, depth, inside, limit*/ ) {
|
||||
var depth = arguments[1] || 0;
|
||||
var inside = arguments[2] || {};
|
||||
var limit = arguments[3] || 1048576;
|
||||
var leaf = {
|
||||
node: node,
|
||||
depth: depth,
|
||||
inside: inside
|
||||
};
|
||||
|
||||
leaf.statistics = function() {
|
||||
var t = (DOM.text(node) || '').replace(/\s+/g, ' ');
|
||||
var l = t.length;
|
||||
return {
|
||||
text: t.substr(0, limit),
|
||||
noLinkText: (inside.link || inside.form) ? '' : t,
|
||||
listTextLength: inside.list ? l : 0,
|
||||
noListTextLength: inside.list ? 0 : l,
|
||||
linkCount: inside.link ? 1 : 0,
|
||||
listCount: inside.li ? 1 : 0,
|
||||
linkListCount: (inside.li && inside.link) ? 1 : 0
|
||||
};
|
||||
};
|
||||
|
||||
return leaf;
|
||||
}, {
|
||||
commonAncestor: function( /* leaves */ ) {
|
||||
var ar = A.map(arguments, function(v) {
|
||||
return v.node;
|
||||
});
|
||||
if (ar.length < 2) {
|
||||
return ar[0];
|
||||
}
|
||||
return A.reduce(ar, function(prev, curr) {
|
||||
return DOM.commonAncestor(prev, curr);
|
||||
});
|
||||
},
|
||||
mergeStatistics: function(a, b) {
|
||||
var r = {};
|
||||
for (var prop in a) {
|
||||
r[prop] = a[prop] + b[prop];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
});
|
||||
|
||||
var Block = function(leaves) {
|
||||
leaves = A.filter(leaves, function(v) {
|
||||
var s = DOM.text(v.node) || '';
|
||||
s = s.replace(/\s+/g, '');
|
||||
return s.length != 0;
|
||||
});
|
||||
var block = {
|
||||
score: 0,
|
||||
leaves: leaves
|
||||
};
|
||||
block.commonAncestor = function() {
|
||||
return Leaf.commonAncestor.apply(null, block.leaves);
|
||||
};
|
||||
return block;
|
||||
};
|
||||
|
||||
var Content = function(c) {
|
||||
var self = {
|
||||
_content: c
|
||||
};
|
||||
|
||||
self.asLeaves = function() {
|
||||
return self._content;
|
||||
};
|
||||
self.asNode = function() {
|
||||
if (self._node) return self._node;
|
||||
self._node = Leaf.commonAncestor.apply(null, self._content);
|
||||
return self._node;
|
||||
};
|
||||
self.asTextFragment = function() {
|
||||
if (self._textFragment) return self._textFragment;
|
||||
if (self._content.length < 1) return '';
|
||||
self._textFragment = A.reduce(self._content, function(prev, curr) {
|
||||
var s = DOM.text(curr.node);
|
||||
s = s.replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
s = s.replace(/\s+/g, ' ');
|
||||
return prev + s;
|
||||
}, '');
|
||||
return self._textFragment;
|
||||
};
|
||||
self.asText = function() {
|
||||
if (self._text) return self._text;
|
||||
// covering node
|
||||
var node = self.asNode();
|
||||
self._text = node ? DOM.text(node) : '';
|
||||
return self._text;
|
||||
};
|
||||
self.toString = function() {
|
||||
return self.asTextFragment();
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
ns.LayeredExtractor = function( /* handler, filter */ ) {
|
||||
var self = {
|
||||
handler: arguments[0] || [],
|
||||
filter: arguments[1] || {}
|
||||
};
|
||||
|
||||
self.factory = {
|
||||
getHandler: function(name) {
|
||||
if (typeof ns.LayeredExtractor.Handler != 'undefined') {
|
||||
return new ns.LayeredExtractor.Handler[name];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
self.addHandler = function(handler) {
|
||||
if (typeof handler != 'undefined') {
|
||||
self.handler.push(handler);
|
||||
}
|
||||
return self;
|
||||
};
|
||||
|
||||
self.filterFor = function(url) {
|
||||
// TODO
|
||||
};
|
||||
|
||||
self.extract = function(d) {
|
||||
var url = d.location.href;
|
||||
var res = {
|
||||
title: d.title,
|
||||
url: d.location.href
|
||||
};
|
||||
var len = self.handler.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var content = self.handler[i].extract(d, url, res);
|
||||
if (!content) continue;
|
||||
|
||||
var f = self.filterFor(url);
|
||||
if (f) {
|
||||
content = f.filter(content);
|
||||
}
|
||||
|
||||
content = new Content(content);
|
||||
if (!content.toString().length) continue;
|
||||
res.content = content;
|
||||
res.isSuccess = true;
|
||||
res.engine = res.engine || self.handler[i];
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
ns.LayeredExtractor.Handler = {};
|
||||
|
||||
ns.LayeredExtractor.Handler.Heuristics = function( /*option, pattern*/ ) {
|
||||
var self = {
|
||||
name: 'Heuristics',
|
||||
content: [],
|
||||
opt: Util.inherit(arguments[0], {
|
||||
threshold: 180,
|
||||
minLength: 150,
|
||||
factor: {
|
||||
decay: 0.75,
|
||||
noBody: 0.72,
|
||||
continuous: 1.16 //1.62
|
||||
},
|
||||
punctuationWeight: 10,
|
||||
minNoLink: 8,
|
||||
noListRatio: 0.2,
|
||||
limit: {
|
||||
leaves: 800,
|
||||
recursion: 20,
|
||||
text: 1048576
|
||||
},
|
||||
debug: false
|
||||
}),
|
||||
pat: Util.inherit(arguments[1], {
|
||||
sep: [
|
||||
'div', 'center', 'td',
|
||||
'h1', 'h2'],
|
||||
waste: [
|
||||
/Copyright|All\s*Rights?\s*Reserved?/i],
|
||||
affiliate: [
|
||||
/amazon[a-z0-9\.\/\-\?&]+-22/i],
|
||||
list: ['ul', 'dl', 'ol'],
|
||||
li: ['li', 'dd'],
|
||||
a: ['a'],
|
||||
form: ['form'],
|
||||
noContent: ['frameset'],
|
||||
ignore: [
|
||||
'iframe',
|
||||
//'img',
|
||||
'script',
|
||||
'style',
|
||||
'select',
|
||||
'noscript', ['div', {
|
||||
id: [/more/, /menu/, /side/, /navi/, /foot/],
|
||||
className: [/more/, /menu/, /side/, /navi/, /foot/]
|
||||
}]],
|
||||
ignoreStyle: {
|
||||
display: 'none',
|
||||
visibility: 'hidden'
|
||||
},
|
||||
// punctuations: /[。、.,!?]|\.[^A-Za-z0-9]|,[^0-9]|!|\?/
|
||||
punctuations: /[\u3002\u3001\uFF0E\uFF0C\uFF01\uFF1F]|\.[^A-Za-z0-9]|,[^0-9]|!|\?/
|
||||
})
|
||||
};
|
||||
|
||||
var MyBlock = Util.inherit(function(leaves) {
|
||||
var block = new Block(leaves);
|
||||
|
||||
block.eliminateLinks = function() {
|
||||
var st = A.map(block.leaves, function(v) {
|
||||
return v.statistics();
|
||||
});
|
||||
if (!st.length) return '';
|
||||
if (st.length == 1) {
|
||||
st = st[0];
|
||||
} else {
|
||||
st = A.reduce(st, function(prev, curr) {
|
||||
return Leaf.mergeStatistics(prev, curr);
|
||||
});
|
||||
}
|
||||
var nolinklen = st.noLinkText.length;
|
||||
var links = st.linkCount;
|
||||
var listlen = st.listTextLength;
|
||||
if (nolinklen < self.opt.minNoLink * links) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// isLinklist
|
||||
var rate = st.linkListCount / (st.listCount || 1);
|
||||
rate *= rate;
|
||||
var limit = self.opt.noListRatio * rate * listlen;
|
||||
if (nolinklen < limit) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return st.noLinkText;
|
||||
};
|
||||
block.noBodyRate = function() {
|
||||
var val = 0;
|
||||
if (block.leaves.length > 0) {
|
||||
val += A.reduce(block.leaves, function(prev, curr) {
|
||||
return prev + DOM.countMatchTagAttr(curr.node, 'a', 'href',
|
||||
self.pat.affiliate);
|
||||
}, 0);
|
||||
}
|
||||
val /= 2.0;
|
||||
val += A.reduce(self.pat.waste, function(prev, curr) {
|
||||
return prev + Util.countMatch(block._nolink, curr);
|
||||
}, 0);
|
||||
return val;
|
||||
};
|
||||
|
||||
block.calcScore = function(factor, continuous) {
|
||||
// ignore link list block
|
||||
block._nolink = block.eliminateLinks();
|
||||
if (block._nolink.length < self.opt.minLength) return 0;
|
||||
|
||||
var c = Util.countMatch(block._nolink, self.pat.punctuations);
|
||||
c *= self.opt.punctuationWeight;
|
||||
c += block._nolink.length;
|
||||
c *= factor;
|
||||
|
||||
// anti-scoring factors
|
||||
var noBodyRate = block.noBodyRate();
|
||||
|
||||
// scores
|
||||
c *= Math.pow(self.opt.factor.noBody, noBodyRate);
|
||||
block._c = block.score = c;
|
||||
block._c1 = c * continuous;
|
||||
return c;
|
||||
};
|
||||
|
||||
block.isAccepted = function() {
|
||||
return block._c > self.opt.threshold;
|
||||
};
|
||||
|
||||
block.isContinuous = function() {
|
||||
return block._c1 > self.opt.threshold;
|
||||
};
|
||||
|
||||
block.merge = function(other) {
|
||||
block.score += other._c1;
|
||||
block.depth = Math.min(block.depth, other.depth);
|
||||
A.push(block.leaves, other.leaves);
|
||||
return block;
|
||||
};
|
||||
|
||||
return block;
|
||||
}, {
|
||||
split: function(node) {
|
||||
var r = [];
|
||||
var buf = [];
|
||||
var leaves = 0;
|
||||
//mark note
|
||||
var limit = self.opt.limit.text;
|
||||
|
||||
var flush = function(flag) {
|
||||
if (flag && buf.length) {
|
||||
r.push(new MyBlock(buf));
|
||||
buf = [];
|
||||
}
|
||||
};
|
||||
|
||||
var rec = function(node, depth, inside) {
|
||||
// depth-first recursion
|
||||
if (leaves >= self.opt.limit.leaves) return r;
|
||||
if (depth >= self.opt.limit.recursion) return r;
|
||||
if (node.nodeName == '#comment') return r;
|
||||
if (DOM.matchTag(node, self.pat.ignore)) return r;
|
||||
if (DOM.matchStyle(node, self.pat.ignoreStyle)) return r;
|
||||
var children = node.childNodes;
|
||||
var sep = self.pat.sep;
|
||||
var len = children.length;
|
||||
var flags = {
|
||||
form: inside.form || DOM.matchTag(node, self.pat.form),
|
||||
link: inside.link || DOM.matchTag(node, self.pat.a),
|
||||
list: inside.list || DOM.matchTag(node, self.pat.list),
|
||||
li: inside.li || DOM.matchTag(node, self.pat.li)
|
||||
};
|
||||
for (var i = 0; i < len; i++) {
|
||||
var c = children[i];
|
||||
var f = DOM.matchTag(c, sep);
|
||||
flush(f);
|
||||
rec(c, depth + 1, flags);
|
||||
flush(f);
|
||||
}
|
||||
if (!len) {
|
||||
leaves++;
|
||||
buf.push(new Leaf(node, depth, flags, limit));
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
rec(node, 0, {});
|
||||
flush(true);
|
||||
return r;
|
||||
}
|
||||
});
|
||||
|
||||
self.extract = function(d /*, url, res*/ ) {
|
||||
var isNoContent = function(v) {
|
||||
return d.getElementsByTagName(v).length != 0;
|
||||
};
|
||||
if (A.some(self.pat.noContent, isNoContent)) return self;
|
||||
|
||||
var factor = 1.0;
|
||||
var continuous = 1.0;
|
||||
var score = 0;
|
||||
|
||||
var res = [];
|
||||
var blocks = MyBlock.split(d.body);
|
||||
var last;
|
||||
|
||||
var len = blocks.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var block = blocks[i];
|
||||
if (last) {
|
||||
continuous /= self.opt.factor.continuous;
|
||||
}
|
||||
|
||||
// score
|
||||
if (!block.calcScore(factor, continuous)) continue;
|
||||
factor *= self.opt.factor.decay;
|
||||
|
||||
// clustor scoring
|
||||
if (block.isAccepted()) {
|
||||
if (block.isContinuous() && last) {
|
||||
last.merge(block);
|
||||
} else {
|
||||
last = block;
|
||||
res.push(block);
|
||||
}
|
||||
continuous = self.opt.factor.continuous;
|
||||
} else { // rejected
|
||||
if (!last) {
|
||||
// do not decay if no block is pushed
|
||||
factor = 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.blocks = res.sort(function(a, b) {
|
||||
return b.score - a.score;
|
||||
});
|
||||
var best = A.first(self.blocks);
|
||||
if (best) {
|
||||
self.content = best.leaves;
|
||||
}
|
||||
|
||||
return self.content;
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
ns.LayeredExtractor.Handler.GoogleAdSection = function( /*opt*/ ) {
|
||||
var self = {
|
||||
name: 'GoogleAdSection',
|
||||
content: [],
|
||||
state: [],
|
||||
opt: Util.inherit(arguments[0], {
|
||||
limit: {
|
||||
leaves: 800,
|
||||
recursion: 20
|
||||
},
|
||||
debug: false
|
||||
})
|
||||
};
|
||||
|
||||
var pat = {
|
||||
ignore: /google_ad_section_start\(weight=ignore\)/i,
|
||||
section: /google_ad_section_start/i,
|
||||
end: /google_ad_section_end/i
|
||||
};
|
||||
var stIgnore = 1;
|
||||
var stSection = 2;
|
||||
|
||||
self.inSection = function() {
|
||||
return A.last(self.state) == stSection;
|
||||
};
|
||||
self.ignore = function() {
|
||||
self.state.push(stIgnore);
|
||||
}
|
||||
self.section = function() {
|
||||
self.state.push(stSection);
|
||||
}
|
||||
self.end = function() {
|
||||
if (self.state.length) self.state.pop();
|
||||
};
|
||||
self.parse = function(node /*, depth*/ ) {
|
||||
var depth = arguments[1] || 0;
|
||||
if (node.nodeName == '#comment') {
|
||||
if (pat.ignore.test(node.nodeValue)) {
|
||||
self.ignore();
|
||||
} else if (pat.section.test(node.nodeValue)) {
|
||||
self.section();
|
||||
} else if (pat.end.test(node.nodeValue)) {
|
||||
self.end();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.content.length >= self.opt.limit.leaves) return;
|
||||
if (depth >= self.opt.limit.recursion) return;
|
||||
var children = node.childNodes;
|
||||
var len = children.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var c = children[i];
|
||||
self.parse(c, depth + 1);
|
||||
}
|
||||
if (!len && self.inSection()) {
|
||||
self.content.push(new Leaf(node, depth));
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
self.extract = function(d /*, url, res*/ ) {
|
||||
self.parse(d);
|
||||
self.blocks = [new Block(self.content)];
|
||||
return self.content;
|
||||
};
|
||||
|
||||
return self;
|
||||
};
|
||||
})(ExtractContentJS);
|
4
BrowserMark/js/lib/jquery-2.1.1.min.js
vendored
Normal file
1
BrowserMark/js/lib/jquery-2.1.1.min.map
Normal file
122
BrowserMark/js/lib/prism.js
Normal file
909
BrowserMark/js/lib/turndown.js
Normal file
@ -0,0 +1,909 @@
|
||||
var TurndownService = (function () {
|
||||
'use strict';
|
||||
|
||||
function extend (destination) {
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
var source = arguments[i];
|
||||
for (var key in source) {
|
||||
if (source.hasOwnProperty(key)) destination[key] = source[key];
|
||||
}
|
||||
}
|
||||
return destination
|
||||
}
|
||||
|
||||
function repeat (character, count) {
|
||||
return Array(count + 1).join(character)
|
||||
}
|
||||
|
||||
var blockElements = [
|
||||
'address', 'article', 'aside', 'audio', 'blockquote', 'body', 'canvas',
|
||||
'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
|
||||
'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
||||
'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
|
||||
'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
|
||||
'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
|
||||
];
|
||||
|
||||
function isBlock (node) {
|
||||
return blockElements.indexOf(node.nodeName.toLowerCase()) !== -1
|
||||
}
|
||||
|
||||
var voidElements = [
|
||||
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
|
||||
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
|
||||
];
|
||||
|
||||
function isVoid (node) {
|
||||
return voidElements.indexOf(node.nodeName.toLowerCase()) !== -1
|
||||
}
|
||||
|
||||
var voidSelector = voidElements.join();
|
||||
function hasVoid (node) {
|
||||
return node.querySelector && node.querySelector(voidSelector)
|
||||
}
|
||||
|
||||
var rules = {};
|
||||
|
||||
rules.paragraph = {
|
||||
filter: 'p',
|
||||
|
||||
replacement: function (content) {
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.lineBreak = {
|
||||
filter: 'br',
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
return options.br + '\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.heading = {
|
||||
filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
var hLevel = Number(node.nodeName.charAt(1));
|
||||
|
||||
if (options.headingStyle === 'setext' && hLevel < 3) {
|
||||
var underline = repeat((hLevel === 1 ? '=' : '-'), content.length);
|
||||
return (
|
||||
'\n\n' + content + '\n' + underline + '\n\n'
|
||||
)
|
||||
} else {
|
||||
return '\n\n' + repeat('#', hLevel) + ' ' + content + '\n\n'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rules.blockquote = {
|
||||
filter: 'blockquote',
|
||||
|
||||
replacement: function (content) {
|
||||
content = content.replace(/^\n+|\n+$/g, '');
|
||||
content = content.replace(/^/gm, '> ');
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.list = {
|
||||
filter: ['ul', 'ol'],
|
||||
|
||||
replacement: function (content, node) {
|
||||
var parent = node.parentNode;
|
||||
if (parent.nodeName === 'LI' && parent.lastElementChild === node) {
|
||||
return '\n' + content
|
||||
} else {
|
||||
return '\n\n' + content + '\n\n'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
rules.listItem = {
|
||||
filter: 'li',
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
content = content
|
||||
.replace(/^\n+/, '') // remove leading newlines
|
||||
.replace(/\n+$/, '\n') // replace trailing newlines with just a single one
|
||||
.replace(/\n/gm, '\n '); // indent
|
||||
var prefix = options.bulletListMarker + ' ';
|
||||
var parent = node.parentNode;
|
||||
if (parent.nodeName === 'OL') {
|
||||
var start = parent.getAttribute('start');
|
||||
var index = Array.prototype.indexOf.call(parent.children, node);
|
||||
prefix = (start ? Number(start) + index : index + 1) + '. ';
|
||||
}
|
||||
return (
|
||||
prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : '')
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
rules.indentedCodeBlock = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.codeBlockStyle === 'indented' &&
|
||||
node.nodeName === 'PRE' &&
|
||||
node.firstChild &&
|
||||
node.firstChild.nodeName === 'CODE'
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
return (
|
||||
'\n\n ' +
|
||||
node.firstChild.textContent.replace(/\n/g, '\n ') +
|
||||
'\n\n'
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
rules.fencedCodeBlock = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.codeBlockStyle === 'fenced' &&
|
||||
node.nodeName === 'PRE' &&
|
||||
node.firstChild &&
|
||||
node.firstChild.nodeName === 'CODE'
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
var className = node.firstChild.className || '';
|
||||
var language = (className.match(/language-(\S+)/) || [null, ''])[1];
|
||||
|
||||
return (
|
||||
'\n\n' + options.fence + language + '\n' +
|
||||
node.firstChild.textContent +
|
||||
'\n' + options.fence + '\n\n'
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
rules.horizontalRule = {
|
||||
filter: 'hr',
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
return '\n\n' + options.hr + '\n\n'
|
||||
}
|
||||
};
|
||||
|
||||
rules.inlineLink = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.linkStyle === 'inlined' &&
|
||||
node.nodeName === 'A' &&
|
||||
node.getAttribute('href')
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node) {
|
||||
var href = node.getAttribute('href');
|
||||
var title = node.title ? ' "' + node.title + '"' : '';
|
||||
return '[' + content + '](' + href + title + ')'
|
||||
}
|
||||
};
|
||||
|
||||
rules.referenceLink = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.linkStyle === 'referenced' &&
|
||||
node.nodeName === 'A' &&
|
||||
node.getAttribute('href')
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
var href = node.getAttribute('href');
|
||||
var title = node.title ? ' "' + node.title + '"' : '';
|
||||
var replacement;
|
||||
var reference;
|
||||
|
||||
switch (options.linkReferenceStyle) {
|
||||
case 'collapsed':
|
||||
replacement = '[' + content + '][]';
|
||||
reference = '[' + content + ']: ' + href + title;
|
||||
break
|
||||
case 'shortcut':
|
||||
replacement = '[' + content + ']';
|
||||
reference = '[' + content + ']: ' + href + title;
|
||||
break
|
||||
default:
|
||||
var id = this.references.length + 1;
|
||||
replacement = '[' + content + '][' + id + ']';
|
||||
reference = '[' + id + ']: ' + href + title;
|
||||
}
|
||||
|
||||
this.references.push(reference);
|
||||
return replacement
|
||||
},
|
||||
|
||||
references: [],
|
||||
|
||||
append: function (options) {
|
||||
var references = '';
|
||||
if (this.references.length) {
|
||||
references = '\n\n' + this.references.join('\n') + '\n\n';
|
||||
this.references = []; // Reset references
|
||||
}
|
||||
return references
|
||||
}
|
||||
};
|
||||
|
||||
rules.emphasis = {
|
||||
filter: ['em', 'i'],
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
if (!content.trim()) return ''
|
||||
return options.emDelimiter + content + options.emDelimiter
|
||||
}
|
||||
};
|
||||
|
||||
rules.strong = {
|
||||
filter: ['strong', 'b'],
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
if (!content.trim()) return ''
|
||||
return options.strongDelimiter + content + options.strongDelimiter
|
||||
}
|
||||
};
|
||||
|
||||
rules.code = {
|
||||
filter: function (node) {
|
||||
var hasSiblings = node.previousSibling || node.nextSibling;
|
||||
var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings;
|
||||
|
||||
return node.nodeName === 'CODE' && !isCodeBlock
|
||||
},
|
||||
|
||||
replacement: function (content) {
|
||||
if (!content.trim()) return ''
|
||||
|
||||
var delimiter = '`';
|
||||
var leadingSpace = '';
|
||||
var trailingSpace = '';
|
||||
var matches = content.match(/`+/gm);
|
||||
if (matches) {
|
||||
if (/^`/.test(content)) leadingSpace = ' ';
|
||||
if (/`$/.test(content)) trailingSpace = ' ';
|
||||
while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + '`';
|
||||
}
|
||||
|
||||
return delimiter + leadingSpace + content + trailingSpace + delimiter
|
||||
}
|
||||
};
|
||||
|
||||
rules.image = {
|
||||
filter: 'img',
|
||||
|
||||
replacement: function (content, node) {
|
||||
var alt = node.alt || '';
|
||||
var src = node.getAttribute('src') || '';
|
||||
var title = node.title || '';
|
||||
var titlePart = title ? ' "' + title + '"' : '';
|
||||
return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages a collection of rules used to convert HTML to Markdown
|
||||
*/
|
||||
|
||||
function Rules (options) {
|
||||
this.options = options;
|
||||
this._keep = [];
|
||||
this._remove = [];
|
||||
|
||||
this.blankRule = {
|
||||
replacement: options.blankReplacement
|
||||
};
|
||||
|
||||
this.keepReplacement = options.keepReplacement;
|
||||
|
||||
this.defaultRule = {
|
||||
replacement: options.defaultReplacement
|
||||
};
|
||||
|
||||
this.array = [];
|
||||
for (var key in options.rules) this.array.push(options.rules[key]);
|
||||
}
|
||||
|
||||
Rules.prototype = {
|
||||
add: function (key, rule) {
|
||||
this.array.unshift(rule);
|
||||
},
|
||||
|
||||
keep: function (filter) {
|
||||
this._keep.unshift({
|
||||
filter: filter,
|
||||
replacement: this.keepReplacement
|
||||
});
|
||||
},
|
||||
|
||||
remove: function (filter) {
|
||||
this._remove.unshift({
|
||||
filter: filter,
|
||||
replacement: function () {
|
||||
return ''
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
forNode: function (node) {
|
||||
if (node.isBlank) return this.blankRule
|
||||
var rule;
|
||||
|
||||
if ((rule = findRule(this.array, node, this.options))) return rule
|
||||
if ((rule = findRule(this._keep, node, this.options))) return rule
|
||||
if ((rule = findRule(this._remove, node, this.options))) return rule
|
||||
|
||||
return this.defaultRule
|
||||
},
|
||||
|
||||
forEach: function (fn) {
|
||||
for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
|
||||
}
|
||||
};
|
||||
|
||||
function findRule (rules, node, options) {
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
var rule = rules[i];
|
||||
if (filterValue(rule, node, options)) return rule
|
||||
}
|
||||
return void 0
|
||||
}
|
||||
|
||||
function filterValue (rule, node, options) {
|
||||
var filter = rule.filter;
|
||||
if (typeof filter === 'string') {
|
||||
if (filter === node.nodeName.toLowerCase()) return true
|
||||
} else if (Array.isArray(filter)) {
|
||||
if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true
|
||||
} else if (typeof filter === 'function') {
|
||||
if (filter.call(rule, node, options)) return true
|
||||
} else {
|
||||
throw new TypeError('`filter` needs to be a string, array, or function')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The collapseWhitespace function is adapted from collapse-whitespace
|
||||
* by Luc Thevenard.
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014 Luc Thevenard <lucthevenard@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* collapseWhitespace(options) removes extraneous whitespace from an the given element.
|
||||
*
|
||||
* @param {Object} options
|
||||
*/
|
||||
function collapseWhitespace (options) {
|
||||
var element = options.element;
|
||||
var isBlock = options.isBlock;
|
||||
var isVoid = options.isVoid;
|
||||
var isPre = options.isPre || function (node) {
|
||||
return node.nodeName === 'PRE'
|
||||
};
|
||||
|
||||
if (!element.firstChild || isPre(element)) return
|
||||
|
||||
var prevText = null;
|
||||
var prevVoid = false;
|
||||
|
||||
var prev = null;
|
||||
var node = next(prev, element, isPre);
|
||||
|
||||
while (node !== element) {
|
||||
if (node.nodeType === 3 || node.nodeType === 4) { // Node.TEXT_NODE or Node.CDATA_SECTION_NODE
|
||||
var text = node.data.replace(/[ \r\n\t]+/g, ' ');
|
||||
|
||||
if ((!prevText || / $/.test(prevText.data)) &&
|
||||
!prevVoid && text[0] === ' ') {
|
||||
text = text.substr(1);
|
||||
}
|
||||
|
||||
// `text` might be empty at this point.
|
||||
if (!text) {
|
||||
node = remove(node);
|
||||
continue
|
||||
}
|
||||
|
||||
node.data = text;
|
||||
|
||||
prevText = node;
|
||||
} else if (node.nodeType === 1) { // Node.ELEMENT_NODE
|
||||
if (isBlock(node) || node.nodeName === 'BR') {
|
||||
if (prevText) {
|
||||
prevText.data = prevText.data.replace(/ $/, '');
|
||||
}
|
||||
|
||||
prevText = null;
|
||||
prevVoid = false;
|
||||
} else if (isVoid(node)) {
|
||||
// Avoid trimming space around non-block, non-BR void elements.
|
||||
prevText = null;
|
||||
prevVoid = true;
|
||||
}
|
||||
} else {
|
||||
node = remove(node);
|
||||
continue
|
||||
}
|
||||
|
||||
var nextNode = next(prev, node, isPre);
|
||||
prev = node;
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
if (prevText) {
|
||||
prevText.data = prevText.data.replace(/ $/, '');
|
||||
if (!prevText.data) {
|
||||
remove(prevText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove(node) removes the given node from the DOM and returns the
|
||||
* next node in the sequence.
|
||||
*
|
||||
* @param {Node} node
|
||||
* @return {Node} node
|
||||
*/
|
||||
function remove (node) {
|
||||
var next = node.nextSibling || node.parentNode;
|
||||
|
||||
node.parentNode.removeChild(node);
|
||||
|
||||
return next
|
||||
}
|
||||
|
||||
/**
|
||||
* next(prev, current, isPre) returns the next node in the sequence, given the
|
||||
* current and previous nodes.
|
||||
*
|
||||
* @param {Node} prev
|
||||
* @param {Node} current
|
||||
* @param {Function} isPre
|
||||
* @return {Node}
|
||||
*/
|
||||
function next (prev, current, isPre) {
|
||||
if ((prev && prev.parentNode === current) || isPre(current)) {
|
||||
return current.nextSibling || current.parentNode
|
||||
}
|
||||
|
||||
return current.firstChild || current.nextSibling || current.parentNode
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up window for Node.js
|
||||
*/
|
||||
|
||||
var root = (typeof window !== 'undefined' ? window : {});
|
||||
|
||||
/*
|
||||
* Parsing HTML strings
|
||||
*/
|
||||
|
||||
function canParseHTMLNatively () {
|
||||
var Parser = root.DOMParser;
|
||||
var canParse = false;
|
||||
|
||||
// Adapted from https://gist.github.com/1129031
|
||||
// Firefox/Opera/IE throw errors on unsupported types
|
||||
try {
|
||||
// WebKit returns null on unsupported types
|
||||
if (new Parser().parseFromString('', 'text/html')) {
|
||||
canParse = true;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return canParse
|
||||
}
|
||||
|
||||
function createHTMLParser () {
|
||||
var Parser = function () {};
|
||||
|
||||
{
|
||||
if (shouldUseActiveX()) {
|
||||
Parser.prototype.parseFromString = function (string) {
|
||||
var doc = new window.ActiveXObject('htmlfile');
|
||||
doc.designMode = 'on'; // disable on-page scripts
|
||||
doc.open();
|
||||
doc.write(string);
|
||||
doc.close();
|
||||
return doc
|
||||
};
|
||||
} else {
|
||||
Parser.prototype.parseFromString = function (string) {
|
||||
var doc = document.implementation.createHTMLDocument('');
|
||||
doc.open();
|
||||
doc.write(string);
|
||||
doc.close();
|
||||
return doc
|
||||
};
|
||||
}
|
||||
}
|
||||
return Parser
|
||||
}
|
||||
|
||||
function shouldUseActiveX () {
|
||||
var useActiveX = false;
|
||||
try {
|
||||
document.implementation.createHTMLDocument('').open();
|
||||
} catch (e) {
|
||||
if (window.ActiveXObject) useActiveX = true;
|
||||
}
|
||||
return useActiveX
|
||||
}
|
||||
|
||||
var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
|
||||
|
||||
function RootNode (input) {
|
||||
var root;
|
||||
if (typeof input === 'string') {
|
||||
var doc = htmlParser().parseFromString(
|
||||
// DOM parsers arrange elements in the <head> and <body>.
|
||||
// Wrapping in a custom element ensures elements are reliably arranged in
|
||||
// a single element.
|
||||
'<x-turndown id="turndown-root">' + input + '</x-turndown>',
|
||||
'text/html'
|
||||
);
|
||||
root = doc.getElementById('turndown-root');
|
||||
} else {
|
||||
root = input.cloneNode(true);
|
||||
}
|
||||
collapseWhitespace({
|
||||
element: root,
|
||||
isBlock: isBlock,
|
||||
isVoid: isVoid
|
||||
});
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
var _htmlParser;
|
||||
function htmlParser () {
|
||||
_htmlParser = _htmlParser || new HTMLParser();
|
||||
return _htmlParser
|
||||
}
|
||||
|
||||
function Node (node) {
|
||||
node.isBlock = isBlock(node);
|
||||
node.isCode = node.nodeName.toLowerCase() === 'code' || node.parentNode.isCode;
|
||||
node.isBlank = isBlank(node);
|
||||
node.flankingWhitespace = flankingWhitespace(node);
|
||||
return node
|
||||
}
|
||||
|
||||
function isBlank (node) {
|
||||
return (
|
||||
['A', 'TH', 'TD', 'IFRAME', 'SCRIPT', 'AUDIO', 'VIDEO'].indexOf(node.nodeName) === -1 &&
|
||||
/^\s*$/i.test(node.textContent) &&
|
||||
!isVoid(node) &&
|
||||
!hasVoid(node)
|
||||
)
|
||||
}
|
||||
|
||||
function flankingWhitespace (node) {
|
||||
var leading = '';
|
||||
var trailing = '';
|
||||
|
||||
if (!node.isBlock) {
|
||||
var hasLeading = /^[ \r\n\t]/.test(node.textContent);
|
||||
var hasTrailing = /[ \r\n\t]$/.test(node.textContent);
|
||||
|
||||
if (hasLeading && !isFlankedByWhitespace('left', node)) {
|
||||
leading = ' ';
|
||||
}
|
||||
if (hasTrailing && !isFlankedByWhitespace('right', node)) {
|
||||
trailing = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return { leading: leading, trailing: trailing }
|
||||
}
|
||||
|
||||
function isFlankedByWhitespace (side, node) {
|
||||
var sibling;
|
||||
var regExp;
|
||||
var isFlanked;
|
||||
|
||||
if (side === 'left') {
|
||||
sibling = node.previousSibling;
|
||||
regExp = / $/;
|
||||
} else {
|
||||
sibling = node.nextSibling;
|
||||
regExp = /^ /;
|
||||
}
|
||||
|
||||
if (sibling) {
|
||||
if (sibling.nodeType === 3) {
|
||||
isFlanked = regExp.test(sibling.nodeValue);
|
||||
} else if (sibling.nodeType === 1 && !isBlock(sibling)) {
|
||||
isFlanked = regExp.test(sibling.textContent);
|
||||
}
|
||||
}
|
||||
return isFlanked
|
||||
}
|
||||
|
||||
var reduce = Array.prototype.reduce;
|
||||
var leadingNewLinesRegExp = /^\n*/;
|
||||
var trailingNewLinesRegExp = /\n*$/;
|
||||
var escapes = [
|
||||
[/\\/g, '\\\\'],
|
||||
[/\*/g, '\\*'],
|
||||
[/^-/g, '\\-'],
|
||||
[/^\+ /g, '\\+ '],
|
||||
[/^(=+)/g, '\\$1'],
|
||||
[/^(#{1,6}) /g, '\\$1 '],
|
||||
[/`/g, '\\`'],
|
||||
[/^~~~/g, '\\~~~'],
|
||||
[/\[/g, '\\['],
|
||||
[/\]/g, '\\]'],
|
||||
[/^>/g, '\\>'],
|
||||
[/_/g, '\\_'],
|
||||
[/^(\d+)\. /g, '$1\\. ']
|
||||
];
|
||||
|
||||
function TurndownService (options) {
|
||||
if (!(this instanceof TurndownService)) return new TurndownService(options)
|
||||
|
||||
var defaults = {
|
||||
rules: rules,
|
||||
headingStyle: 'setext',
|
||||
hr: '* * *',
|
||||
bulletListMarker: '*',
|
||||
codeBlockStyle: 'indented',
|
||||
fence: '```',
|
||||
emDelimiter: '_',
|
||||
strongDelimiter: '**',
|
||||
linkStyle: 'inlined',
|
||||
linkReferenceStyle: 'full',
|
||||
br: ' ',
|
||||
blankReplacement: function (content, node) {
|
||||
return node.isBlock ? '\n\n' : ''
|
||||
},
|
||||
keepReplacement: function (content, node) {
|
||||
return node.isBlock ? '\n\n' + node.outerHTML + '\n\n' : node.outerHTML
|
||||
},
|
||||
defaultReplacement: function (content, node) {
|
||||
return node.isBlock ? '\n\n' + content + '\n\n' : content
|
||||
}
|
||||
};
|
||||
this.options = extend({}, defaults, options);
|
||||
this.rules = new Rules(this.options);
|
||||
}
|
||||
|
||||
TurndownService.prototype = {
|
||||
/**
|
||||
* The entry point for converting a string or DOM node to Markdown
|
||||
* @public
|
||||
* @param {String|HTMLElement} input The string or DOM node to convert
|
||||
* @returns A Markdown representation of the input
|
||||
* @type String
|
||||
*/
|
||||
|
||||
turndown: function (input) {
|
||||
if (!canConvert(input)) {
|
||||
throw new TypeError(
|
||||
input + ' is not a string, or an element/document/fragment node.'
|
||||
)
|
||||
}
|
||||
|
||||
if (input === '') return ''
|
||||
|
||||
var output = process.call(this, new RootNode(input));
|
||||
return postProcess.call(this, output)
|
||||
},
|
||||
|
||||
/**
|
||||
* Add one or more plugins
|
||||
* @public
|
||||
* @param {Function|Array} plugin The plugin or array of plugins to add
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
use: function (plugin) {
|
||||
if (Array.isArray(plugin)) {
|
||||
for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
|
||||
} else if (typeof plugin === 'function') {
|
||||
plugin(this);
|
||||
} else {
|
||||
throw new TypeError('plugin must be a Function or an Array of Functions')
|
||||
}
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a rule
|
||||
* @public
|
||||
* @param {String} key The unique key of the rule
|
||||
* @param {Object} rule The rule
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
addRule: function (key, rule) {
|
||||
this.rules.add(key, rule);
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Keep a node (as HTML) that matches the filter
|
||||
* @public
|
||||
* @param {String|Array|Function} filter The unique key of the rule
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
keep: function (filter) {
|
||||
this.rules.keep(filter);
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a node that matches the filter
|
||||
* @public
|
||||
* @param {String|Array|Function} filter The unique key of the rule
|
||||
* @returns The Turndown instance for chaining
|
||||
* @type Object
|
||||
*/
|
||||
|
||||
remove: function (filter) {
|
||||
this.rules.remove(filter);
|
||||
return this
|
||||
},
|
||||
|
||||
/**
|
||||
* Escapes Markdown syntax
|
||||
* @public
|
||||
* @param {String} string The string to escape
|
||||
* @returns A string with Markdown syntax escaped
|
||||
* @type String
|
||||
*/
|
||||
|
||||
escape: function (string) {
|
||||
return escapes.reduce(function (accumulator, escape) {
|
||||
return accumulator.replace(escape[0], escape[1])
|
||||
}, string)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Reduces a DOM node down to its Markdown string equivalent
|
||||
* @private
|
||||
* @param {HTMLElement} parentNode The node to convert
|
||||
* @returns A Markdown representation of the node
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function process (parentNode) {
|
||||
var self = this;
|
||||
return reduce.call(parentNode.childNodes, function (output, node) {
|
||||
node = new Node(node);
|
||||
|
||||
var replacement = '';
|
||||
if (node.nodeType === 3) {
|
||||
replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
|
||||
} else if (node.nodeType === 1) {
|
||||
replacement = replacementForNode.call(self, node);
|
||||
}
|
||||
|
||||
return join(output, replacement)
|
||||
}, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends strings as each rule requires and trims the output
|
||||
* @private
|
||||
* @param {String} output The conversion output
|
||||
* @returns A trimmed version of the ouput
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function postProcess (output) {
|
||||
var self = this;
|
||||
this.rules.forEach(function (rule) {
|
||||
if (typeof rule.append === 'function') {
|
||||
output = join(output, rule.append(self.options));
|
||||
}
|
||||
});
|
||||
|
||||
return output.replace(/^[\t\r\n]+/, '').replace(/[\t\r\n\s]+$/, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an element node to its Markdown equivalent
|
||||
* @private
|
||||
* @param {HTMLElement} node The node to convert
|
||||
* @returns A Markdown representation of the node
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function replacementForNode (node) {
|
||||
var rule = this.rules.forNode(node);
|
||||
var content = process.call(this, node);
|
||||
var whitespace = node.flankingWhitespace;
|
||||
if (whitespace.leading || whitespace.trailing) content = content.trim();
|
||||
return (
|
||||
whitespace.leading +
|
||||
rule.replacement(content, node, this.options) +
|
||||
whitespace.trailing
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the new lines between the current output and the replacement
|
||||
* @private
|
||||
* @param {String} output The current conversion output
|
||||
* @param {String} replacement The string to append to the output
|
||||
* @returns The whitespace to separate the current output and the replacement
|
||||
* @type String
|
||||
*/
|
||||
|
||||
function separatingNewlines (output, replacement) {
|
||||
var newlines = [
|
||||
output.match(trailingNewLinesRegExp)[0],
|
||||
replacement.match(leadingNewLinesRegExp)[0]
|
||||
].sort();
|
||||
var maxNewlines = newlines[newlines.length - 1];
|
||||
return maxNewlines.length < 2 ? maxNewlines : '\n\n'
|
||||
}
|
||||
|
||||
function join (string1, string2) {
|
||||
var separator = separatingNewlines(string1, string2);
|
||||
|
||||
// Remove trailing/leading newlines and replace with separator
|
||||
string1 = string1.replace(trailingNewLinesRegExp, '');
|
||||
string2 = string2.replace(leadingNewLinesRegExp, '');
|
||||
|
||||
return string1 + separator + string2
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether an input can be converted
|
||||
* @private
|
||||
* @param {String|HTMLElement} input Describe this parameter
|
||||
* @returns Describe what it returns
|
||||
* @type String|Object|Array|Boolean|Number
|
||||
*/
|
||||
|
||||
function canConvert (input) {
|
||||
return (
|
||||
input != null && (
|
||||
typeof input === 'string' ||
|
||||
(input.nodeType && (
|
||||
input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return TurndownService;
|
||||
|
||||
}());
|
||||
|
1226
BrowserMark/js/lib/underscore.js
Normal file
34
BrowserMark/js/loading.js
Normal file
@ -0,0 +1,34 @@
|
||||
(function() {
|
||||
var mrdocPopup = {
|
||||
init: function() {
|
||||
var self = this;
|
||||
self.addEvents();
|
||||
},
|
||||
// popup页面事件
|
||||
addEvents: function() {
|
||||
var self = this;
|
||||
// 点击选项按钮,创建选项标签
|
||||
$('#optionbtn').click(function(e) {
|
||||
chrome.extension.sendRequest({
|
||||
name: 'createoptionstab'
|
||||
});
|
||||
return false;
|
||||
});
|
||||
// 点击关闭按钮,关闭popup页面
|
||||
$('#closebtn').click(function(e) {
|
||||
console.log('close12');
|
||||
parent.postMessage({
|
||||
name: 'closefrommaikupopup'
|
||||
}, '*');
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
$(function() {
|
||||
// 初始化popup页面
|
||||
mrdocPopup.init();
|
||||
parent.postMessage({
|
||||
name: 'pageCompleted'
|
||||
}, '*');
|
||||
});
|
||||
})();
|
790
BrowserMark/js/mrdocclipper.js
Normal file
@ -0,0 +1,790 @@
|
||||
(function($) {
|
||||
'use strict';
|
||||
var _rootWin = window;
|
||||
var regBackgroundRepeat = new RegExp('background-repeat: no-repeat no-repeat;', 'ig')
|
||||
window.mrdocClipper = {
|
||||
init: function() {
|
||||
var self = this;
|
||||
$(document).keydown(function(e) {
|
||||
// console.log(e)
|
||||
if (e.ctrlKey && e.shiftKey && e.keyCode == 88 /*x*/ ) {
|
||||
var port = chrome.extension.connect({
|
||||
name: 'createpopup'
|
||||
});
|
||||
port.postMessage();
|
||||
self.createPopup(); //创建popup弹出窗口
|
||||
}
|
||||
});
|
||||
self.addWindowEventListener();
|
||||
},
|
||||
//html转Markdown
|
||||
html2md : function(html){
|
||||
// 实例化一个turndown
|
||||
var turndownService = new TurndownService({
|
||||
headingStyle:'atx', // 标题风格
|
||||
hr:'---', // 水平分割线
|
||||
bulletListMarker:'-', // 列表项
|
||||
codeBlockStyle:'fenced', //代码块样式
|
||||
})
|
||||
var md = turndownService.turndown(html)
|
||||
return md
|
||||
},
|
||||
//图片URL转base64
|
||||
img2base : function(url){
|
||||
//发送请求到background
|
||||
chrome.runtime.sendMessage({
|
||||
name: 'image2base64',
|
||||
data: url
|
||||
});
|
||||
},
|
||||
// 获取选择的内容
|
||||
getSelectedContent: function() {
|
||||
var self = this,
|
||||
commonAncestorContainer = self.getSelectionContainer(),
|
||||
content = '',
|
||||
title = '';
|
||||
if (commonAncestorContainer === null || $(commonAncestorContainer).text() === '') {
|
||||
content = false;
|
||||
} else if (commonAncestorContainer.nodeType === 3) {
|
||||
content = $(commonAncestorContainer).text();
|
||||
title = document.title; //content
|
||||
} else if (commonAncestorContainer.nodeType === 1) {
|
||||
var selectedHTML = self.getSelectedHTML();
|
||||
var tempNode = $('<div>', {
|
||||
html: selectedHTML
|
||||
}).insertAfter($(commonAncestorContainer));
|
||||
self.getHTMLByNode(tempNode);
|
||||
var html = tempNode.html();
|
||||
// console.log(md)
|
||||
title = document.title; //tempNode.text();
|
||||
tempNode.remove();
|
||||
content = html;
|
||||
}
|
||||
|
||||
if (content) {
|
||||
var port = chrome.extension.connect({
|
||||
name: 'getselectedcontent'
|
||||
});
|
||||
port.postMessage({
|
||||
title: title,
|
||||
sourceurl: location.href,
|
||||
content: content
|
||||
});
|
||||
}
|
||||
},
|
||||
// 获取选择容器
|
||||
getSelectionContainer: function() {
|
||||
var container = null;
|
||||
if (window.getSelection) {
|
||||
var selectionRange = window.getSelection();
|
||||
if (selectionRange.rangeCount > 0) {
|
||||
var range = selectionRange.getRangeAt(0);
|
||||
container = range.commonAncestorContainer;
|
||||
}
|
||||
} else {
|
||||
if (document.selection) {
|
||||
var textRange = document.selection.createRange();
|
||||
container = textRange.parentElement();
|
||||
}
|
||||
}
|
||||
return container;
|
||||
},
|
||||
|
||||
// 获取选择的HTML
|
||||
getSelectedHTML: function() {
|
||||
var userSelection;
|
||||
if (window.getSelection) {
|
||||
//W3C Ranges
|
||||
userSelection = window.getSelection();
|
||||
//Get the range:
|
||||
if (userSelection.getRangeAt) {
|
||||
var range = userSelection.getRangeAt(0);
|
||||
} else {
|
||||
var range = document.createRange();
|
||||
range.setStart(userSelection.anchorNode, userSelection.anchorOffset);
|
||||
range.setEnd(userSelection.focusNode, userSelection.focusOffset);
|
||||
}
|
||||
//And the HTML:
|
||||
var clonedSelection = range.cloneContents();
|
||||
var div = document.createElement('div');
|
||||
div.appendChild(clonedSelection);
|
||||
return div.innerHTML;
|
||||
} else if (document.selection) {
|
||||
//Explorer selection, return the HTML
|
||||
userSelection = document.selection.createRange();
|
||||
return userSelection.htmlText;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
// 获取页面内容
|
||||
getPageContent: function() {
|
||||
var self = this,
|
||||
port = chrome.extension.connect({
|
||||
name: 'getpagecontent'
|
||||
});
|
||||
var h1 = $('h1').eq(0);
|
||||
port.postMessage({
|
||||
title: document.title,
|
||||
sourceurl: location.href,
|
||||
content: self.getHTMLByNode($(document.body))
|
||||
});
|
||||
},
|
||||
//创建剪藏
|
||||
createMrClipWrap: function(zIndex, height) {
|
||||
if ($(document.body).is('frameset')) {
|
||||
return null;
|
||||
}
|
||||
var self = this;
|
||||
if (!self.closePopup) {
|
||||
self.closePopup = function() {
|
||||
$(document).unbind('keydown.mrdocclipperpopup');
|
||||
self.removeInspector();
|
||||
self.isCreatedPopup = false;
|
||||
self.popupInstance.fadeOut(function(e) {
|
||||
$(this).remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
var el = $('<div mrclip="true" style="position:fixed;right:8px;top:8px;width:450px;height:' + height + 'px;\
|
||||
background-color:rgba(0,0,0,.5);z-index:;border-radius:1px;\
|
||||
box-shadow:rgba(51, 51, 51, 0.498039) 0px 0px 8px 0px;overflow:hidden;"></div>').css('z-index', zIndex).hide().appendTo(document.body).fadeIn();
|
||||
var iframe = $('<iframe frameborder="0" style="width:100%;height:100%;max-height:450px"></iframe>').appendTo(el),
|
||||
iframeWin = iframe[0].contentWindow,
|
||||
iframeDoc = iframe[0].contentDocument || iframeWin.document;
|
||||
|
||||
return {
|
||||
wrap: el,
|
||||
iframe: iframe
|
||||
}
|
||||
},
|
||||
//创建打开加载页面
|
||||
createLoadingEl: function(zIndex) {
|
||||
var obj = this.createMrClipWrap(zIndex, 150);
|
||||
if (obj == null) return null;
|
||||
obj.iframe[0].src = chrome.extension.getURL('loading.html');
|
||||
return obj.wrap;
|
||||
},
|
||||
//创建打开popup页面
|
||||
createClipEl: function(zIndex) {
|
||||
var self = this;
|
||||
var obj = this.createMrClipWrap(zIndex, 450);
|
||||
if (obj == null) return null;
|
||||
obj.iframe[0].src = chrome.extension.getURL('popup.html');
|
||||
self.initDivHeight = parseInt(obj.wrap.css('height'));
|
||||
var judgeHeight = function(h) {
|
||||
if (h < 304) return 304;
|
||||
if (h > 644) return 644;
|
||||
return h;
|
||||
}
|
||||
self.changeHeight = function(changeStep) {
|
||||
obj.wrap.css('height', judgeHeight(self.initDivHeight + changeStep));
|
||||
}
|
||||
|
||||
$(document).bind('keydown.mrdocclipperpopup', function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
self.closePopup();
|
||||
}
|
||||
});
|
||||
return obj.wrap;
|
||||
},
|
||||
//创建popup
|
||||
createPopup: function() {
|
||||
var self = this;
|
||||
if (self.isCreatedPopup) return;
|
||||
self.popupZIndex = 20120726;
|
||||
self.isCreatedPopup = true;
|
||||
var errorMessage = "page isn't be support",
|
||||
loadingEl, ClipEl;
|
||||
|
||||
function showPage() {
|
||||
if (self.isLoadComplated == true) {
|
||||
if (ClipEl) return true;
|
||||
if (loadingEl) loadingEl.remove();
|
||||
self.popupInstance = ClipEl = self.createClipEl(self.popupZIndex);
|
||||
if (ClipEl == null) throw Error(errorMessage);
|
||||
return true;
|
||||
} else {
|
||||
if (loadingEl) return false;
|
||||
self.popupInstance = loadingEl = self.createLoadingEl(self.popupZIndex);
|
||||
if (loadingEl == null) throw Error(errorMessage);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
showPage();
|
||||
var handler = setInterval(function() {
|
||||
if (showPage()) {
|
||||
clearInterval(handler);
|
||||
}
|
||||
}, 500);
|
||||
} catch (e) {
|
||||
self.isCreatedPopup = false;
|
||||
if (e.message == errorMessage) {
|
||||
self.tipsReadyError();
|
||||
}
|
||||
}
|
||||
},
|
||||
//parent.postMessage窗口事件监听
|
||||
addWindowEventListener: function() {
|
||||
var self = this;
|
||||
window.addEventListener('message', function(e) {
|
||||
switch (e.data.name) {
|
||||
case 'createinspectorfrommrdocpopup':
|
||||
self.createInspector(e.data.autoExtractContent);
|
||||
break;
|
||||
case 'changeheightfrommrdocpopup':
|
||||
self.changeHeight(e.data.param);
|
||||
break;
|
||||
case 'stopchangeheightfrommrdocpopup':
|
||||
self.initDivHeight = parseInt(self.popupInstance.css('height'));
|
||||
break;
|
||||
case 'closefrommrdocpopup':
|
||||
self.closePopup();
|
||||
break;
|
||||
case 'resetfrommrdocpopup':
|
||||
self.clearMarks();
|
||||
break;
|
||||
case 'savenotefrommrdocpopup':
|
||||
self.saveNote(e.data.notedata);
|
||||
break;
|
||||
case 'showinspectorfrommrdocpopup':
|
||||
self.showInspector();
|
||||
break;
|
||||
case 'hideinspectorfrommrdocpopup':
|
||||
self.hideInspector();
|
||||
break;
|
||||
case 'hidemaskfrommrdocpopup':
|
||||
self.mask && self.mask.hide();
|
||||
break;
|
||||
case 'pageCompleted':
|
||||
self.isLoadComplated = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
//创建注入器
|
||||
createInspector: function(autoExtractContent) {
|
||||
var self = this,
|
||||
body = $(document.body);
|
||||
self.cover = $('<div mrclip="true" cover></div>').css({
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
opacity: 0,
|
||||
'z-index': self.popupZIndex - 1
|
||||
});
|
||||
self.mask = $('<div mrclip="true" mask></div>').css({
|
||||
'border-radius': 5,
|
||||
border: '3px dashed black',
|
||||
position: 'absolute',
|
||||
top: -9999,
|
||||
left: -9999,
|
||||
width: 0,
|
||||
height: 0,
|
||||
'z-index': self.popupZIndex - 1,
|
||||
background: 'transparent'
|
||||
});
|
||||
// var backgroundImageSrc = chrome.extension.getURL('css/images/sprite.png'),
|
||||
//'chrome-extension://__MSG_@@extension_id__/sprites.png'
|
||||
//遮罩半透明
|
||||
var markInner = $('<div mrclip="true" markInner></div>').css({
|
||||
background: '#ccffcc',
|
||||
height: '100%',
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
opacity: 0.35,
|
||||
width: '100%'
|
||||
})
|
||||
// //扩大选区按钮
|
||||
// markExpandor = $('<div mrclip="true" markExpandor></div>').css({
|
||||
// background: 'url(' + backgroundImageSrc + ') -120px -66px no-repeat',
|
||||
// height: 20,
|
||||
// width: 20,
|
||||
// cursor: 'pointer',
|
||||
// position: 'absolute',
|
||||
// top: 1,
|
||||
// left: 1,
|
||||
// 'z-index': self.popupZIndex - 1
|
||||
// }).attr('title', chrome.i18n.getMessage('MarkExpandorTip')),
|
||||
// //关闭按钮
|
||||
// markClose = $('<span mrclip="true" markClose></span').css({
|
||||
// background: 'url(' + backgroundImageSrc + ') -120px -44px no-repeat',
|
||||
// height: 20,
|
||||
// width: 20,
|
||||
// cursor: 'pointer',
|
||||
// position: 'absolute',
|
||||
// top: 1,
|
||||
// left: 23,
|
||||
// 'z-index': self.popupZIndex - 1
|
||||
// }).attr('title', chrome.i18n.getMessage('CancelTip'));
|
||||
//最外层的框
|
||||
self.mark = $('<div mrclip="true" mark></div>').css({
|
||||
'border-radius': 3,
|
||||
border: '3px dashed black',
|
||||
position: 'absolute',
|
||||
top: -9999,
|
||||
left: -9999,
|
||||
'z-index': self.popupZIndex - 1,
|
||||
background: 'transparent'
|
||||
}).append(markInner)
|
||||
//有些网页会把div强制为position:relative 导致选择区显示出错
|
||||
//手动将position强制为默认值
|
||||
//测试 http://www.smashingmagazine.com/2013/02/28/desktop-wallpaper-calendar-march-2013/
|
||||
self.markContainer = $('<div mrclip="true" style="position:static" markContainer></div>').appendTo(body).append(self.cover).append(self.mask);
|
||||
self.markedElements = {}; //save all marked page element
|
||||
self.marks = {}; //save all marks
|
||||
self.markCount = 0;
|
||||
self.body = body;
|
||||
body.bind('mousemove.mrdocclippermark', function(e) {
|
||||
self.mouseMoveMarkHandler(e);
|
||||
}).bind('click.mrdocclippermark', function(e) {
|
||||
self.clickMarkHandler(e);
|
||||
}).bind('mouseleave.mrdocclippermark', function(e) {
|
||||
self.mask.hide();
|
||||
});
|
||||
var title = document.title;
|
||||
//如果开启了自动提取正文
|
||||
if (autoExtractContent) {
|
||||
// 提取内容
|
||||
var extract = self.extractContent(document);
|
||||
if (extract.isSuccess) { //提取成功
|
||||
var extractedContent = extract.content.asNode();
|
||||
if (extractedContent.nodeType == 3) {
|
||||
extractedContent = extractedContent.parentNode;
|
||||
}
|
||||
setTimeout(function() {
|
||||
var title = document.title; //&& document.title.split('-')[0];
|
||||
self.addMark($(extractedContent), self.mark.clone(), title.trim());
|
||||
}, 0);
|
||||
} else { // 提取失败,选择整个网页
|
||||
var extractedContent = document.body;
|
||||
setTimeout(function() {
|
||||
var title = document.title;
|
||||
self.addMark($(extractedContent), self.mark.clone(), title.trim());
|
||||
}, 0);
|
||||
}
|
||||
}else{ //没有开启自动提取正文
|
||||
var extractedContent = document.body;
|
||||
setTimeout(function() {
|
||||
var title = document.title;
|
||||
self.addMark('', self.mark.clone(), title.trim());
|
||||
}, 0);
|
||||
}
|
||||
},
|
||||
//隐藏注入器
|
||||
hideInspector: function() {
|
||||
var self = this;
|
||||
if (!self.markContainer) return;
|
||||
self.markContainer.hide();
|
||||
self.body.unbind('mousemove.mrdocclippermark').unbind('click.mrdocclippermark');
|
||||
},
|
||||
//显示注入器
|
||||
showInspector: function() {
|
||||
var self = this;
|
||||
if (!self.markContainer) return;
|
||||
self.markContainer.show();
|
||||
self.body.bind('mousemove.mrdocclippermark', function(e) {
|
||||
self.mouseMoveMarkHandler(e);
|
||||
}).bind('click.mrdocclippermark', function(e) {
|
||||
self.clickMarkHandler(e);
|
||||
})
|
||||
},
|
||||
//移除注入器
|
||||
removeInspector: function() {
|
||||
var self = this;
|
||||
if (!self.markContainer) return;
|
||||
self.markContainer.remove();
|
||||
self.markedElements = {};
|
||||
self.marks = {};
|
||||
self.markCount = 0;
|
||||
self.body.unbind('mousemove.mrdocclippermark').unbind('click.mrdocclippermark');
|
||||
},
|
||||
// 鼠标移动标记的处理
|
||||
mouseMoveMarkHandler: function(e) {
|
||||
var self = this;
|
||||
self.cover.show();
|
||||
self.mask.show();
|
||||
var target = self.elementFromPoint(e),
|
||||
isMark = target.attr('mrclip'),
|
||||
isIgnore = false;
|
||||
if (target.is('body, html') || isMark) {
|
||||
isIgnore = true;
|
||||
}
|
||||
//mouse in mark or remove-mark
|
||||
//hide cover so that remove-mark could be clicked
|
||||
if (!isMark && !isIgnore) {
|
||||
self.attachBox(target, self.mask);
|
||||
} else {
|
||||
self.cover.hide();
|
||||
self.mask.hide();
|
||||
}
|
||||
},
|
||||
// 点击标记框的处理
|
||||
clickMarkHandler: function(e) {
|
||||
console.log("点击了标记框")
|
||||
var self = this,
|
||||
target = self.elementFromPoint(e),
|
||||
isIgnore = false;
|
||||
if (target.is('iframe, frame')) {
|
||||
console.log('无法获取iframe及frame里面的内容');
|
||||
return false;
|
||||
}
|
||||
if (target.is('body, html')) {
|
||||
isIgnore = true;
|
||||
}
|
||||
self.removeMarkInElement(target);
|
||||
if (!isIgnore) {
|
||||
self.addMark(target, self.mark.clone());
|
||||
return false;
|
||||
}
|
||||
e.stopPropagation();
|
||||
},
|
||||
//添加标记到内容框
|
||||
addMark: function(target, mark, title) {
|
||||
var self = this,
|
||||
uid = 'mkmark_' + self.markCount;
|
||||
self.markContainer.append(mark);
|
||||
if(target == ''){ // 首次点击图标时,未选择页面元素,将其设为空字符串,以便自动设置标题
|
||||
self.markCount++;
|
||||
var html = ' ';
|
||||
var md = ' ';
|
||||
}else{
|
||||
self.attachBox(target, mark);
|
||||
self.markCount++;
|
||||
var html = self.getHTMLByNode(target);
|
||||
|
||||
var md = self.html2md(html)
|
||||
}
|
||||
self.sendContentToPopup(uid, md, true, title); // 写入Markdown
|
||||
//self.sendContentToPopup(uid, html, true, title); // 写入HTML
|
||||
self.markedElements[uid] = target;
|
||||
self.marks[uid] = mark;
|
||||
mark.data('uid', uid).click(function(e) {
|
||||
self.delMark(mark);
|
||||
return false;
|
||||
});
|
||||
$(mark.children()[1]).click(function(e) {
|
||||
self.parentMark(mark);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
//删除标记
|
||||
delMark: function(mark) {
|
||||
var self = this,
|
||||
uid = mark.data('uid');
|
||||
self.sendContentToPopup(uid);
|
||||
mark.remove();
|
||||
delete self.markedElements[uid];
|
||||
},
|
||||
//清除标记
|
||||
clearMarks: function() {
|
||||
var self = this;
|
||||
self.markContainer.html('').append(self.cover).append(self.mask);
|
||||
self.markedElements = {};
|
||||
self.marks = {};
|
||||
self.markCount = 0;
|
||||
},
|
||||
// 父级标记
|
||||
parentMark: function(mark) {
|
||||
var self = this,
|
||||
uid = mark.data('uid'),
|
||||
parent = self.markedElements[uid].parent();
|
||||
if (parent.is('html')) return;
|
||||
self.removeMarkInElement(parent);
|
||||
self.addMark(parent, self.mark.clone());
|
||||
},
|
||||
// 从元素中移除标记
|
||||
removeMarkInElement: function(el) {
|
||||
var self = this,
|
||||
markedPageElementInParent = {};
|
||||
for (var uid in self.markedElements) {
|
||||
if (el.find(self.markedElements[uid]).length > 0) {
|
||||
markedPageElementInParent[uid] = true;
|
||||
}
|
||||
}
|
||||
for (var uid in self.marks) {
|
||||
if (markedPageElementInParent[uid]) {
|
||||
self.delMark(self.marks[uid]);
|
||||
}
|
||||
}
|
||||
},
|
||||
//获取鼠标点击位置的元素
|
||||
elementFromPoint: function(e) {
|
||||
var self = this;
|
||||
self.cover.hide();
|
||||
self.mask.hide();
|
||||
var pos = {
|
||||
top: e.pageY - $(window).scrollTop(),
|
||||
left: e.pageX
|
||||
},
|
||||
target = $(document.elementFromPoint(pos.left, pos.top));
|
||||
self.cover.show();
|
||||
self.mask.show();
|
||||
return target;
|
||||
},
|
||||
//生成一个点击元素大小的附加框
|
||||
attachBox: function(target, el) {
|
||||
var self = this,
|
||||
body = self.body,
|
||||
size = {
|
||||
height: target.outerHeight(),
|
||||
width: target.outerWidth()
|
||||
},
|
||||
pos = {
|
||||
left: target.offset().left,
|
||||
top: target.offset().top
|
||||
}
|
||||
//box on the page edge
|
||||
//ajust the pos and size order to show the whole box
|
||||
var bodyOuterWidth = body.outerWidth();
|
||||
if (pos.left == 0) {
|
||||
if (size.width >= bodyOuterWidth) {
|
||||
size.width = bodyOuterWidth - 6;
|
||||
}
|
||||
} else if (pos.left + size.width >= bodyOuterWidth) {
|
||||
size.width = bodyOuterWidth - pos.left - 6;
|
||||
} else {
|
||||
pos.left -= 3;
|
||||
}
|
||||
if (pos.top == 0) {
|
||||
size.height -= 3;
|
||||
} else {
|
||||
pos.top -= 3;
|
||||
}
|
||||
el.css({
|
||||
left: pos.left,
|
||||
top: pos.top,
|
||||
height: size.height,
|
||||
width: size.width
|
||||
});
|
||||
},
|
||||
// 从节点中获取HTML
|
||||
getHTMLByNode: function(node) {
|
||||
var self = this,
|
||||
filterTagsObj = self.filterTagsObj,
|
||||
nodeTagName = node[0].tagName.toLowerCase();
|
||||
if (filterTagsObj[nodeTagName]) { //如果标签名在过滤列表中,返回空字符串
|
||||
return '';
|
||||
}
|
||||
var allEles = node[0].querySelectorAll('*'),
|
||||
allElesLength = allEles.length,
|
||||
nodeCSSStyleDeclaration = getComputedStyle(node[0]);
|
||||
if (allElesLength == 0) {
|
||||
// 没有子节点
|
||||
if (!/^(img|a)$/.test(nodeTagName) && node[0].innerHTML == 0 && nodeCSSStyleDeclaration['background-image'] == 'none') {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
var cloneNode = node.clone(),
|
||||
allElesCloned = cloneNode[0].querySelectorAll('*'),
|
||||
el, cloneEl, color, cssStyleDeclaration, styleObj = {},
|
||||
cssValue, saveStyles = self.saveStyles;
|
||||
for (var j = allElesLength - 1, tagName; j >= 0; j--) {
|
||||
cloneEl = allElesCloned[j];
|
||||
tagName = cloneEl.tagName.toLowerCase();
|
||||
if (filterTagsObj[tagName] || cloneEl.getAttribute('mrclip')) {
|
||||
$(cloneEl).remove();
|
||||
continue;
|
||||
}
|
||||
if (tagName == 'br') {
|
||||
continue;
|
||||
}
|
||||
el = allEles[j];
|
||||
cssStyleDeclaration = getComputedStyle(el);
|
||||
cloneEl = $(cloneEl);
|
||||
color = cssStyleDeclaration.color;
|
||||
styleObj = {};
|
||||
// 图片转base64,然后上传到MrDoc
|
||||
// if (tagName == 'img') {
|
||||
// console.log("存在图片,解析上传……",)
|
||||
// self.img2base(cloneEl[0].src) // 图片转base64
|
||||
// chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
|
||||
// if(request.name == 'img2base64url'){
|
||||
// console.log("获取上传图片URL:",request.data)
|
||||
// cloneEl[0].src = request.data
|
||||
// };
|
||||
// });
|
||||
|
||||
// continue;
|
||||
// }
|
||||
for (var cssProperty in saveStyles) {
|
||||
cssValue = cssStyleDeclaration[cssProperty];
|
||||
if (cssValue == saveStyles[cssProperty]) continue;
|
||||
if (cssProperty == 'color') {
|
||||
styleObj[cssProperty] = (color == 'rgb(255,255,255)' ? '#000' : color);
|
||||
continue;
|
||||
}
|
||||
styleObj[cssProperty] = cssValue;
|
||||
}
|
||||
if (tagName == 'a') {
|
||||
cloneEl.attr('href', el.href);
|
||||
} else if (/^(ul|ol|li)$/.test(tagName)) {
|
||||
styleObj['list-style'] = cssStyleDeclaration['list-style'];
|
||||
}
|
||||
cloneEl.css(styleObj);
|
||||
self.removeAttrs(cloneEl);
|
||||
}
|
||||
if (nodeTagName == 'body') {
|
||||
return cloneNode[0].innerHTML.replace(regBackgroundRepeat, 'background-repeat: no-repeat;');
|
||||
} else {
|
||||
color = nodeCSSStyleDeclaration.color;
|
||||
styleObj = {};
|
||||
for (var cssProperty in saveStyles) {
|
||||
cssValue = nodeCSSStyleDeclaration[cssProperty];
|
||||
if (cssValue == saveStyles[cssProperty]) continue;
|
||||
if (/^(margin|float)$/.test(cssProperty)) continue;
|
||||
if (cssProperty == 'color') {
|
||||
styleObj[cssProperty] = (color == 'rgb(255,255,255)' ? '#000' : color);
|
||||
continue;
|
||||
}
|
||||
styleObj[cssProperty] = cssValue;
|
||||
}
|
||||
cloneNode.css(styleObj);
|
||||
self.removeAttrs(cloneNode);
|
||||
if (/^(img)$/.test(nodeTagName)) {
|
||||
var imgSrc = $(cloneNode[0]).attr('src');
|
||||
if (!/^http(s)?:\/\//.test(imgSrc)) {
|
||||
$(cloneNode[0]).attr('src', window.location.protocol + '//' + window.location.host + '/' + imgSrc);
|
||||
}
|
||||
}
|
||||
return cloneNode[0].outerHTML.replace(regBackgroundRepeat, 'background-repeat: no-repeat;');
|
||||
}
|
||||
},
|
||||
//过滤的标签对象
|
||||
filterTagsObj: {
|
||||
style: 1,
|
||||
script: 1,
|
||||
link: 1,
|
||||
iframe: 1,
|
||||
frame: 1,
|
||||
frameset: 1,
|
||||
noscript: 1,
|
||||
head: 1,
|
||||
html: 1,
|
||||
applet: 1,
|
||||
base: 1,
|
||||
basefont: 1,
|
||||
bgsound: 1,
|
||||
blink: 1,
|
||||
ilayer: 1,
|
||||
layer: 1,
|
||||
meta: 1,
|
||||
object: 1,
|
||||
embed: 1,
|
||||
input: 1,
|
||||
textarea: 1,
|
||||
button: 1,
|
||||
select: 1,
|
||||
canvas: 1,
|
||||
map: 1
|
||||
},
|
||||
//保存的样式
|
||||
saveStyles: {
|
||||
'background': 'rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box',
|
||||
'border': '0px none rgb(0, 0, 0)',
|
||||
'bottom': 'auto',
|
||||
'box-shadow': 'none',
|
||||
'clear': 'none',
|
||||
'color': 'rgb(0, 0, 0)',
|
||||
'cursor': 'auto',
|
||||
'display': '',
|
||||
//consider inline tag or block tag, this value must have
|
||||
'float': 'none',
|
||||
'font': '',
|
||||
//this value must have, since it affect the appearance very much and style inherit is very complex
|
||||
'height': 'auto',
|
||||
'left': 'auto',
|
||||
'letter-spacing': 'normal',
|
||||
'line-height': 'normal',
|
||||
'margin': '',
|
||||
'max-height': 'none',
|
||||
'max-width': 'none',
|
||||
'min-height': '0px',
|
||||
'min-width': '0px',
|
||||
'opacity': '1',
|
||||
'outline': 'rgb(0, 0, 0) none 0px',
|
||||
'overflow': 'visible',
|
||||
'padding': '',
|
||||
'position': 'static',
|
||||
'right': 'auto',
|
||||
'table-layout': 'auto',
|
||||
'text-align': 'start',
|
||||
'text-decoration': '',
|
||||
'text-indent': '0px',
|
||||
'text-shadow': 'none',
|
||||
'text-overflow': 'clip',
|
||||
'text-transform': 'none',
|
||||
'top': 'auto',
|
||||
'vertical-align': 'baseline',
|
||||
'visibility': 'visible',
|
||||
'white-space': 'normal',
|
||||
'width': 'auto',
|
||||
'word-break': 'normal',
|
||||
'word-spacing': '0px',
|
||||
'word-wrap': 'normal',
|
||||
'z-index': 'auto',
|
||||
'zoom': '1'
|
||||
},
|
||||
//移除属性
|
||||
removeAttrs: function(node) {
|
||||
var removeAttrs = ['id', 'class', 'height', 'width'];
|
||||
for (var i = 0, l = removeAttrs.length; i < l; i++) {
|
||||
node.removeAttr(removeAttrs[i]);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
//从节点中提取内容
|
||||
extractContent: function(doc) {
|
||||
var ex = new ExtractContentJS.LayeredExtractor();
|
||||
ex.addHandler(ex.factory.getHandler('Heuristics'));
|
||||
var res = ex.extract(doc);
|
||||
return res;
|
||||
},
|
||||
//发送内容到Popup中
|
||||
sendContentToPopup: function(uid, content, add, title) {
|
||||
//不能直接发送数据到popup页面,所以先连接到background页面
|
||||
if (add && !content) return; //添加空节点, return;
|
||||
var port = chrome.extension.connect({
|
||||
name: 'actionfrompopupinspecotr'
|
||||
});
|
||||
port.postMessage({
|
||||
uid: uid,
|
||||
content: content,
|
||||
add: add,
|
||||
title: title
|
||||
});
|
||||
},
|
||||
|
||||
//保存文档
|
||||
saveNote: function(notedata) {
|
||||
var self = this,
|
||||
//发送消息到background.js
|
||||
port = chrome.extension.connect({
|
||||
name: 'savenotefrompopup'
|
||||
});
|
||||
// 关闭 popup
|
||||
self.closePopup();
|
||||
notedata.sourceurl = location.href;
|
||||
port.postMessage(notedata);
|
||||
},
|
||||
|
||||
//提示读取错误
|
||||
tipsReadyError: function() {
|
||||
var port = chrome.extension.connect({
|
||||
name: 'mrdocclipperisnotready'
|
||||
});
|
||||
var data = {
|
||||
'key': 'notClipPageInfo'
|
||||
}
|
||||
port.postMessage(data);
|
||||
}
|
||||
}
|
||||
mrdocClipper.init();
|
||||
$(function() {
|
||||
mrdocClipper.isLoadComplated = true;
|
||||
});
|
||||
})(jQuery);
|
69
BrowserMark/js/options.js
Normal file
@ -0,0 +1,69 @@
|
||||
(function($){
|
||||
'use strict';
|
||||
window.mrdocClipperSettings = {
|
||||
init: function(){
|
||||
var self = this,
|
||||
//从chrome.storage.local里面读取值
|
||||
mrdocClipperOptions = chrome.storage.local
|
||||
//mrdoc地址
|
||||
mrdocClipperOptions.get(['serverUrl'],function(r){
|
||||
console.log(r)
|
||||
$("input[name='mrdoc_server_url']").val(r['serverUrl']);
|
||||
});
|
||||
//账户密钥
|
||||
mrdocClipperOptions.get(['accountKey'],function(r){
|
||||
$("input[name='mrdoc_account_key']").val(r['accountKey']);
|
||||
});
|
||||
//转存图片
|
||||
// mrdocClipperOptions.get(['retrieveImg'],function(r){
|
||||
// if(r['retrieveImg'] == true){
|
||||
// $("#retrieveimage").prop('checked',true);
|
||||
// }
|
||||
// });
|
||||
}
|
||||
}
|
||||
$(function(){
|
||||
mrdocClipperSettings.init();
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
|
||||
//点击保存按钮
|
||||
$('#save-btn').click(function () {
|
||||
saveSettingOptions();
|
||||
});
|
||||
|
||||
//保存设置选项
|
||||
saveSettingOptions = function(){
|
||||
mrdocClipperOptions = chrome.storage.local
|
||||
mrdocClipperOptions.set({'serverUrl':$("input[name='mrdoc_server_url']").val()})
|
||||
mrdocClipperOptions.set({'accountKey':$("input[name='mrdoc_account_key']").val()})
|
||||
// mrdocClipperOptions.set({'retrieveImg':$("#retrieveimage").prop('checked')})
|
||||
layer.msg("保存成功")
|
||||
};
|
||||
|
||||
//点击验证按钮
|
||||
$("#checkKey").click(function(){
|
||||
var host = $('#mrdoc_url').val()
|
||||
var token = $('#mrdoc_token').val()
|
||||
checkAccountKey(host,token);
|
||||
})
|
||||
|
||||
//验证账户密钥
|
||||
checkAccountKey = function(server_url,account_key){
|
||||
layer.load(1);
|
||||
$('button.layui-btn').attr("disabled",true);
|
||||
$('button.layui-btn').addClass('layui-btn-disabled');
|
||||
$.get(server_url+'/api/get_projects/?token='+account_key,function(r){
|
||||
if(r.status){
|
||||
layer.msg("验证成功")
|
||||
}else{
|
||||
layer.msg("验证失败")
|
||||
}
|
||||
}).fail(function(){
|
||||
layer.msg('连接MrDoc出错')
|
||||
})
|
||||
layer.closeAll('loading');
|
||||
$('button.layui-btn').attr("disabled",false);
|
||||
$('button.layui-btn').removeClass('layui-btn-disabled');
|
||||
}
|
236
BrowserMark/js/popup.js
Normal file
@ -0,0 +1,236 @@
|
||||
self.title = $('#titleinp'); //popup页面的标题栏
|
||||
layer = layui.layer;
|
||||
form = layui.form;
|
||||
|
||||
//点击关闭按钮
|
||||
$('#closebtn').click(function(e) {
|
||||
parent.postMessage({
|
||||
name: 'closefrommrdocpopup'
|
||||
}, '*');
|
||||
return false;
|
||||
});
|
||||
|
||||
//点击重置按钮
|
||||
$('#resetbtn').click(function(e) {
|
||||
self.editor.setValue('')
|
||||
parent.postMessage({
|
||||
name: 'resetfrommrdocpopup'
|
||||
}, '*');
|
||||
});
|
||||
|
||||
// 点击保存按钮
|
||||
$("#savebtn").click(function(e){
|
||||
layer.load(1)
|
||||
var item = {
|
||||
title : self.title.val(),//标题
|
||||
pid : $("#projects").val(), // 文集ID
|
||||
doc : self.editor.getValue()
|
||||
}
|
||||
// console.log(item)
|
||||
if(item.pid == ''){ // 如果文集为空,消息提示
|
||||
layer.closeAll('loading');
|
||||
layer.msg("必须选择文集")
|
||||
return
|
||||
}
|
||||
//发送请求到background
|
||||
chrome.runtime.sendMessage({
|
||||
name: 'savedocfrompopup',
|
||||
data: item
|
||||
});
|
||||
});
|
||||
|
||||
//粘贴上传图片
|
||||
$("#notecontentwrap").on('paste',function(ev){
|
||||
var data = ev.clipboardData;
|
||||
var items = (event.clipboardData || event.originalEvent.clipboardData).items;
|
||||
for (var index in items) {
|
||||
var item = items[index];
|
||||
if (item.kind === 'file') {
|
||||
layer.load(1);
|
||||
var blob = item.getAsFile();
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
var base64 = event.target.result;
|
||||
//发送请求到background
|
||||
chrome.runtime.sendMessage({
|
||||
name: 'pasteimage',
|
||||
data: base64
|
||||
});
|
||||
}; // data url!
|
||||
var url = reader.readAsDataURL(blob);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//鼠标选择 - 2020-03-15自定义
|
||||
// $("#mouse-select").click(function(){
|
||||
// var t = $("#mouse-select").prop('checked');
|
||||
// console.log(t)
|
||||
// if(t){
|
||||
// parent.postMessage({
|
||||
// name: 'showinspectorfrommrdocpopup'
|
||||
// }, '*');
|
||||
// }else{
|
||||
// parent.postMessage({
|
||||
// name: 'hideinspectorfrommrdocpopup'
|
||||
// }, '*');
|
||||
// }
|
||||
// });
|
||||
|
||||
// 监听鼠标选择开关
|
||||
form.on('switch()', function(data){
|
||||
// console.log(data.elem); //得到checkbox原始DOM对象
|
||||
// console.log(data.elem.checked); //开关是否开启,true或者false
|
||||
if(data.elem.checked){
|
||||
parent.postMessage({
|
||||
name: 'showinspectorfrommrdocpopup'
|
||||
}, '*');
|
||||
}else{
|
||||
parent.postMessage({
|
||||
name: 'hideinspectorfrommrdocpopup'
|
||||
}, '*');
|
||||
}
|
||||
// console.log(data.value); //开关value值,也可以通过data.elem.value得到
|
||||
// console.log(data.othis); //得到美化后的DOM对象
|
||||
});
|
||||
|
||||
//初始化Markdown编辑器
|
||||
iniMdEditor = function(){
|
||||
var self = this;
|
||||
// codemirror 编辑器
|
||||
self.editor = CodeMirror.fromTextArea($('#editor').get(0), {
|
||||
mode: 'markdown',
|
||||
lineNumbers: true,
|
||||
autoCloseBrackets: true,
|
||||
matchBrackets: true,
|
||||
showCursorWhenSelecting: true,
|
||||
lineWrapping: true, // 长句子折行
|
||||
// theme: "material",
|
||||
keyMap: 'sublime',
|
||||
extraKeys: {"Enter": "newlineAndIndentContinueMarkdownList"}
|
||||
});
|
||||
};
|
||||
iniMdEditor();
|
||||
|
||||
// 获取文集列表
|
||||
getProjects = function(){
|
||||
var opt = chrome.storage.local
|
||||
// 获取mrdoc地址
|
||||
opt.get(['serverUrl'],function(r){
|
||||
self.mrdocUrl = r['serverUrl'];
|
||||
// 获取账户token
|
||||
opt.get(['accountKey'],function(r){
|
||||
self.mrdocToken = r['accountKey'];
|
||||
// 如果存在mrdoc服务地址和账户token,获取文集
|
||||
if(self.mrdocUrl != undefined && self.mrdocToken != undefined){
|
||||
layer.load(1);
|
||||
item = {'url':self.mrdocUrl,'token':self.mrdocToken}
|
||||
chrome.runtime.sendMessage({
|
||||
name: 'selectprojects',
|
||||
data:item
|
||||
});
|
||||
}else{
|
||||
//打开选项页
|
||||
chrome.tabs.create({url: chrome.runtime.getURL('options.html')});
|
||||
}
|
||||
})
|
||||
})
|
||||
};
|
||||
getProjects();
|
||||
|
||||
//创建注入器
|
||||
createInspector = function(autoExtractContent) {
|
||||
// 发送消息到mrdocclipper.js
|
||||
parent.postMessage({
|
||||
name: 'createinspectorfrommrdocpopup',
|
||||
autoExtractContent: autoExtractContent
|
||||
}, '*');
|
||||
};
|
||||
createInspector(false);
|
||||
|
||||
// 默认关闭鼠标选择标记框
|
||||
hideInspector = function(){
|
||||
parent.postMessage({
|
||||
name: 'hideinspectorfrommrdocpopup'
|
||||
}, '*');
|
||||
};
|
||||
hideInspector();
|
||||
|
||||
|
||||
// 处理background发送来的页面剪藏内容,将其添加到文本编辑器中
|
||||
actionfrompopupinspecotrHandler = function(data) {
|
||||
var self = this;
|
||||
console.log("开始处理background发送来的内容")
|
||||
if (data.add) { //如果存在add属性,则添加内容
|
||||
//添加内容 到文本框
|
||||
if(data.content == ' '){ // 没有内容时,不换行
|
||||
self.editor.replaceSelection(data.content)
|
||||
}else{
|
||||
self.editor.replaceSelection(data.content+'\n\n')
|
||||
}
|
||||
parent.postMessage({
|
||||
name: 'resetfrommrdocpopup'
|
||||
}, '*');
|
||||
if (data.title) {
|
||||
//for auto extract content
|
||||
self.title.val(data.title);
|
||||
}
|
||||
} else {// 如果不存在add属性,则移除ID所属的元素内容
|
||||
//从uid移除内容
|
||||
$('#' + data.uid, self.noteContent).remove();
|
||||
}
|
||||
};
|
||||
|
||||
// 处理background发送来的文集列表数据,将其遍历到文集下拉框
|
||||
selectProjectsHandler = function(projects){
|
||||
layer.closeAll('loading');
|
||||
// 如果获取文集失败,关闭load层
|
||||
if(projects.error){
|
||||
return
|
||||
}
|
||||
var pro = $("#projects")
|
||||
pro.empty(); //清空option
|
||||
pro.append('<option value="">请选择一个文集</option>')
|
||||
for (var i = 0, l = projects.length, project; i < l; i++) {
|
||||
project = projects[i];
|
||||
if (project.type==0) {
|
||||
pro.append('<option value="' + project.id + '">[公开]' + project.name + '</option>');
|
||||
}else if(project.type==1){
|
||||
pro.append('<option value="' + project.id + '">[私密]' + project.name + '</option>');
|
||||
}else if(project.type==2){
|
||||
pro.append('<option value="' + project.id + '">[指定用户]' + project.name + '</option>');
|
||||
}else if(project.type==3){
|
||||
pro.append('<option value="' + project.id + '">[访问码]' + project.name + '</option>');
|
||||
}
|
||||
else {
|
||||
pro.append('<option value="' + project.id + '">[受限]' + project.name + '</option>');
|
||||
}
|
||||
}
|
||||
form.render();
|
||||
};
|
||||
|
||||
// 处理background发来来的上传图片的URL,将其添加到文本编辑器中
|
||||
pasteImageHandler = function(url){
|
||||
layer.closeAll('loading');
|
||||
self.editor.replaceSelection("\n\n")
|
||||
}
|
||||
|
||||
// popup侦听消息
|
||||
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
|
||||
if (!sender || sender.id !== chrome.i18n.getMessage("@@extension_id")) return;
|
||||
switch (request.name) {
|
||||
case 'actionfrompopupinspecotr': // background将页面标记的数据发送过来
|
||||
self.actionfrompopupinspecotrHandler(request.data);
|
||||
break;
|
||||
case 'checktokenvalue':
|
||||
break;
|
||||
case 'pasteimgurl': //粘贴上传图片
|
||||
pasteImageHandler(request.data)
|
||||
break;
|
||||
case 'selectprojectsvalue':
|
||||
selectProjectsHandler(request.data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
7
BrowserMark/js/readyerror.js
Normal file
@ -0,0 +1,7 @@
|
||||
(function($) {
|
||||
$(function() {
|
||||
var backgroundPage = chrome.extension.getBackgroundPage(),
|
||||
notificationData = backgroundPage.ReadyErrorNotify.notificationData;
|
||||
$('#content').html(notificationData.content);
|
||||
});
|
||||
})(jQuery);
|
2
BrowserMark/layui/css/layui.css
Normal file
2
BrowserMark/layui/css/layui.mobile.css
Normal file
2
BrowserMark/layui/css/modules/code.css
Normal file
@ -0,0 +1,2 @@
|
||||
/** layui-v2.5.6 MIT License By https://www.layui.com */
|
||||
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}
|
BIN
BrowserMark/layui/css/modules/layer/default/icon-ext.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
BrowserMark/layui/css/modules/layer/default/icon.png
Normal file
After Width: | Height: | Size: 11 KiB |
2
BrowserMark/layui/css/modules/layer/default/layer.css
Normal file
BIN
BrowserMark/layui/css/modules/layer/default/loading-0.gif
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
BrowserMark/layui/css/modules/layer/default/loading-1.gif
Normal file
After Width: | Height: | Size: 701 B |
BIN
BrowserMark/layui/css/modules/layer/default/loading-2.gif
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
BrowserMark/layui/font/iconfont.eot
Normal file
554
BrowserMark/layui/font/iconfont.svg
Normal file
After Width: | Height: | Size: 299 KiB |
BIN
BrowserMark/layui/font/iconfont.ttf
Normal file
BIN
BrowserMark/layui/font/iconfont.woff
Normal file
BIN
BrowserMark/layui/font/iconfont.woff2
Normal file
BIN
BrowserMark/layui/images/face/0.gif
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
BrowserMark/layui/images/face/1.gif
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
BrowserMark/layui/images/face/10.gif
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
BrowserMark/layui/images/face/11.gif
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
BrowserMark/layui/images/face/12.gif
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
BrowserMark/layui/images/face/13.gif
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
BrowserMark/layui/images/face/14.gif
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
BrowserMark/layui/images/face/15.gif
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
BrowserMark/layui/images/face/16.gif
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
BrowserMark/layui/images/face/17.gif
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
BrowserMark/layui/images/face/18.gif
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
BrowserMark/layui/images/face/19.gif
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
BrowserMark/layui/images/face/2.gif
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
BrowserMark/layui/images/face/20.gif
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
BrowserMark/layui/images/face/21.gif
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
BrowserMark/layui/images/face/22.gif
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
BrowserMark/layui/images/face/23.gif
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
BrowserMark/layui/images/face/24.gif
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
BrowserMark/layui/images/face/25.gif
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
BrowserMark/layui/images/face/26.gif
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
BrowserMark/layui/images/face/27.gif
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
BrowserMark/layui/images/face/28.gif
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
BrowserMark/layui/images/face/29.gif
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
BrowserMark/layui/images/face/3.gif
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
BrowserMark/layui/images/face/30.gif
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
BrowserMark/layui/images/face/31.gif
Normal file
After Width: | Height: | Size: 2.0 KiB |