##// END OF EJS Templates
comments: fixed codemirror styling problems.
marcink -
r4131:726badcf default
parent child Browse files
Show More
@@ -1,438 +1,439 b''
1 /* BASICS */
1 /* BASICS */
2
2
3 .CodeMirror {
3 .CodeMirror {
4 /* Set height, width, borders, and global font properties here */
4 /* Set height, width, borders, and global font properties here */
5 font-family: monospace;
5 font-family: monospace;
6 height: 300px;
6 height: 300px;
7 color: black;
7 color: black;
8 direction: ltr;
8 direction: ltr;
9 border-radius: @border-radius;
9 border-radius: @border-radius;
10 border: @border-thickness solid @grey6;
10 border: @border-thickness solid @grey6;
11 margin: 0 0 @padding;
11 margin: 0 0 @padding;
12 }
12 }
13
13
14 /* PADDING */
14 /* PADDING */
15
15
16 .CodeMirror-lines {
16 .CodeMirror-lines {
17 padding: 4px 0; /* Vertical padding around content */
17 padding: 4px 0; /* Vertical padding around content */
18 }
18 }
19 .CodeMirror pre.CodeMirror-line,
19 .CodeMirror pre.CodeMirror-line,
20 .CodeMirror pre.CodeMirror-line-like {
20 .CodeMirror pre.CodeMirror-line-like {
21 padding: 0 4px; /* Horizontal padding of content */
21 padding: 0 4px; /* Horizontal padding of content */
22 }
22 }
23
23
24 .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
24 .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
25 background-color: white; /* The little square between H and V scrollbars */
25 background-color: white; /* The little square between H and V scrollbars */
26 }
26 }
27
27
28 /* GUTTER */
28 /* GUTTER */
29
29
30 .CodeMirror-gutters {
30 .CodeMirror-gutters {
31 border-right: 1px solid #ddd;
31 border-right: 1px solid #ddd;
32 background-color: white;
32 background-color: white;
33 white-space: nowrap;
33 white-space: nowrap;
34 }
34 }
35 .CodeMirror-linenumbers {}
35 .CodeMirror-linenumbers {}
36 .CodeMirror-linenumber {
36 .CodeMirror-linenumber {
37 padding: 0 3px 0 5px;
37 padding: 0 3px 0 5px;
38 min-width: 20px;
38 min-width: 20px;
39 text-align: right;
39 text-align: right;
40 color: @grey4;
40 color: @grey4;
41 white-space: nowrap;
41 white-space: nowrap;
42 }
42 }
43
43
44 .CodeMirror-guttermarker { color: black; }
44 .CodeMirror-guttermarker { color: black; }
45 .CodeMirror-guttermarker-subtle { color: #999; }
45 .CodeMirror-guttermarker-subtle { color: #999; }
46
46
47 /* CURSOR */
47 /* CURSOR */
48
48
49 .CodeMirror-cursor {
49 .CodeMirror-cursor {
50 border-left: 1px solid black;
50 border-left: 1px solid black;
51 border-right: none;
51 border-right: none;
52 width: 0;
52 width: 0;
53 }
53 }
54 /* Shown when moving in bi-directional text */
54 /* Shown when moving in bi-directional text */
55 .CodeMirror div.CodeMirror-secondarycursor {
55 .CodeMirror div.CodeMirror-secondarycursor {
56 border-left: 1px solid silver;
56 border-left: 1px solid silver;
57 }
57 }
58 .cm-fat-cursor .CodeMirror-cursor {
58 .cm-fat-cursor .CodeMirror-cursor {
59 width: auto;
59 width: auto;
60 border: 0 !important;
60 border: 0 !important;
61 background: @grey6;
61 background: @grey6;
62 }
62 }
63 .cm-fat-cursor div.CodeMirror-cursors {
63 .cm-fat-cursor div.CodeMirror-cursors {
64 z-index: 1;
64 z-index: 1;
65 }
65 }
66 .cm-fat-cursor-mark {
66 .cm-fat-cursor-mark {
67 background-color: rgba(20, 255, 20, 0.5);
67 background-color: rgba(20, 255, 20, 0.5);
68 -webkit-animation: blink 1.06s steps(1) infinite;
68 -webkit-animation: blink 1.06s steps(1) infinite;
69 -moz-animation: blink 1.06s steps(1) infinite;
69 -moz-animation: blink 1.06s steps(1) infinite;
70 animation: blink 1.06s steps(1) infinite;
70 animation: blink 1.06s steps(1) infinite;
71 }
71 }
72 .cm-animate-fat-cursor {
72 .cm-animate-fat-cursor {
73 width: auto;
73 width: auto;
74 border: 0;
74 border: 0;
75 -webkit-animation: blink 1.06s steps(1) infinite;
75 -webkit-animation: blink 1.06s steps(1) infinite;
76 -moz-animation: blink 1.06s steps(1) infinite;
76 -moz-animation: blink 1.06s steps(1) infinite;
77 animation: blink 1.06s steps(1) infinite;
77 animation: blink 1.06s steps(1) infinite;
78 background-color: #7e7;
78 background-color: #7e7;
79 }
79 }
80 @-moz-keyframes blink {
80 @-moz-keyframes blink {
81 0% { background: #7e7; }
81 0% { background: #7e7; }
82 50% { background: none; }
82 50% { background: none; }
83 100% { background: #7e7; }
83 100% { background: #7e7; }
84 }
84 }
85 @-webkit-keyframes blink {
85 @-webkit-keyframes blink {
86 0% { background: #7e7; }
86 0% { background: #7e7; }
87 50% { background: none; }
87 50% { background: none; }
88 100% { background: #7e7; }
88 100% { background: #7e7; }
89 }
89 }
90 @keyframes blink {
90 @keyframes blink {
91 0% { background: #7e7; }
91 0% { background: #7e7; }
92 50% { background: none; }
92 50% { background: none; }
93 100% { background: #7e7; }
93 100% { background: #7e7; }
94 }
94 }
95
95
96 /* Can style cursor different in overwrite (non-insert) mode */
96 /* Can style cursor different in overwrite (non-insert) mode */
97 .CodeMirror-overwrite .CodeMirror-cursor {}
97 .CodeMirror-overwrite .CodeMirror-cursor {}
98
98
99 .cm-tab { display: inline-block; text-decoration: inherit; }
99 .cm-tab { display: inline-block; text-decoration: inherit; }
100
100
101 .CodeMirror-rulers {
101 .CodeMirror-rulers {
102 position: absolute;
102 position: absolute;
103 left: 0; right: 0; top: -50px; bottom: 0;
103 left: 0; right: 0; top: -50px; bottom: 0;
104 overflow: hidden;
104 overflow: hidden;
105 }
105 }
106 .CodeMirror-ruler {
106 .CodeMirror-ruler {
107 border-left: 1px solid #ccc;
107 border-left: 1px solid #ccc;
108 top: 0; bottom: 0;
108 top: 0; bottom: 0;
109 position: absolute;
109 position: absolute;
110 }
110 }
111
111
112 /* DEFAULT THEME */
112 /* DEFAULT THEME */
113
113
114 .cm-s-default .cm-header {color: blue;}
114 .cm-s-default .cm-header {color: blue;}
115 .cm-s-default .cm-quote {color: #090;}
115 .cm-s-default .cm-quote {color: #090;}
116 .cm-negative {color: #d44;}
116 .cm-negative {color: #d44;}
117 .cm-positive {color: #292;}
117 .cm-positive {color: #292;}
118 .cm-header, .cm-strong {font-weight: bold;}
118 .cm-header, .cm-strong {font-weight: bold;}
119 .cm-em {font-style: italic;}
119 .cm-em {font-style: italic;}
120 .cm-link {text-decoration: underline;}
120 .cm-link {text-decoration: underline;}
121 .cm-strikethrough {text-decoration: line-through;}
121 .cm-strikethrough {text-decoration: line-through;}
122
122
123 .cm-s-default .cm-keyword {color: #708;}
123 .cm-s-default .cm-keyword {color: #708;}
124 .cm-s-default .cm-atom {color: #219;}
124 .cm-s-default .cm-atom {color: #219;}
125 .cm-s-default .cm-number {color: #164;}
125 .cm-s-default .cm-number {color: #164;}
126 .cm-s-default .cm-def {color: #00f;}
126 .cm-s-default .cm-def {color: #00f;}
127 .cm-s-default .cm-variable,
127 .cm-s-default .cm-variable,
128 .cm-s-default .cm-punctuation,
128 .cm-s-default .cm-punctuation,
129 .cm-s-default .cm-property,
129 .cm-s-default .cm-property,
130 .cm-s-default .cm-operator {}
130 .cm-s-default .cm-operator {}
131 .cm-s-default .cm-variable-2 {color: #05a;}
131 .cm-s-default .cm-variable-2 {color: #05a;}
132 .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
132 .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
133 .cm-s-default .cm-comment {color: #a50;}
133 .cm-s-default .cm-comment {color: #a50;}
134 .cm-s-default .cm-string {color: #a11;}
134 .cm-s-default .cm-string {color: #a11;}
135 .cm-s-default .cm-string-2 {color: #f50;}
135 .cm-s-default .cm-string-2 {color: #f50;}
136 .cm-s-default .cm-meta {color: #555;}
136 .cm-s-default .cm-meta {color: #555;}
137 .cm-s-default .cm-qualifier {color: #555;}
137 .cm-s-default .cm-qualifier {color: #555;}
138 .cm-s-default .cm-builtin {color: #30a;}
138 .cm-s-default .cm-builtin {color: #30a;}
139 .cm-s-default .cm-bracket {color: #997;}
139 .cm-s-default .cm-bracket {color: #997;}
140 .cm-s-default .cm-tag {color: #170;}
140 .cm-s-default .cm-tag {color: #170;}
141 .cm-s-default .cm-attribute {color: #00c;}
141 .cm-s-default .cm-attribute {color: #00c;}
142 .cm-s-default .cm-hr {color: #999;}
142 .cm-s-default .cm-hr {color: #999;}
143 .cm-s-default .cm-link {color: #00c;}
143 .cm-s-default .cm-link {color: #00c;}
144
144
145 .cm-s-default .cm-error {color: #f00;}
145 .cm-s-default .cm-error {color: #f00;}
146 .cm-invalidchar {color: #f00;}
146 .cm-invalidchar {color: #f00;}
147
147
148 .CodeMirror-composing { border-bottom: 2px solid; }
148 .CodeMirror-composing { border-bottom: 2px solid; }
149
149
150 /* Default styles for common addons */
150 /* Default styles for common addons */
151
151
152 div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
152 div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
153 div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
153 div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
154 .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
154 .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
155 .CodeMirror-activeline-background {background: #e8f2ff;}
155 .CodeMirror-activeline-background {background: #e8f2ff;}
156
156
157 /* STOP */
157 /* STOP */
158
158
159 /* The rest of this file contains styles related to the mechanics of
159 /* The rest of this file contains styles related to the mechanics of
160 the editor. You probably shouldn't touch them. */
160 the editor. You probably shouldn't touch them. */
161
161
162 .CodeMirror {
162 .CodeMirror {
163 position: relative;
163 position: relative;
164 overflow: hidden;
164 overflow: hidden;
165 background: white;
165 background: white;
166 }
166 }
167
167
168 .CodeMirror-scroll {
168 .CodeMirror-scroll {
169 overflow: scroll !important; /* Things will break if this is overridden */
169 overflow: scroll !important; /* Things will break if this is overridden */
170 /* 30px is the magic margin used to hide the element's real scrollbars */
170 /* 30px is the magic margin used to hide the element's real scrollbars */
171 /* See overflow: hidden in .CodeMirror */
171 /* See overflow: hidden in .CodeMirror */
172 margin-bottom: -30px; margin-right: -30px;
172 margin-bottom: -30px; margin-right: -30px;
173 padding-bottom: 30px;
173 padding-bottom: 30px;
174 height: 100%;
174 height: 100%;
175 outline: none; /* Prevent dragging from highlighting the element */
175 outline: none; /* Prevent dragging from highlighting the element */
176 position: relative;
176 position: relative;
177 }
177 }
178 .CodeMirror-sizer {
178 .CodeMirror-sizer {
179 position: relative;
179 position: relative;
180 border-right: 30px solid transparent;
180 border-right: 30px solid transparent;
181 }
181 }
182
182
183 /* The fake, visible scrollbars. Used to force redraw during scrolling
183 /* The fake, visible scrollbars. Used to force redraw during scrolling
184 before actual scrolling happens, thus preventing shaking and
184 before actual scrolling happens, thus preventing shaking and
185 flickering artifacts. */
185 flickering artifacts. */
186 .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
186 .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
187 position: absolute;
187 position: absolute;
188 z-index: 6;
188 z-index: 6;
189 display: none;
189 display: none;
190 }
190 }
191 .CodeMirror-vscrollbar {
191 .CodeMirror-vscrollbar {
192 right: 0; top: 0;
192 right: 0; top: 0;
193 overflow-x: hidden;
193 overflow-x: hidden;
194 overflow-y: scroll;
194 overflow-y: scroll;
195 }
195 }
196 .CodeMirror-hscrollbar {
196 .CodeMirror-hscrollbar {
197 bottom: 0; left: 0;
197 bottom: 0; left: 0;
198 overflow-y: hidden;
198 overflow-y: hidden;
199 overflow-x: scroll;
199 overflow-x: scroll;
200 }
200 }
201 .CodeMirror-scrollbar-filler {
201 .CodeMirror-scrollbar-filler {
202 right: 0; bottom: 0;
202 right: 0; bottom: 0;
203 }
203 }
204 .CodeMirror-gutter-filler {
204 .CodeMirror-gutter-filler {
205 left: 0; bottom: 0;
205 left: 0; bottom: 0;
206 }
206 }
207
207
208 .CodeMirror-gutters {
208 .CodeMirror-gutters {
209 position: absolute; left: 0; top: 0;
209 position: absolute; left: 0; top: 0;
210 min-height: 100%;
210 min-height: 100%;
211 z-index: 3;
211 z-index: 3;
212 }
212 }
213 .CodeMirror-gutter {
213 .CodeMirror-gutter {
214 white-space: normal;
214 white-space: normal;
215 height: 100%;
215 height: 100%;
216 display: inline-block;
216 display: inline-block;
217 vertical-align: top;
217 vertical-align: top;
218 margin-bottom: -30px;
218 margin-bottom: -30px;
219 }
219 }
220 .CodeMirror-gutter-wrapper {
220 .CodeMirror-gutter-wrapper {
221 position: absolute;
221 position: absolute;
222 z-index: 4;
222 z-index: 4;
223 background: none !important;
223 background: none !important;
224 border: none !important;
224 border: none !important;
225 height: 100%;
225 height: 100%;
226 }
226 }
227 .CodeMirror-gutter-background {
227 .CodeMirror-gutter-background {
228 position: absolute;
228 position: absolute;
229 top: 0; bottom: 0;
229 top: 0; bottom: 0;
230 z-index: 4;
230 z-index: 4;
231 }
231 }
232 .CodeMirror-gutter-elt {
232 .CodeMirror-gutter-elt {
233 position: absolute;
233 position: absolute;
234 cursor: default;
234 cursor: default;
235 z-index: 4;
235 z-index: 4;
236 }
236 }
237 .CodeMirror-gutter-wrapper {
237 .CodeMirror-gutter-wrapper {
238 -webkit-user-select: none;
238 -webkit-user-select: none;
239 -moz-user-select: none;
239 -moz-user-select: none;
240 user-select: none;
240 user-select: none;
241 }
241 }
242
242
243 .CodeMirror-lines {
243 .CodeMirror-lines {
244 cursor: text;
244 cursor: text;
245 min-height: 1px; /* prevents collapsing before first draw */
245 min-height: 1px; /* prevents collapsing before first draw */
246 }
246 }
247 .CodeMirror pre.CodeMirror-line,
247 .CodeMirror pre.CodeMirror-line,
248 .CodeMirror pre.CodeMirror-line-like {
248 .CodeMirror pre.CodeMirror-line-like {
249 /* Reset some styles that the rest of the page might have set */
249 /* Reset some styles that the rest of the page might have set */
250 -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
250 -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
251 border-width: 0;
251 border-width: 0;
252 background: transparent;
252 background: transparent;
253 font-family: inherit;
253 font-family: inherit;
254 font-size: inherit;
254 font-size: inherit;
255 margin: 0;
255 margin: 0;
256 white-space: pre;
256 white-space: pre;
257 word-wrap: normal;
257 word-wrap: normal;
258 line-height: inherit;
258 line-height: inherit;
259 color: inherit;
259 color: inherit;
260 z-index: 2;
260 z-index: 2;
261 position: relative;
261 position: relative;
262 overflow: visible;
262 overflow: visible;
263 -webkit-tap-highlight-color: transparent;
263 -webkit-tap-highlight-color: transparent;
264 -webkit-font-variant-ligatures: contextual;
264 -webkit-font-variant-ligatures: contextual;
265 font-variant-ligatures: contextual;
265 font-variant-ligatures: contextual;
266 }
266 }
267 .CodeMirror-wrap pre.CodeMirror-line,
267 .CodeMirror-wrap pre.CodeMirror-line,
268 .CodeMirror-wrap pre.CodeMirror-line-like {
268 .CodeMirror-wrap pre.CodeMirror-line-like {
269 word-wrap: break-word;
269 word-wrap: break-word;
270 white-space: pre-wrap;
270 white-space: pre-wrap;
271 word-break: normal;
271 word-break: normal;
272 }
272 }
273
273
274 .CodeMirror-linebackground {
274 .CodeMirror-linebackground {
275 position: absolute;
275 position: absolute;
276 left: 0; right: 0; top: 0; bottom: 0;
276 left: 0; right: 0; top: 0; bottom: 0;
277 z-index: 0;
277 z-index: 0;
278 }
278 }
279
279
280 .CodeMirror-linewidget {
280 .CodeMirror-linewidget {
281 position: relative;
281 position: relative;
282 z-index: 2;
282 z-index: 2;
283 padding: 0.1px; /* Force widget margins to stay inside of the container */
283 padding: 0.1px; /* Force widget margins to stay inside of the container */
284 overflow: auto;
284 overflow: auto;
285 }
285 }
286
286
287 .CodeMirror-widget {}
287 .CodeMirror-widget {}
288
288
289 .CodeMirror-rtl pre { direction: rtl; }
289 .CodeMirror-rtl pre { direction: rtl; }
290
290
291 .CodeMirror-code {
291 .CodeMirror-code {
292 outline: none;
292 outline: none;
293 }
293 }
294
294
295 /* Force content-box sizing for the elements where we expect it */
295 /* Force content-box sizing for the elements where we expect it */
296 .CodeMirror-scroll,
296 .CodeMirror-scroll,
297 .CodeMirror-sizer,
297 .CodeMirror-sizer,
298 .CodeMirror-gutter,
298 .CodeMirror-gutter,
299 .CodeMirror-gutters,
299 .CodeMirror-gutters,
300 .CodeMirror-linenumber {
300 .CodeMirror-linenumber {
301 -moz-box-sizing: content-box;
301 /* RhodeCode added !important, to fix diffs rule */
302 box-sizing: content-box;
302 -moz-box-sizing: content-box !important;
303 box-sizing: content-box !important;
303 }
304 }
304
305
305 .CodeMirror-measure {
306 .CodeMirror-measure {
306 position: absolute;
307 position: absolute;
307 width: 100%;
308 width: 100%;
308 height: 0;
309 height: 0;
309 overflow: hidden;
310 overflow: hidden;
310 visibility: hidden;
311 visibility: hidden;
311 }
312 }
312
313
313 .CodeMirror-cursor {
314 .CodeMirror-cursor {
314 position: absolute;
315 position: absolute;
315 pointer-events: none;
316 pointer-events: none;
316 border-right: none;
317 border-right: none;
317 width: 0;
318 width: 0;
318 }
319 }
319 .CodeMirror-measure pre { position: static; }
320 .CodeMirror-measure pre { position: static; }
320
321
321 div.CodeMirror-cursors {
322 div.CodeMirror-cursors {
322 visibility: hidden;
323 visibility: hidden;
323 position: relative;
324 position: relative;
324 z-index: 3;
325 z-index: 3;
325 }
326 }
326 div.CodeMirror-dragcursors {
327 div.CodeMirror-dragcursors {
327 visibility: visible;
328 visibility: visible;
328 }
329 }
329
330
330 .CodeMirror-focused div.CodeMirror-cursors {
331 .CodeMirror-focused div.CodeMirror-cursors {
331 visibility: visible;
332 visibility: visible;
332 }
333 }
333
334
334 .CodeMirror-selected { background: #d9d9d9; }
335 .CodeMirror-selected { background: #d9d9d9; }
335 .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
336 .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
336 .CodeMirror-crosshair { cursor: crosshair; }
337 .CodeMirror-crosshair { cursor: crosshair; }
337 .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
338 .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
338 .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
339 .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
339
340
340 .cm-searching {
341 .cm-searching {
341 background-color: #ffa;
342 background-color: #ffa;
342 background-color: rgba(255, 255, 0, .4);
343 background-color: rgba(255, 255, 0, .4);
343 }
344 }
344
345
345 /* Used to force a border model for a node */
346 /* Used to force a border model for a node */
346 .cm-force-border { padding-right: .1px; }
347 .cm-force-border { padding-right: .1px; }
347
348
348 @media print {
349 @media print {
349 /* Hide the cursor when printing */
350 /* Hide the cursor when printing */
350 .CodeMirror div.CodeMirror-cursors {
351 .CodeMirror div.CodeMirror-cursors {
351 visibility: hidden;
352 visibility: hidden;
352 }
353 }
353 }
354 }
354
355
355 /* See issue #2901 */
356 /* See issue #2901 */
356 .cm-tab-wrap-hack:after { content: ''; }
357 .cm-tab-wrap-hack:after { content: ''; }
357
358
358 /* Help users use markselection to safely style text background */
359 /* Help users use markselection to safely style text background */
359 span.CodeMirror-selectedtext { background: none; }
360 span.CodeMirror-selectedtext { background: none; }
360
361
361 /* codemirror autocomplete widget */
362 /* codemirror autocomplete widget */
362 .CodeMirror-hints {
363 .CodeMirror-hints {
363 position: absolute;
364 position: absolute;
364 z-index: 10;
365 z-index: 10;
365 overflow: hidden;
366 overflow: hidden;
366 list-style: none;
367 list-style: none;
367
368
368 margin: 0;
369 margin: 0;
369 padding: 0;
370 padding: 0;
370
371
371 border-radius: @border-radius;
372 border-radius: @border-radius;
372 border: @border-thickness solid @rcblue;
373 border: @border-thickness solid @rcblue;
373
374
374 color: @rcblue;
375 color: @rcblue;
375 background-color: white;
376 background-color: white;
376 font-size: 95%;
377 font-size: 95%;
377
378
378 max-height: 20em;
379 max-height: 20em;
379 overflow-y: auto;
380 overflow-y: auto;
380 }
381 }
381
382
382 .CodeMirror-hint {
383 .CodeMirror-hint {
383 margin: 0;
384 margin: 0;
384 padding: 4px 8px;
385 padding: 4px 8px;
385 max-width: 40em;
386 max-width: 40em;
386 white-space: pre;
387 white-space: pre;
387 color: @rcblue;
388 color: @rcblue;
388 cursor: pointer;
389 cursor: pointer;
389 }
390 }
390
391
391 .CodeMirror-hint-active {
392 .CodeMirror-hint-active {
392 background: @rclightblue;
393 background: @rclightblue;
393 color: @rcblue;
394 color: @rcblue;
394 }
395 }
395
396
396 .CodeMirror-hint-entry {
397 .CodeMirror-hint-entry {
397 width: 38em;
398 width: 38em;
398 color: @rcblue;
399 color: @rcblue;
399 }
400 }
400
401
401 .CodeMirror-hint-entry .gravatar {
402 .CodeMirror-hint-entry .gravatar {
402 height: @gravatar-size;
403 height: @gravatar-size;
403 width: @gravatar-size;
404 width: @gravatar-size;
404 margin-right: 4px;
405 margin-right: 4px;
405 }
406 }
406
407
407 .CodeMirror-empty {
408 .CodeMirror-empty {
408 border: @border-thickness solid @grey5;
409 border: @border-thickness solid @grey5;
409 }
410 }
410
411
411 .CodeMirror-focused {
412 .CodeMirror-focused {
412 border: @border-thickness solid @grey5;
413 border: @border-thickness solid @grey5;
413 }
414 }
414
415
415 .CodeMirror-empty.CodeMirror-focused {
416 .CodeMirror-empty.CodeMirror-focused {
416 border: @border-thickness solid @grey5;
417 border: @border-thickness solid @grey5;
417 }
418 }
418
419
419 .CodeMirror pre.CodeMirror-placeholder {
420 .CodeMirror pre.CodeMirror-placeholder {
420 color: @grey4;
421 color: @grey4;
421 }
422 }
422
423
423 /** RhodeCode Customizations **/
424 /** RhodeCode Customizations **/
424
425
425 .CodeMirror.cm-s-rc-input {
426 .CodeMirror.cm-s-rc-input {
426 border: @border-thickness solid @grey4;
427 border: @border-thickness solid @grey4;
427 }
428 }
428
429
429 .CodeMirror-code pre {
430 .CodeMirror-code pre {
430 border-right: 30px solid transparent;
431 border-right: 30px solid transparent;
431 width: -webkit-fit-content;
432 width: -webkit-fit-content;
432 width: -moz-fit-content;
433 width: -moz-fit-content;
433 width: fit-content;
434 width: fit-content;
434 }
435 }
435 .CodeMirror-wrap .CodeMirror-code pre {
436 .CodeMirror-wrap .CodeMirror-code pre {
436 border-right: none;
437 border-right: none;
437 width: auto;
438 width: auto;
438 }
439 }
@@ -1,844 +1,843 b''
1 // # Copyright (C) 2010-2019 RhodeCode GmbH
1 // # Copyright (C) 2010-2019 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 /**
19 /**
20 * Code Mirror
20 * Code Mirror
21 */
21 */
22 // global code-mirror logger;, to enable run
22 // global code-mirror logger;, to enable run
23 // Logger.get('CodeMirror').setLevel(Logger.DEBUG)
23 // Logger.get('CodeMirror').setLevel(Logger.DEBUG)
24
24
25 cmLog = Logger.get('CodeMirror');
25 cmLog = Logger.get('CodeMirror');
26 cmLog.setLevel(Logger.OFF);
26 cmLog.setLevel(Logger.OFF);
27
27
28
28
29 //global cache for inline forms
29 //global cache for inline forms
30 var userHintsCache = {};
30 var userHintsCache = {};
31
31
32 // global timer, used to cancel async loading
32 // global timer, used to cancel async loading
33 var CodeMirrorLoadUserHintTimer;
33 var CodeMirrorLoadUserHintTimer;
34
34
35 var escapeRegExChars = function(value) {
35 var escapeRegExChars = function(value) {
36 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
36 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
37 };
37 };
38
38
39 /**
39 /**
40 * Load hints from external source returns an array of objects in a format
40 * Load hints from external source returns an array of objects in a format
41 * that hinting lib requires
41 * that hinting lib requires
42 * @returns {Array}
42 * @returns {Array}
43 */
43 */
44 var CodeMirrorLoadUserHints = function(query, triggerHints) {
44 var CodeMirrorLoadUserHints = function(query, triggerHints) {
45 cmLog.debug('Loading mentions users via AJAX');
45 cmLog.debug('Loading mentions users via AJAX');
46 var _users = [];
46 var _users = [];
47 $.ajax({
47 $.ajax({
48 type: 'GET',
48 type: 'GET',
49 data: {query: query},
49 data: {query: query},
50 url: pyroutes.url('user_autocomplete_data'),
50 url: pyroutes.url('user_autocomplete_data'),
51 headers: {'X-PARTIAL-XHR': true},
51 headers: {'X-PARTIAL-XHR': true},
52 async: true
52 async: true
53 })
53 })
54 .done(function(data) {
54 .done(function(data) {
55 var tmpl = '<img class="gravatar" src="{0}"/>{1}';
55 var tmpl = '<img class="gravatar" src="{0}"/>{1}';
56 $.each(data.suggestions, function(i) {
56 $.each(data.suggestions, function(i) {
57 var userObj = data.suggestions[i];
57 var userObj = data.suggestions[i];
58
58
59 if (userObj.username !== "default") {
59 if (userObj.username !== "default") {
60 _users.push({
60 _users.push({
61 text: userObj.username + " ",
61 text: userObj.username + " ",
62 org_text: userObj.username,
62 org_text: userObj.username,
63 displayText: userObj.value_display, // search that field
63 displayText: userObj.value_display, // search that field
64 // internal caches
64 // internal caches
65 _icon_link: userObj.icon_link,
65 _icon_link: userObj.icon_link,
66 _text: userObj.value_display,
66 _text: userObj.value_display,
67
67
68 render: function(elt, data, completion) {
68 render: function(elt, data, completion) {
69 var el = document.createElement('div');
69 var el = document.createElement('div');
70 el.className = "CodeMirror-hint-entry";
70 el.className = "CodeMirror-hint-entry";
71 el.innerHTML = tmpl.format(
71 el.innerHTML = tmpl.format(
72 completion._icon_link, completion._text);
72 completion._icon_link, completion._text);
73 elt.appendChild(el);
73 elt.appendChild(el);
74 }
74 }
75 });
75 });
76 }
76 }
77 });
77 });
78 cmLog.debug('Mention users loaded');
78 cmLog.debug('Mention users loaded');
79 // set to global cache
79 // set to global cache
80 userHintsCache[query] = _users;
80 userHintsCache[query] = _users;
81 triggerHints(userHintsCache[query]);
81 triggerHints(userHintsCache[query]);
82 })
82 })
83 .fail(function(data, textStatus, xhr) {
83 .fail(function(data, textStatus, xhr) {
84 alert("error processing request. \n" +
84 alert("error processing request. \n" +
85 "Error code {0} ({1}).".format(data.status, data.statusText));
85 "Error code {0} ({1}).".format(data.status, data.statusText));
86 });
86 });
87 };
87 };
88
88
89 /**
89 /**
90 * filters the results based on the current context
90 * filters the results based on the current context
91 * @param users
91 * @param users
92 * @param context
92 * @param context
93 * @returns {Array}
93 * @returns {Array}
94 */
94 */
95 var CodeMirrorFilterUsers = function(users, context) {
95 var CodeMirrorFilterUsers = function(users, context) {
96 var MAX_LIMIT = 10;
96 var MAX_LIMIT = 10;
97 var filtered_users = [];
97 var filtered_users = [];
98 var curWord = context.string;
98 var curWord = context.string;
99
99
100 cmLog.debug('Filtering users based on query:', curWord);
100 cmLog.debug('Filtering users based on query:', curWord);
101 $.each(users, function(i) {
101 $.each(users, function(i) {
102 var match = users[i];
102 var match = users[i];
103 var searchText = match.displayText;
103 var searchText = match.displayText;
104
104
105 if (!curWord ||
105 if (!curWord ||
106 searchText.toLowerCase().lastIndexOf(curWord) !== -1) {
106 searchText.toLowerCase().lastIndexOf(curWord) !== -1) {
107 // reset state
107 // reset state
108 match._text = match.displayText;
108 match._text = match.displayText;
109 if (curWord) {
109 if (curWord) {
110 // do highlighting
110 // do highlighting
111 var pattern = '(' + escapeRegExChars(curWord) + ')';
111 var pattern = '(' + escapeRegExChars(curWord) + ')';
112 match._text = searchText.replace(
112 match._text = searchText.replace(
113 new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
113 new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
114 }
114 }
115
115
116 filtered_users.push(match);
116 filtered_users.push(match);
117 }
117 }
118 // to not return to many results, use limit of filtered results
118 // to not return to many results, use limit of filtered results
119 if (filtered_users.length > MAX_LIMIT) {
119 if (filtered_users.length > MAX_LIMIT) {
120 return false;
120 return false;
121 }
121 }
122 });
122 });
123
123
124 return filtered_users;
124 return filtered_users;
125 };
125 };
126
126
127 var CodeMirrorMentionHint = function(editor, callback, options) {
127 var CodeMirrorMentionHint = function(editor, callback, options) {
128 var cur = editor.getCursor();
128 var cur = editor.getCursor();
129 var curLine = editor.getLine(cur.line).slice(0, cur.ch);
129 var curLine = editor.getLine(cur.line).slice(0, cur.ch);
130
130
131 // match on @ +1char
131 // match on @ +1char
132 var tokenMatch = new RegExp(
132 var tokenMatch = new RegExp(
133 '(^@| @)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*)$').exec(curLine);
133 '(^@| @)([a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]*)$').exec(curLine);
134
134
135 var tokenStr = '';
135 var tokenStr = '';
136 if (tokenMatch !== null && tokenMatch.length > 0){
136 if (tokenMatch !== null && tokenMatch.length > 0){
137 tokenStr = tokenMatch[0].strip();
137 tokenStr = tokenMatch[0].strip();
138 } else {
138 } else {
139 // skip if we didn't match our token
139 // skip if we didn't match our token
140 return;
140 return;
141 }
141 }
142
142
143 var context = {
143 var context = {
144 start: (cur.ch - tokenStr.length) + 1,
144 start: (cur.ch - tokenStr.length) + 1,
145 end: cur.ch,
145 end: cur.ch,
146 string: tokenStr.slice(1),
146 string: tokenStr.slice(1),
147 type: null
147 type: null
148 };
148 };
149
149
150 // case when we put the @sign in fron of a string,
150 // case when we put the @sign in fron of a string,
151 // eg <@ we put it here>sometext then we need to prepend to text
151 // eg <@ we put it here>sometext then we need to prepend to text
152 if (context.end > cur.ch) {
152 if (context.end > cur.ch) {
153 context.start = context.start + 1; // we add to the @ sign
153 context.start = context.start + 1; // we add to the @ sign
154 context.end = cur.ch; // don't eat front part just append
154 context.end = cur.ch; // don't eat front part just append
155 context.string = context.string.slice(1, cur.ch - context.start);
155 context.string = context.string.slice(1, cur.ch - context.start);
156 }
156 }
157
157
158 cmLog.debug('Mention context', context);
158 cmLog.debug('Mention context', context);
159
159
160 var triggerHints = function(userHints){
160 var triggerHints = function(userHints){
161 return callback({
161 return callback({
162 list: CodeMirrorFilterUsers(userHints, context),
162 list: CodeMirrorFilterUsers(userHints, context),
163 from: CodeMirror.Pos(cur.line, context.start),
163 from: CodeMirror.Pos(cur.line, context.start),
164 to: CodeMirror.Pos(cur.line, context.end)
164 to: CodeMirror.Pos(cur.line, context.end)
165 });
165 });
166 };
166 };
167
167
168 var queryBasedHintsCache = undefined;
168 var queryBasedHintsCache = undefined;
169 // if we have something in the cache, try to fetch the query based cache
169 // if we have something in the cache, try to fetch the query based cache
170 if (userHintsCache !== {}){
170 if (userHintsCache !== {}){
171 queryBasedHintsCache = userHintsCache[context.string];
171 queryBasedHintsCache = userHintsCache[context.string];
172 }
172 }
173
173
174 if (queryBasedHintsCache !== undefined) {
174 if (queryBasedHintsCache !== undefined) {
175 cmLog.debug('Users loaded from cache');
175 cmLog.debug('Users loaded from cache');
176 triggerHints(queryBasedHintsCache);
176 triggerHints(queryBasedHintsCache);
177 } else {
177 } else {
178 // this takes care for async loading, and then displaying results
178 // this takes care for async loading, and then displaying results
179 // and also propagates the userHintsCache
179 // and also propagates the userHintsCache
180 window.clearTimeout(CodeMirrorLoadUserHintTimer);
180 window.clearTimeout(CodeMirrorLoadUserHintTimer);
181 CodeMirrorLoadUserHintTimer = setTimeout(function() {
181 CodeMirrorLoadUserHintTimer = setTimeout(function() {
182 CodeMirrorLoadUserHints(context.string, triggerHints);
182 CodeMirrorLoadUserHints(context.string, triggerHints);
183 }, 300);
183 }, 300);
184 }
184 }
185 };
185 };
186
186
187 var CodeMirrorCompleteAfter = function(cm, pred) {
187 var CodeMirrorCompleteAfter = function(cm, pred) {
188 var options = {
188 var options = {
189 completeSingle: false,
189 completeSingle: false,
190 async: true,
190 async: true,
191 closeOnUnfocus: true
191 closeOnUnfocus: true
192 };
192 };
193 var cur = cm.getCursor();
193 var cur = cm.getCursor();
194 setTimeout(function() {
194 setTimeout(function() {
195 if (!cm.state.completionActive) {
195 if (!cm.state.completionActive) {
196 cmLog.debug('Trigger mentions hinting');
196 cmLog.debug('Trigger mentions hinting');
197 CodeMirror.showHint(cm, CodeMirror.hint.mentions, options);
197 CodeMirror.showHint(cm, CodeMirror.hint.mentions, options);
198 }
198 }
199 }, 100);
199 }, 100);
200
200
201 // tell CodeMirror we didn't handle the key
201 // tell CodeMirror we didn't handle the key
202 // trick to trigger on a char but still complete it
202 // trick to trigger on a char but still complete it
203 return CodeMirror.Pass;
203 return CodeMirror.Pass;
204 };
204 };
205
205
206 var initCodeMirror = function(textAreadId, resetUrl, focus, options) {
206 var initCodeMirror = function(textAreadId, resetUrl, focus, options) {
207 if (textAreadId.substr(0,1) === "#"){
207 if (textAreadId.substr(0,1) === "#"){
208 var ta = $(textAreadId).get(0);
208 var ta = $(textAreadId).get(0);
209 }else {
209 }else {
210 var ta = $('#' + textAreadId).get(0);
210 var ta = $('#' + textAreadId).get(0);
211 }
211 }
212
212
213 if (focus === undefined) {
213 if (focus === undefined) {
214 focus = true;
214 focus = true;
215 }
215 }
216
216
217 // default options
217 // default options
218 var codeMirrorOptions = {
218 var codeMirrorOptions = {
219 mode: "null",
219 mode: "null",
220 lineNumbers: true,
220 lineNumbers: true,
221 indentUnit: 4,
221 indentUnit: 4,
222 autofocus: focus
222 autofocus: focus
223 };
223 };
224
224
225 if (options !== undefined) {
225 if (options !== undefined) {
226 // extend with custom options
226 // extend with custom options
227 codeMirrorOptions = $.extend(true, codeMirrorOptions, options);
227 codeMirrorOptions = $.extend(true, codeMirrorOptions, options);
228 }
228 }
229
229
230 var myCodeMirror = CodeMirror.fromTextArea(ta, codeMirrorOptions);
230 var myCodeMirror = CodeMirror.fromTextArea(ta, codeMirrorOptions);
231
231
232 $('#reset').on('click', function(e) {
232 $('#reset').on('click', function(e) {
233 window.location = resetUrl;
233 window.location = resetUrl;
234 });
234 });
235
235
236 return myCodeMirror;
236 return myCodeMirror;
237 };
237 };
238
238
239
239
240 var initMarkupCodeMirror = function(textAreadId, focus, options) {
240 var initMarkupCodeMirror = function(textAreadId, focus, options) {
241 var initialHeight = 100;
241 var initialHeight = 100;
242
242
243 var ta = $(textAreadId).get(0);
243 var ta = $(textAreadId).get(0);
244 if (focus === undefined) {
244 if (focus === undefined) {
245 focus = true;
245 focus = true;
246 }
246 }
247
247
248 // default options
248 // default options
249 var codeMirrorOptions = {
249 var codeMirrorOptions = {
250 lineNumbers: false,
250 lineNumbers: false,
251 indentUnit: 4,
251 indentUnit: 4,
252 viewportMargin: 30,
252 viewportMargin: 30,
253 // this is a trick to trigger some logic behind codemirror placeholder
253 // this is a trick to trigger some logic behind codemirror placeholder
254 // it influences styling and behaviour.
254 // it influences styling and behaviour.
255 placeholder: " ",
255 placeholder: " ",
256 lineWrapping: true,
256 lineWrapping: true,
257 autofocus: focus
257 autofocus: focus
258 };
258 };
259
259
260 if (options !== undefined) {
260 if (options !== undefined) {
261 // extend with custom options
261 // extend with custom options
262 codeMirrorOptions = $.extend(true, codeMirrorOptions, options);
262 codeMirrorOptions = $.extend(true, codeMirrorOptions, options);
263 }
263 }
264
264
265 var cm = CodeMirror.fromTextArea(ta, codeMirrorOptions);
265 var cm = CodeMirror.fromTextArea(ta, codeMirrorOptions);
266 cm.setSize(null, initialHeight);
266 cm.setSize(null, initialHeight);
267 cm.setOption("mode", DEFAULT_RENDERER);
267 cm.setOption("mode", DEFAULT_RENDERER);
268 CodeMirror.autoLoadMode(cm, DEFAULT_RENDERER); // load rst or markdown mode
268 CodeMirror.autoLoadMode(cm, DEFAULT_RENDERER); // load rst or markdown mode
269 cmLog.debug('Loading codemirror mode', DEFAULT_RENDERER);
269 cmLog.debug('Loading codemirror mode', DEFAULT_RENDERER);
270
270
271 // start listening on changes to make auto-expanded editor
271 // start listening on changes to make auto-expanded editor
272 cm.on("change", function(instance, changeObj) {
272 cm.on("change", function (instance, changeObj) {
273 var height = initialHeight;
273 var height = initialHeight;
274 var lines = instance.lineCount();
274 var lines = instance.lineCount();
275 if ( lines > 6 && lines < 20) {
275 if (lines > 6 && lines < 20) {
276 height = "auto";
276 height = "auto";
277 }
277 } else if (lines >= 20) {
278 else if (lines >= 20){
278 height = 20 * 15;
279 zheight = 20*15;
280 }
279 }
281 instance.setSize(null, height);
280 instance.setSize(null, height);
282
281
283 // detect if the change was trigger by auto desc, or user input
282 // detect if the change was trigger by auto desc, or user input
284 var changeOrigin = changeObj.origin;
283 var changeOrigin = changeObj.origin;
285
284
286 if (changeOrigin === "setValue") {
285 if (changeOrigin === "setValue") {
287 cmLog.debug('Change triggered by setValue');
286 cmLog.debug('Change triggered by setValue');
288 }
287 }
289 else {
288 else {
290 cmLog.debug('user triggered change !');
289 cmLog.debug('user triggered change !');
291 // set special marker to indicate user has created an input.
290 // set special marker to indicate user has created an input.
292 instance._userDefinedValue = true;
291 instance._userDefinedValue = true;
293 }
292 }
294
293
295 });
294 });
296
295
297 return cm;
296 return cm;
298 };
297 };
299
298
300
299
301 var initCommentBoxCodeMirror = function(CommentForm, textAreaId, triggerActions){
300 var initCommentBoxCodeMirror = function(CommentForm, textAreaId, triggerActions){
302 var initialHeight = 100;
301 var initialHeight = 100;
303
302
304 if (typeof userHintsCache === "undefined") {
303 if (typeof userHintsCache === "undefined") {
305 userHintsCache = {};
304 userHintsCache = {};
306 cmLog.debug('Init empty cache for mentions');
305 cmLog.debug('Init empty cache for mentions');
307 }
306 }
308 if (!$(textAreaId).get(0)) {
307 if (!$(textAreaId).get(0)) {
309 cmLog.debug('Element for textarea not found', textAreaId);
308 cmLog.debug('Element for textarea not found', textAreaId);
310 return;
309 return;
311 }
310 }
312 /**
311 /**
313 * Filter action based on typed in text
312 * Filter action based on typed in text
314 * @param actions
313 * @param actions
315 * @param context
314 * @param context
316 * @returns {Array}
315 * @returns {Array}
317 */
316 */
318
317
319 var filterActions = function(actions, context){
318 var filterActions = function(actions, context){
320
319
321 var MAX_LIMIT = 10;
320 var MAX_LIMIT = 10;
322 var filtered_actions = [];
321 var filtered_actions = [];
323 var curWord = context.string;
322 var curWord = context.string;
324
323
325 cmLog.debug('Filtering actions based on query:', curWord);
324 cmLog.debug('Filtering actions based on query:', curWord);
326 $.each(actions, function(i) {
325 $.each(actions, function(i) {
327 var match = actions[i];
326 var match = actions[i];
328 var searchText = match.searchText;
327 var searchText = match.searchText;
329
328
330 if (!curWord ||
329 if (!curWord ||
331 searchText.toLowerCase().lastIndexOf(curWord) !== -1) {
330 searchText.toLowerCase().lastIndexOf(curWord) !== -1) {
332 // reset state
331 // reset state
333 match._text = match.displayText;
332 match._text = match.displayText;
334 if (curWord) {
333 if (curWord) {
335 // do highlighting
334 // do highlighting
336 var pattern = '(' + escapeRegExChars(curWord) + ')';
335 var pattern = '(' + escapeRegExChars(curWord) + ')';
337 match._text = searchText.replace(
336 match._text = searchText.replace(
338 new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
337 new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
339 }
338 }
340
339
341 filtered_actions.push(match);
340 filtered_actions.push(match);
342 }
341 }
343 // to not return to many results, use limit of filtered results
342 // to not return to many results, use limit of filtered results
344 if (filtered_actions.length > MAX_LIMIT) {
343 if (filtered_actions.length > MAX_LIMIT) {
345 return false;
344 return false;
346 }
345 }
347 });
346 });
348
347
349 return filtered_actions;
348 return filtered_actions;
350 };
349 };
351
350
352 var submitForm = function(cm, pred) {
351 var submitForm = function(cm, pred) {
353 $(cm.display.input.textarea.form).submit();
352 $(cm.display.input.textarea.form).submit();
354 return CodeMirror.Pass;
353 return CodeMirror.Pass;
355 };
354 };
356
355
357 var completeActions = function(actions){
356 var completeActions = function(actions){
358
357
359 var registeredActions = [];
358 var registeredActions = [];
360 var allActions = [
359 var allActions = [
361 {
360 {
362 text: "approve",
361 text: "approve",
363 searchText: "status approved",
362 searchText: "status approved",
364 displayText: _gettext('Set status to Approved'),
363 displayText: _gettext('Set status to Approved'),
365 hint: function(CodeMirror, data, completion) {
364 hint: function(CodeMirror, data, completion) {
366 CodeMirror.replaceRange("", completion.from || data.from,
365 CodeMirror.replaceRange("", completion.from || data.from,
367 completion.to || data.to, "complete");
366 completion.to || data.to, "complete");
368 $(CommentForm.statusChange).select2("val", 'approved').trigger('change');
367 $(CommentForm.statusChange).select2("val", 'approved').trigger('change');
369 },
368 },
370 render: function(elt, data, completion) {
369 render: function(elt, data, completion) {
371 var el = document.createElement('i');
370 var el = document.createElement('i');
372
371
373 el.className = "icon-circle review-status-approved";
372 el.className = "icon-circle review-status-approved";
374 elt.appendChild(el);
373 elt.appendChild(el);
375
374
376 el = document.createElement('span');
375 el = document.createElement('span');
377 el.innerHTML = completion.displayText;
376 el.innerHTML = completion.displayText;
378 elt.appendChild(el);
377 elt.appendChild(el);
379 }
378 }
380 },
379 },
381 {
380 {
382 text: "reject",
381 text: "reject",
383 searchText: "status rejected",
382 searchText: "status rejected",
384 displayText: _gettext('Set status to Rejected'),
383 displayText: _gettext('Set status to Rejected'),
385 hint: function(CodeMirror, data, completion) {
384 hint: function(CodeMirror, data, completion) {
386 CodeMirror.replaceRange("", completion.from || data.from,
385 CodeMirror.replaceRange("", completion.from || data.from,
387 completion.to || data.to, "complete");
386 completion.to || data.to, "complete");
388 $(CommentForm.statusChange).select2("val", 'rejected').trigger('change');
387 $(CommentForm.statusChange).select2("val", 'rejected').trigger('change');
389 },
388 },
390 render: function(elt, data, completion) {
389 render: function(elt, data, completion) {
391 var el = document.createElement('i');
390 var el = document.createElement('i');
392 el.className = "icon-circle review-status-rejected";
391 el.className = "icon-circle review-status-rejected";
393 elt.appendChild(el);
392 elt.appendChild(el);
394
393
395 el = document.createElement('span');
394 el = document.createElement('span');
396 el.innerHTML = completion.displayText;
395 el.innerHTML = completion.displayText;
397 elt.appendChild(el);
396 elt.appendChild(el);
398 }
397 }
399 },
398 },
400 {
399 {
401 text: "as_todo",
400 text: "as_todo",
402 searchText: "todo comment",
401 searchText: "todo comment",
403 displayText: _gettext('TODO comment'),
402 displayText: _gettext('TODO comment'),
404 hint: function(CodeMirror, data, completion) {
403 hint: function(CodeMirror, data, completion) {
405 CodeMirror.replaceRange("", completion.from || data.from,
404 CodeMirror.replaceRange("", completion.from || data.from,
406 completion.to || data.to, "complete");
405 completion.to || data.to, "complete");
407
406
408 $(CommentForm.commentType).val('todo');
407 $(CommentForm.commentType).val('todo');
409 },
408 },
410 render: function(elt, data, completion) {
409 render: function(elt, data, completion) {
411 var el = document.createElement('div');
410 var el = document.createElement('div');
412 el.className = "pull-left";
411 el.className = "pull-left";
413 elt.appendChild(el);
412 elt.appendChild(el);
414
413
415 el = document.createElement('span');
414 el = document.createElement('span');
416 el.innerHTML = completion.displayText;
415 el.innerHTML = completion.displayText;
417 elt.appendChild(el);
416 elt.appendChild(el);
418 }
417 }
419 },
418 },
420 {
419 {
421 text: "as_note",
420 text: "as_note",
422 searchText: "note comment",
421 searchText: "note comment",
423 displayText: _gettext('Note Comment'),
422 displayText: _gettext('Note Comment'),
424 hint: function(CodeMirror, data, completion) {
423 hint: function(CodeMirror, data, completion) {
425 CodeMirror.replaceRange("", completion.from || data.from,
424 CodeMirror.replaceRange("", completion.from || data.from,
426 completion.to || data.to, "complete");
425 completion.to || data.to, "complete");
427
426
428 $(CommentForm.commentType).val('note');
427 $(CommentForm.commentType).val('note');
429 },
428 },
430 render: function(elt, data, completion) {
429 render: function(elt, data, completion) {
431 var el = document.createElement('div');
430 var el = document.createElement('div');
432 el.className = "pull-left";
431 el.className = "pull-left";
433 elt.appendChild(el);
432 elt.appendChild(el);
434
433
435 el = document.createElement('span');
434 el = document.createElement('span');
436 el.innerHTML = completion.displayText;
435 el.innerHTML = completion.displayText;
437 elt.appendChild(el);
436 elt.appendChild(el);
438 }
437 }
439 }
438 }
440 ];
439 ];
441
440
442 $.each(allActions, function(index, value){
441 $.each(allActions, function(index, value){
443 var actionData = allActions[index];
442 var actionData = allActions[index];
444 if (actions.indexOf(actionData['text']) != -1) {
443 if (actions.indexOf(actionData['text']) != -1) {
445 registeredActions.push(actionData);
444 registeredActions.push(actionData);
446 }
445 }
447 });
446 });
448
447
449 return function(cm, pred) {
448 return function(cm, pred) {
450 var cur = cm.getCursor();
449 var cur = cm.getCursor();
451 var options = {
450 var options = {
452 closeOnUnfocus: true,
451 closeOnUnfocus: true,
453 registeredActions: registeredActions
452 registeredActions: registeredActions
454 };
453 };
455 setTimeout(function() {
454 setTimeout(function() {
456 if (!cm.state.completionActive) {
455 if (!cm.state.completionActive) {
457 cmLog.debug('Trigger actions hinting');
456 cmLog.debug('Trigger actions hinting');
458 CodeMirror.showHint(cm, CodeMirror.hint.actions, options);
457 CodeMirror.showHint(cm, CodeMirror.hint.actions, options);
459 }
458 }
460 }, 100);
459 }, 100);
461
460
462 // tell CodeMirror we didn't handle the key
461 // tell CodeMirror we didn't handle the key
463 // trick to trigger on a char but still complete it
462 // trick to trigger on a char but still complete it
464 return CodeMirror.Pass;
463 return CodeMirror.Pass;
465 }
464 }
466 };
465 };
467
466
468 var extraKeys = {
467 var extraKeys = {
469 "'@'": CodeMirrorCompleteAfter,
468 "'@'": CodeMirrorCompleteAfter,
470 Tab: function(cm) {
469 Tab: function(cm) {
471 // space indent instead of TABS
470 // space indent instead of TABS
472 var spaces = new Array(cm.getOption("indentUnit") + 1).join(" ");
471 var spaces = new Array(cm.getOption("indentUnit") + 1).join(" ");
473 cm.replaceSelection(spaces);
472 cm.replaceSelection(spaces);
474 }
473 }
475 };
474 };
476 // submit form on Meta-Enter
475 // submit form on Meta-Enter
477 if (OSType === "mac") {
476 if (OSType === "mac") {
478 extraKeys["Cmd-Enter"] = submitForm;
477 extraKeys["Cmd-Enter"] = submitForm;
479 }
478 }
480 else {
479 else {
481 extraKeys["Ctrl-Enter"] = submitForm;
480 extraKeys["Ctrl-Enter"] = submitForm;
482 }
481 }
483
482
484 if (triggerActions) {
483 if (triggerActions) {
485 // register triggerActions for this instance
484 // register triggerActions for this instance
486 extraKeys["'/'"] = completeActions(triggerActions);
485 extraKeys["'/'"] = completeActions(triggerActions);
487 }
486 }
488
487
489 var cm = CodeMirror.fromTextArea($(textAreaId).get(0), {
488 var cm = CodeMirror.fromTextArea($(textAreaId).get(0), {
490 lineNumbers: false,
489 lineNumbers: false,
491 indentUnit: 4,
490 indentUnit: 4,
492 viewportMargin: 30,
491 viewportMargin: 30,
493 // this is a trick to trigger some logic behind codemirror placeholder
492 // this is a trick to trigger some logic behind codemirror placeholder
494 // it influences styling and behaviour.
493 // it influences styling and behaviour.
495 placeholder: " ",
494 placeholder: " ",
496 extraKeys: extraKeys,
495 extraKeys: extraKeys,
497 lineWrapping: true
496 lineWrapping: true
498 });
497 });
499
498
500 cm.setSize(null, initialHeight);
499 cm.setSize(null, initialHeight);
501 cm.setOption("mode", DEFAULT_RENDERER);
500 cm.setOption("mode", DEFAULT_RENDERER);
502 CodeMirror.autoLoadMode(cm, DEFAULT_RENDERER); // load rst or markdown mode
501 CodeMirror.autoLoadMode(cm, DEFAULT_RENDERER); // load rst or markdown mode
503 cmLog.debug('Loading codemirror mode', DEFAULT_RENDERER);
502 cmLog.debug('Loading codemirror mode', DEFAULT_RENDERER);
503
504 // start listening on changes to make auto-expanded editor
504 // start listening on changes to make auto-expanded editor
505 cm.on("change", function(self) {
505 cm.on("change", function (self) {
506 var height = initialHeight;
506 var height = initialHeight;
507 var lines = self.lineCount();
507 var lines = self.lineCount();
508 if ( lines > 6 && lines < 20) {
508 if (lines > 6 && lines < 20) {
509 height = "auto";
509 height = "auto";
510 }
510 } else if (lines >= 20) {
511 else if (lines >= 20){
511 height = 20 * 15;
512 zheight = 20*15;
513 }
512 }
514 self.setSize(null, height);
513 self.setSize(null, height);
515 });
514 });
516
515
517 var actionHint = function(editor, options) {
516 var actionHint = function(editor, options) {
518
517
519 var cur = editor.getCursor();
518 var cur = editor.getCursor();
520 var curLine = editor.getLine(cur.line).slice(0, cur.ch);
519 var curLine = editor.getLine(cur.line).slice(0, cur.ch);
521
520
522 // match only on /+1 character minimum
521 // match only on /+1 character minimum
523 var tokenMatch = new RegExp('(^/\|/\)([a-zA-Z]*)$').exec(curLine);
522 var tokenMatch = new RegExp('(^/\|/\)([a-zA-Z]*)$').exec(curLine);
524
523
525 var tokenStr = '';
524 var tokenStr = '';
526 if (tokenMatch !== null && tokenMatch.length > 0){
525 if (tokenMatch !== null && tokenMatch.length > 0){
527 tokenStr = tokenMatch[2].strip();
526 tokenStr = tokenMatch[2].strip();
528 }
527 }
529
528
530 var context = {
529 var context = {
531 start: (cur.ch - tokenStr.length) - 1,
530 start: (cur.ch - tokenStr.length) - 1,
532 end: cur.ch,
531 end: cur.ch,
533 string: tokenStr,
532 string: tokenStr,
534 type: null
533 type: null
535 };
534 };
536
535
537 return {
536 return {
538 list: filterActions(options.registeredActions, context),
537 list: filterActions(options.registeredActions, context),
539 from: CodeMirror.Pos(cur.line, context.start),
538 from: CodeMirror.Pos(cur.line, context.start),
540 to: CodeMirror.Pos(cur.line, context.end)
539 to: CodeMirror.Pos(cur.line, context.end)
541 };
540 };
542
541
543 };
542 };
544 CodeMirror.registerHelper("hint", "mentions", CodeMirrorMentionHint);
543 CodeMirror.registerHelper("hint", "mentions", CodeMirrorMentionHint);
545 CodeMirror.registerHelper("hint", "actions", actionHint);
544 CodeMirror.registerHelper("hint", "actions", actionHint);
546 return cm;
545 return cm;
547 };
546 };
548
547
549 var setCodeMirrorMode = function(codeMirrorInstance, mode) {
548 var setCodeMirrorMode = function(codeMirrorInstance, mode) {
550 CodeMirror.autoLoadMode(codeMirrorInstance, mode);
549 CodeMirror.autoLoadMode(codeMirrorInstance, mode);
551 codeMirrorInstance.setOption("mode", mode);
550 codeMirrorInstance.setOption("mode", mode);
552 };
551 };
553
552
554 var setCodeMirrorLineWrap = function(codeMirrorInstance, line_wrap) {
553 var setCodeMirrorLineWrap = function(codeMirrorInstance, line_wrap) {
555 codeMirrorInstance.setOption("lineWrapping", line_wrap);
554 codeMirrorInstance.setOption("lineWrapping", line_wrap);
556 };
555 };
557
556
558 var setCodeMirrorModeFromSelect = function(
557 var setCodeMirrorModeFromSelect = function(
559 targetSelect, targetFileInput, codeMirrorInstance, callback){
558 targetSelect, targetFileInput, codeMirrorInstance, callback){
560
559
561 $(targetSelect).on('change', function(e) {
560 $(targetSelect).on('change', function(e) {
562 cmLog.debug('codemirror select2 mode change event !');
561 cmLog.debug('codemirror select2 mode change event !');
563 var selected = e.currentTarget;
562 var selected = e.currentTarget;
564 var node = selected.options[selected.selectedIndex];
563 var node = selected.options[selected.selectedIndex];
565 var mimetype = node.value;
564 var mimetype = node.value;
566 cmLog.debug('picked mimetype', mimetype);
565 cmLog.debug('picked mimetype', mimetype);
567 var new_mode = $(node).attr('mode');
566 var new_mode = $(node).attr('mode');
568 setCodeMirrorMode(codeMirrorInstance, new_mode);
567 setCodeMirrorMode(codeMirrorInstance, new_mode);
569 cmLog.debug('set new mode', new_mode);
568 cmLog.debug('set new mode', new_mode);
570
569
571 //propose filename from picked mode
570 //propose filename from picked mode
572 cmLog.debug('setting mimetype', mimetype);
571 cmLog.debug('setting mimetype', mimetype);
573 var proposed_ext = getExtFromMimeType(mimetype);
572 var proposed_ext = getExtFromMimeType(mimetype);
574 cmLog.debug('file input', $(targetFileInput).val());
573 cmLog.debug('file input', $(targetFileInput).val());
575 var file_data = getFilenameAndExt($(targetFileInput).val());
574 var file_data = getFilenameAndExt($(targetFileInput).val());
576 var filename = file_data.filename || 'filename1';
575 var filename = file_data.filename || 'filename1';
577 $(targetFileInput).val(filename + proposed_ext);
576 $(targetFileInput).val(filename + proposed_ext);
578 cmLog.debug('proposed file', filename + proposed_ext);
577 cmLog.debug('proposed file', filename + proposed_ext);
579
578
580
579
581 if (typeof(callback) === 'function') {
580 if (typeof(callback) === 'function') {
582 try {
581 try {
583 cmLog.debug('running callback', callback);
582 cmLog.debug('running callback', callback);
584 callback(filename, mimetype, new_mode);
583 callback(filename, mimetype, new_mode);
585 } catch (err) {
584 } catch (err) {
586 console.log('failed to run callback', callback, err);
585 console.log('failed to run callback', callback, err);
587 }
586 }
588 }
587 }
589 cmLog.debug('finish iteration...');
588 cmLog.debug('finish iteration...');
590 });
589 });
591 };
590 };
592
591
593 var setCodeMirrorModeFromInput = function(
592 var setCodeMirrorModeFromInput = function(
594 targetSelect, targetFileInput, codeMirrorInstance, callback) {
593 targetSelect, targetFileInput, codeMirrorInstance, callback) {
595
594
596 // on type the new filename set mode
595 // on type the new filename set mode
597 $(targetFileInput).on('keyup', function(e) {
596 $(targetFileInput).on('keyup', function(e) {
598 var file_data = getFilenameAndExt(this.value);
597 var file_data = getFilenameAndExt(this.value);
599 if (file_data.ext === null) {
598 if (file_data.ext === null) {
600 return;
599 return;
601 }
600 }
602
601
603 var mimetypes = getMimeTypeFromExt(file_data.ext, true);
602 var mimetypes = getMimeTypeFromExt(file_data.ext, true);
604 cmLog.debug('mimetype from file', file_data, mimetypes);
603 cmLog.debug('mimetype from file', file_data, mimetypes);
605 var detected_mode;
604 var detected_mode;
606 var detected_option;
605 var detected_option;
607 for (var i in mimetypes) {
606 for (var i in mimetypes) {
608 var mt = mimetypes[i];
607 var mt = mimetypes[i];
609 if (!detected_mode) {
608 if (!detected_mode) {
610 detected_mode = detectCodeMirrorMode(this.value, mt);
609 detected_mode = detectCodeMirrorMode(this.value, mt);
611 }
610 }
612
611
613 if (!detected_option) {
612 if (!detected_option) {
614 cmLog.debug('#mimetype option[value="{0}"]'.format(mt));
613 cmLog.debug('#mimetype option[value="{0}"]'.format(mt));
615 if ($(targetSelect).find('option[value="{0}"]'.format(mt)).length) {
614 if ($(targetSelect).find('option[value="{0}"]'.format(mt)).length) {
616 detected_option = mt;
615 detected_option = mt;
617 }
616 }
618 }
617 }
619 }
618 }
620
619
621 cmLog.debug('detected mode', detected_mode);
620 cmLog.debug('detected mode', detected_mode);
622 cmLog.debug('detected option', detected_option);
621 cmLog.debug('detected option', detected_option);
623 if (detected_mode && detected_option){
622 if (detected_mode && detected_option){
624
623
625 $(targetSelect).select2("val", detected_option);
624 $(targetSelect).select2("val", detected_option);
626 setCodeMirrorMode(codeMirrorInstance, detected_mode);
625 setCodeMirrorMode(codeMirrorInstance, detected_mode);
627
626
628 if(typeof(callback) === 'function'){
627 if(typeof(callback) === 'function'){
629 try{
628 try{
630 cmLog.debug('running callback', callback);
629 cmLog.debug('running callback', callback);
631 var filename = file_data.filename + "." + file_data.ext;
630 var filename = file_data.filename + "." + file_data.ext;
632 callback(filename, detected_option, detected_mode);
631 callback(filename, detected_option, detected_mode);
633 }catch (err){
632 }catch (err){
634 console.log('failed to run callback', callback, err);
633 console.log('failed to run callback', callback, err);
635 }
634 }
636 }
635 }
637 }
636 }
638
637
639 });
638 });
640 };
639 };
641
640
642 var fillCodeMirrorOptions = function(targetSelect) {
641 var fillCodeMirrorOptions = function(targetSelect) {
643 //inject new modes, based on codeMirrors modeInfo object
642 //inject new modes, based on codeMirrors modeInfo object
644 var modes_select = $(targetSelect);
643 var modes_select = $(targetSelect);
645 for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
644 for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
646 var m = CodeMirror.modeInfo[i];
645 var m = CodeMirror.modeInfo[i];
647 var opt = new Option(m.name, m.mime);
646 var opt = new Option(m.name, m.mime);
648 $(opt).attr('mode', m.mode);
647 $(opt).attr('mode', m.mode);
649 modes_select.append(opt);
648 modes_select.append(opt);
650 }
649 }
651 };
650 };
652
651
653
652
654 /* markup form */
653 /* markup form */
655 (function(mod) {
654 (function(mod) {
656
655
657 if (typeof exports == "object" && typeof module == "object") {
656 if (typeof exports == "object" && typeof module == "object") {
658 // CommonJS
657 // CommonJS
659 module.exports = mod();
658 module.exports = mod();
660 }
659 }
661 else {
660 else {
662 // Plain browser env
661 // Plain browser env
663 (this || window).MarkupForm = mod();
662 (this || window).MarkupForm = mod();
664 }
663 }
665
664
666 })(function() {
665 })(function() {
667 "use strict";
666 "use strict";
668
667
669 function MarkupForm(textareaId) {
668 function MarkupForm(textareaId) {
670 if (!(this instanceof MarkupForm)) {
669 if (!(this instanceof MarkupForm)) {
671 return new MarkupForm(textareaId);
670 return new MarkupForm(textareaId);
672 }
671 }
673
672
674 // bind the element instance to our Form
673 // bind the element instance to our Form
675 $('#' + textareaId).get(0).MarkupForm = this;
674 $('#' + textareaId).get(0).MarkupForm = this;
676
675
677 this.withSelectorId = function(selector) {
676 this.withSelectorId = function(selector) {
678 var selectorId = textareaId;
677 var selectorId = textareaId;
679 return selector + '_' + selectorId;
678 return selector + '_' + selectorId;
680 };
679 };
681
680
682 this.previewButton = this.withSelectorId('#preview-btn');
681 this.previewButton = this.withSelectorId('#preview-btn');
683 this.previewContainer = this.withSelectorId('#preview-container');
682 this.previewContainer = this.withSelectorId('#preview-container');
684
683
685 this.previewBoxSelector = this.withSelectorId('#preview-box');
684 this.previewBoxSelector = this.withSelectorId('#preview-box');
686
685
687 this.editButton = this.withSelectorId('#edit-btn');
686 this.editButton = this.withSelectorId('#edit-btn');
688 this.editContainer = this.withSelectorId('#edit-container');
687 this.editContainer = this.withSelectorId('#edit-container');
689
688
690 this.cmBox = textareaId;
689 this.cmBox = textareaId;
691 this.cm = initMarkupCodeMirror('#' + textareaId);
690 this.cm = initMarkupCodeMirror('#' + textareaId);
692
691
693 this.previewUrl = pyroutes.url('markup_preview');
692 this.previewUrl = pyroutes.url('markup_preview');
694
693
695 // FUNCTIONS and helpers
694 // FUNCTIONS and helpers
696 var self = this;
695 var self = this;
697
696
698 this.getCmInstance = function(){
697 this.getCmInstance = function(){
699 return this.cm
698 return this.cm
700 };
699 };
701
700
702 this.setPlaceholder = function(placeholder) {
701 this.setPlaceholder = function(placeholder) {
703 var cm = this.getCmInstance();
702 var cm = this.getCmInstance();
704 if (cm){
703 if (cm){
705 cm.setOption('placeholder', placeholder);
704 cm.setOption('placeholder', placeholder);
706 }
705 }
707 };
706 };
708
707
709 this.initStatusChangeSelector = function(){
708 this.initStatusChangeSelector = function(){
710 var formatChangeStatus = function(state, escapeMarkup) {
709 var formatChangeStatus = function(state, escapeMarkup) {
711 var originalOption = state.element;
710 var originalOption = state.element;
712 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
711 var tmpl = '<i class="icon-circle review-status-{0}"></i><span>{1}</span>'.format($(originalOption).data('status'), escapeMarkup(state.text));
713 return tmpl
712 return tmpl
714 };
713 };
715 var formatResult = function(result, container, query, escapeMarkup) {
714 var formatResult = function(result, container, query, escapeMarkup) {
716 return formatChangeStatus(result, escapeMarkup);
715 return formatChangeStatus(result, escapeMarkup);
717 };
716 };
718
717
719 var formatSelection = function(data, container, escapeMarkup) {
718 var formatSelection = function(data, container, escapeMarkup) {
720 return formatChangeStatus(data, escapeMarkup);
719 return formatChangeStatus(data, escapeMarkup);
721 };
720 };
722
721
723 $(this.submitForm).find(this.statusChange).select2({
722 $(this.submitForm).find(this.statusChange).select2({
724 placeholder: _gettext('Status Review'),
723 placeholder: _gettext('Status Review'),
725 formatResult: formatResult,
724 formatResult: formatResult,
726 formatSelection: formatSelection,
725 formatSelection: formatSelection,
727 containerCssClass: "drop-menu status_box_menu",
726 containerCssClass: "drop-menu status_box_menu",
728 dropdownCssClass: "drop-menu-dropdown",
727 dropdownCssClass: "drop-menu-dropdown",
729 dropdownAutoWidth: true,
728 dropdownAutoWidth: true,
730 minimumResultsForSearch: -1
729 minimumResultsForSearch: -1
731 });
730 });
732 $(this.submitForm).find(this.statusChange).on('change', function() {
731 $(this.submitForm).find(this.statusChange).on('change', function() {
733 var status = self.getCommentStatus();
732 var status = self.getCommentStatus();
734
733
735 if (status && !self.isInline()) {
734 if (status && !self.isInline()) {
736 $(self.submitButton).prop('disabled', false);
735 $(self.submitButton).prop('disabled', false);
737 }
736 }
738
737
739 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
738 var placeholderText = _gettext('Comment text will be set automatically based on currently selected status ({0}) ...').format(status);
740 self.setPlaceholder(placeholderText)
739 self.setPlaceholder(placeholderText)
741 })
740 })
742 };
741 };
743
742
744 // reset the text area into it's original state
743 // reset the text area into it's original state
745 this.resetMarkupFormState = function(content) {
744 this.resetMarkupFormState = function(content) {
746 content = content || '';
745 content = content || '';
747
746
748 $(this.editContainer).show();
747 $(this.editContainer).show();
749 $(this.editButton).parent().addClass('active');
748 $(this.editButton).parent().addClass('active');
750
749
751 $(this.previewContainer).hide();
750 $(this.previewContainer).hide();
752 $(this.previewButton).parent().removeClass('active');
751 $(this.previewButton).parent().removeClass('active');
753
752
754 this.setActionButtonsDisabled(true);
753 this.setActionButtonsDisabled(true);
755 self.cm.setValue(content);
754 self.cm.setValue(content);
756 self.cm.setOption("readOnly", false);
755 self.cm.setOption("readOnly", false);
757 };
756 };
758
757
759 this.previewSuccessCallback = function(o) {
758 this.previewSuccessCallback = function(o) {
760 $(self.previewBoxSelector).html(o);
759 $(self.previewBoxSelector).html(o);
761 $(self.previewBoxSelector).removeClass('unloaded');
760 $(self.previewBoxSelector).removeClass('unloaded');
762
761
763 // swap buttons, making preview active
762 // swap buttons, making preview active
764 $(self.previewButton).parent().addClass('active');
763 $(self.previewButton).parent().addClass('active');
765 $(self.editButton).parent().removeClass('active');
764 $(self.editButton).parent().removeClass('active');
766
765
767 // unlock buttons
766 // unlock buttons
768 self.setActionButtonsDisabled(false);
767 self.setActionButtonsDisabled(false);
769 };
768 };
770
769
771 this.setActionButtonsDisabled = function(state) {
770 this.setActionButtonsDisabled = function(state) {
772 $(this.editButton).prop('disabled', state);
771 $(this.editButton).prop('disabled', state);
773 $(this.previewButton).prop('disabled', state);
772 $(this.previewButton).prop('disabled', state);
774 };
773 };
775
774
776 // lock preview/edit/submit buttons on load, but exclude cancel button
775 // lock preview/edit/submit buttons on load, but exclude cancel button
777 var excludeCancelBtn = true;
776 var excludeCancelBtn = true;
778 this.setActionButtonsDisabled(true);
777 this.setActionButtonsDisabled(true);
779
778
780 // anonymous users don't have access to initialized CM instance
779 // anonymous users don't have access to initialized CM instance
781 if (this.cm !== undefined){
780 if (this.cm !== undefined){
782 this.cm.on('change', function(cMirror) {
781 this.cm.on('change', function(cMirror) {
783 if (cMirror.getValue() === "") {
782 if (cMirror.getValue() === "") {
784 self.setActionButtonsDisabled(true)
783 self.setActionButtonsDisabled(true)
785 } else {
784 } else {
786 self.setActionButtonsDisabled(false)
785 self.setActionButtonsDisabled(false)
787 }
786 }
788 });
787 });
789 }
788 }
790
789
791 $(this.editButton).on('click', function(e) {
790 $(this.editButton).on('click', function(e) {
792 e.preventDefault();
791 e.preventDefault();
793
792
794 $(self.previewButton).parent().removeClass('active');
793 $(self.previewButton).parent().removeClass('active');
795 $(self.previewContainer).hide();
794 $(self.previewContainer).hide();
796
795
797 $(self.editButton).parent().addClass('active');
796 $(self.editButton).parent().addClass('active');
798 $(self.editContainer).show();
797 $(self.editContainer).show();
799
798
800 });
799 });
801
800
802 $(this.previewButton).on('click', function(e) {
801 $(this.previewButton).on('click', function(e) {
803 e.preventDefault();
802 e.preventDefault();
804 var text = self.cm.getValue();
803 var text = self.cm.getValue();
805
804
806 if (text === "") {
805 if (text === "") {
807 return;
806 return;
808 }
807 }
809
808
810 var postData = {
809 var postData = {
811 'text': text,
810 'text': text,
812 'renderer': templateContext.visual.default_renderer,
811 'renderer': templateContext.visual.default_renderer,
813 'csrf_token': CSRF_TOKEN
812 'csrf_token': CSRF_TOKEN
814 };
813 };
815
814
816 // lock ALL buttons on preview
815 // lock ALL buttons on preview
817 self.setActionButtonsDisabled(true);
816 self.setActionButtonsDisabled(true);
818
817
819 $(self.previewBoxSelector).addClass('unloaded');
818 $(self.previewBoxSelector).addClass('unloaded');
820 $(self.previewBoxSelector).html(_gettext('Loading ...'));
819 $(self.previewBoxSelector).html(_gettext('Loading ...'));
821
820
822 $(self.editContainer).hide();
821 $(self.editContainer).hide();
823 $(self.previewContainer).show();
822 $(self.previewContainer).show();
824
823
825 // by default we reset state of comment preserving the text
824 // by default we reset state of comment preserving the text
826 var previewFailCallback = function(data){
825 var previewFailCallback = function(data){
827 alert(
826 alert(
828 "Error while submitting preview.\n" +
827 "Error while submitting preview.\n" +
829 "Error code {0} ({1}).".format(data.status, data.statusText)
828 "Error code {0} ({1}).".format(data.status, data.statusText)
830 );
829 );
831 self.resetMarkupFormState(text)
830 self.resetMarkupFormState(text)
832 };
831 };
833 _submitAjaxPOST(
832 _submitAjaxPOST(
834 self.previewUrl, postData, self.previewSuccessCallback,
833 self.previewUrl, postData, self.previewSuccessCallback,
835 previewFailCallback);
834 previewFailCallback);
836
835
837 $(self.previewButton).parent().addClass('active');
836 $(self.previewButton).parent().addClass('active');
838 $(self.editButton).parent().removeClass('active');
837 $(self.editButton).parent().removeClass('active');
839 });
838 });
840
839
841 }
840 }
842
841
843 return MarkupForm;
842 return MarkupForm;
844 });
843 });
General Comments 0
You need to be logged in to leave comments. Login now