##// END OF EJS Templates
Added server side file editing with commit
marcink -
r1305:166317d4 beta
parent child Browse files
Show More
@@ -0,0 +1,54 b''
1 .CodeMirror {
2 overflow: auto;
3 height: 450px;
4 line-height: 1em;
5 font-family: monospace;
6 _position: relative; /* IE6 hack */
7 }
8
9 .CodeMirror-gutter {
10 position: absolute; left: 0; top: 0;
11 background-color: #f7f7f7;
12 border-right: 1px solid #eee;
13 min-width: 2em;
14 height: 100%;
15 }
16 .CodeMirror-gutter-text {
17 color: #aaa;
18 text-align: right;
19 padding: .4em .2em .4em .4em;
20 }
21 .CodeMirror-lines {
22 padding: .4em;
23 }
24
25 .CodeMirror pre {
26 -moz-border-radius: 0;
27 -webkit-border-radius: 0;
28 -o-border-radius: 0;
29 border-radius: 0;
30 border-width: 0; margin: 0; padding: 0; background: transparent;
31 font-family: inherit;
32 }
33
34 .CodeMirror-cursor {
35 z-index: 10;
36 position: absolute;
37 visibility: hidden;
38 border-left: 1px solid black !important;
39 }
40 .CodeMirror-focused .CodeMirror-cursor {
41 visibility: visible;
42 }
43
44 span.CodeMirror-selected {
45 background: #ccc !important;
46 color: HighlightText !important;
47 }
48 .CodeMirror-focused span.CodeMirror-selected {
49 background: Highlight !important;
50 }
51
52 .CodeMirror-matchingbracket {color: #0f0 !important;}
53 .CodeMirror-nonmatchingbracket {color: #f22 !important;}
54 .CodeMirror-gutter-text{color: #003367 !important;} No newline at end of file
This diff has been collapsed as it changes many lines, (1915 lines changed) Show them Hide them
@@ -0,0 +1,1915 b''
1 // All functions that need access to the editor's state live inside
2 // the CodeMirror function. Below that, at the bottom of the file,
3 // some utilities are defined.
4
5 // CodeMirror is the only global var we claim
6 var CodeMirror = (function() {
7 // This is the function that produces an editor instance. It's
8 // closure is used to store the editor state.
9 function CodeMirror(place, givenOptions) {
10 // Determine effective options based on given values and defaults.
11 var options = {}, defaults = CodeMirror.defaults;
12 for (var opt in defaults)
13 if (defaults.hasOwnProperty(opt))
14 options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
15
16 // The element in which the editor lives. Takes care of scrolling
17 // (if enabled).
18 var wrapper = document.createElement("div");
19 wrapper.className = "CodeMirror";
20 // This mess creates the base DOM structure for the editor.
21 wrapper.innerHTML =
22 '<div style="position: relative">' + // Set to the height of the text, causes scrolling
23 '<pre style="position: relative; height: 0; visibility: hidden; overflow: hidden;">' + // To measure line/char size
24 '<span>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></pre>' +
25 '<div style="position: relative">' + // Moved around its parent to cover visible view
26 '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
27 '<div style="overflow: hidden; position: absolute; width: 0; left: 0">' + // Wraps and hides input textarea
28 '<textarea style="height: 1px; position: absolute; width: 1px;" wrap="off"></textarea></div>' +
29 // Provides positioning relative to (visible) text origin
30 '<div class="CodeMirror-lines"><div style="position: relative">' +
31 '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
32 '<div></div></div></div></div></div>'; // This DIV contains the actual code
33 if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
34 // I've never seen more elegant code in my life.
35 var code = wrapper.firstChild, measure = code.firstChild, mover = measure.nextSibling,
36 gutter = mover.firstChild, gutterText = gutter.firstChild,
37 inputDiv = gutter.nextSibling, input = inputDiv.firstChild,
38 lineSpace = inputDiv.nextSibling.firstChild, cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
39 if (options.tabindex != null) input.tabindex = options.tabindex;
40 if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
41
42 // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
43 var poll = new Delayed(), highlight = new Delayed(), blinker;
44
45 // mode holds a mode API object. lines an array of Line objects
46 // (see Line constructor), work an array of lines that should be
47 // parsed, and history the undo history (instance of History
48 // constructor).
49 var mode, lines = [new Line("")], work, history = new History(), focused;
50 loadMode();
51 // The selection. These are always maintained to point at valid
52 // positions. Inverted is used to remember that the user is
53 // selecting bottom-to-top.
54 var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
55 // Selection-related flags. shiftSelecting obviously tracks
56 // whether the user is holding shift. reducedSelection is a hack
57 // to get around the fact that we can't create inverted
58 // selections. See below.
59 var shiftSelecting, reducedSelection;
60 // Variables used by startOperation/endOperation to track what
61 // happened during the operation.
62 var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
63 // Current visible range (may be bigger than the view window).
64 var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
65 // editing will hold an object describing the things we put in the
66 // textarea, to help figure out whether something changed.
67 // bracketHighlighted is used to remember that a backet has been
68 // marked.
69 var editing, bracketHighlighted;
70
71 // Initialize the content. Somewhat hacky (delayed prepareInput)
72 // to work around browser issues.
73 operation(function(){setValue(options.value || ""); updateInput = false;})();
74 setTimeout(prepareInput, 20);
75
76 // Register our event handlers.
77 connect(wrapper, "mousedown", operation(onMouseDown));
78 // Gecko browsers fire contextmenu *after* opening the menu, at
79 // which point we can't mess with it anymore. Context menu is
80 // handled in onMouseDown for Gecko.
81 if (!gecko) connect(wrapper, "contextmenu", operation(onContextMenu));
82 connect(code, "dblclick", operation(onDblClick));
83 connect(wrapper, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
84 connect(window, "resize", function() {updateDisplay(true);});
85 connect(input, "keyup", operation(onKeyUp));
86 connect(input, "keydown", operation(onKeyDown));
87 connect(input, "keypress", operation(onKeyPress));
88 connect(input, "focus", onFocus);
89 connect(input, "blur", onBlur);
90
91 connect(wrapper, "dragenter", function(e){e.stop();});
92 connect(wrapper, "dragover", function(e){e.stop();});
93 connect(wrapper, "drop", operation(onDrop));
94 connect(wrapper, "paste", function(){input.focus(); fastPoll();});
95 connect(input, "paste", function(){fastPoll();});
96 connect(input, "cut", function(){fastPoll();});
97
98 if (document.activeElement == input) onFocus();
99 else onBlur();
100
101 function isLine(l) {return l >= 0 && l < lines.length;}
102 // The instance object that we'll return. Mostly calls out to
103 // local functions in the CodeMirror function. Some do some extra
104 // range checking and/or clipping. operation is used to wrap the
105 // call so that changes it makes are tracked, and the display is
106 // updated afterwards.
107 var instance = {
108 getValue: getValue,
109 setValue: operation(setValue),
110 getSelection: getSelection,
111 replaceSelection: operation(replaceSelection),
112 focus: function(){input.focus(); onFocus(); fastPoll();},
113 setOption: function(option, value) {
114 options[option] = value;
115 if (option == "lineNumbers" || option == "gutter") gutterChanged();
116 else if (option == "mode" || option == "indentUnit") loadMode();
117 },
118 getOption: function(option) {return options[option];},
119 undo: operation(undo),
120 redo: operation(redo),
121 indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
122 historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
123 matchBrackets: operation(function(){matchBrackets(true);}),
124 getTokenAt: function(pos) {
125 pos = clipPos(pos);
126 return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
127 },
128 cursorCoords: function(start){
129 if (start == null) start = sel.inverted;
130 return pageCoords(start ? sel.from : sel.to);
131 },
132 charCoords: function(pos){return pageCoords(clipPos(pos));},
133 coordsChar: function(coords) {
134 var off = eltOffset(lineSpace);
135 var line = Math.min(showingTo - 1, showingFrom + Math.floor(coords.y / lineHeight()));
136 return clipPos({line: line, ch: charFromX(clipLine(line), coords.x)});
137 },
138 getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
139 markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
140 setMarker: addGutterMarker,
141 clearMarker: removeGutterMarker,
142 setLineClass: operation(setLineClass),
143 lineInfo: lineInfo,
144 addWidget: function(pos, node, scroll) {
145 var pos = localCoords(clipPos(pos), true);
146 node.style.top = (showingFrom * lineHeight() + pos.yBot + paddingTop()) + "px";
147 node.style.left = (pos.x + paddingLeft()) + "px";
148 code.appendChild(node);
149 if (scroll)
150 scrollIntoView(pos.x, pos.yBot, pos.x + node.offsetWidth, pos.yBot + node.offsetHeight);
151 },
152
153 lineCount: function() {return lines.length;},
154 getCursor: function(start) {
155 if (start == null) start = sel.inverted;
156 return copyPos(start ? sel.from : sel.to);
157 },
158 somethingSelected: function() {return !posEq(sel.from, sel.to);},
159 setCursor: operation(function(line, ch) {
160 if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
161 else setCursor(line, ch);
162 }),
163 setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
164 getLine: function(line) {if (isLine(line)) return lines[line].text;},
165 setLine: operation(function(line, text) {
166 if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
167 }),
168 removeLine: operation(function(line) {
169 if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
170 }),
171 replaceRange: operation(replaceRange),
172 getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
173
174 operation: function(f){return operation(f)();},
175 refresh: function(){updateDisplay(true);},
176 getInputField: function(){return input;},
177 getWrapperElement: function(){return wrapper;}
178 };
179
180 function setValue(code) {
181 history = null;
182 var top = {line: 0, ch: 0};
183 updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
184 splitLines(code), top, top);
185 history = new History();
186 }
187 function getValue(code) {
188 var text = [];
189 for (var i = 0, l = lines.length; i < l; ++i)
190 text.push(lines[i].text);
191 return text.join("\n");
192 }
193
194 function onMouseDown(e) {
195 // First, see if this is a click in the gutter
196 for (var n = e.target(); n != wrapper; n = n.parentNode)
197 if (n.parentNode == gutterText) {
198 if (options.onGutterClick)
199 options.onGutterClick(instance, indexOf(gutterText.childNodes, n) + showingFrom);
200 return e.stop();
201 }
202
203 if (gecko && e.button() == 3) onContextMenu(e);
204 if (e.button() != 1) return;
205 // For button 1, if it was clicked inside the editor
206 // (posFromMouse returning non-null), we have to adjust the
207 // selection.
208 var start = posFromMouse(e), last = start, going;
209 if (!start) {if (e.target() == wrapper) e.stop(); return;}
210 setCursor(start.line, start.ch, false);
211
212 if (!focused) onFocus();
213 e.stop();
214 // And then we have to see if it's a drag event, in which case
215 // the dragged-over text must be selected.
216 function end() {
217 input.focus();
218 updateInput = true;
219 move(); up();
220 }
221 function extend(e) {
222 var cur = posFromMouse(e, true);
223 if (cur && !posEq(cur, last)) {
224 if (!focused) onFocus();
225 last = cur;
226 setSelection(start, cur);
227 updateInput = false;
228 var visible = visibleLines();
229 if (cur.line >= visible.to || cur.line < visible.from)
230 going = setTimeout(operation(function(){extend(e);}), 150);
231 }
232 }
233
234 var move = connect(document, "mousemove", operation(function(e) {
235 clearTimeout(going);
236 e.stop();
237 extend(e);
238 }), true);
239 var up = connect(document, "mouseup", operation(function(e) {
240 clearTimeout(going);
241 var cur = posFromMouse(e);
242 if (cur) setSelection(start, cur);
243 e.stop();
244 end();
245 }), true);
246 }
247 function onDblClick(e) {
248 var pos = posFromMouse(e);
249 if (!pos) return;
250 selectWordAt(pos);
251 e.stop();
252 }
253 function onDrop(e) {
254 var pos = posFromMouse(e, true), files = e.e.dataTransfer.files;
255 if (!pos || options.readOnly) return;
256 if (files && files.length && window.FileReader && window.File) {
257 var n = files.length, text = Array(n), read = 0;
258 for (var i = 0; i < n; ++i) loadFile(files[i], i);
259 function loadFile(file, i) {
260 var reader = new FileReader;
261 reader.onload = function() {
262 text[i] = reader.result;
263 if (++read == n) replaceRange(text.join(""), clipPos(pos), clipPos(pos));
264 };
265 reader.readAsText(file);
266 }
267 }
268 else {
269 try {
270 var text = e.e.dataTransfer.getData("Text");
271 if (text) replaceRange(text, pos, pos);
272 }
273 catch(e){}
274 }
275 }
276 function onKeyDown(e) {
277 if (!focused) onFocus();
278
279 var code = e.e.keyCode;
280 // Tries to detect ctrl on non-mac, cmd on mac.
281 var mod = (mac ? e.e.metaKey : e.e.ctrlKey) && !e.e.altKey, anyMod = e.e.ctrlKey || e.e.altKey || e.e.metaKey;
282 if (code == 16 || e.e.shiftKey) shiftSelecting = shiftSelecting || (sel.inverted ? sel.to : sel.from);
283 else shiftSelecting = null;
284 // First give onKeyEvent option a chance to handle this.
285 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e.e))) return;
286
287 if (code == 33 || code == 34) {scrollPage(code == 34); return e.stop();} // page up/down
288 if (mod && (code == 36 || code == 35)) {scrollEnd(code == 36); return e.stop();} // ctrl-home/end
289 if (mod && code == 65) {selectAll(); return e.stop();} // ctrl-a
290 if (!options.readOnly) {
291 if (!anyMod && code == 13) {return;} // enter
292 if (!anyMod && code == 9 && handleTab(e.e.shiftKey)) return e.stop(); // tab
293 if (mod && code == 90) {undo(); return e.stop();} // ctrl-z
294 if (mod && ((e.e.shiftKey && code == 90) || code == 89)) {redo(); return e.stop();} // ctrl-shift-z, ctrl-y
295 }
296
297 // Key id to use in the movementKeys map. We also pass it to
298 // fastPoll in order to 'self learn'. We need this because
299 // reducedSelection, the hack where we collapse the selection to
300 // its start when it is inverted and a movement key is pressed
301 // (and later restore it again), shouldn't be used for
302 // non-movement keys.
303 curKeyId = (mod ? "c" : "") + code;
304 if (sel.inverted && movementKeys.hasOwnProperty(curKeyId)) {
305 var range = selRange(input);
306 if (range) {
307 reducedSelection = {anchor: range.start};
308 setSelRange(input, range.start, range.start);
309 }
310 }
311 fastPoll(curKeyId);
312 }
313 function onKeyUp(e) {
314 if (reducedSelection) {
315 reducedSelection = null;
316 updateInput = true;
317 }
318 if (e.e.keyCode == 16) shiftSelecting = null;
319 }
320 function onKeyPress(e) {
321 if (options.onKeyEvent && options.onKeyEvent(instance, addStop(e.e))) return;
322 if (options.electricChars && mode.electricChars) {
323 var ch = String.fromCharCode(e.e.charCode == null ? e.e.keyCode : e.e.charCode);
324 if (mode.electricChars.indexOf(ch) > -1)
325 setTimeout(operation(function() {indentLine(sel.to.line, "smart");}), 50);
326 }
327 var code = e.e.keyCode;
328 // Re-stop tab and enter. Necessary on some browsers.
329 if (code == 13) {handleEnter(); e.stop();}
330 else if (code == 9 && options.tabMode != "default") e.stop();
331 else fastPoll(curKeyId);
332 }
333
334 function onFocus() {
335 if (!focused && options.onFocus) options.onFocus(instance);
336 focused = true;
337 slowPoll();
338 if (wrapper.className.search(/\bCodeMirror-focused\b/) == -1)
339 wrapper.className += " CodeMirror-focused";
340 restartBlink();
341 }
342 function onBlur() {
343 if (focused && options.onBlur) options.onBlur(instance);
344 clearInterval(blinker);
345 shiftSelecting = null;
346 focused = false;
347 wrapper.className = wrapper.className.replace(" CodeMirror-focused", "");
348 }
349
350 // Replace the range from from to to by the strings in newText.
351 // Afterwards, set the selection to selFrom, selTo.
352 function updateLines(from, to, newText, selFrom, selTo) {
353 if (history) {
354 var old = [];
355 for (var i = from.line, e = to.line + 1; i < e; ++i) old.push(lines[i].text);
356 history.addChange(from.line, newText.length, old);
357 while (history.done.length > options.undoDepth) history.done.shift();
358 }
359 updateLinesNoUndo(from, to, newText, selFrom, selTo);
360 }
361 function unredoHelper(from, to) {
362 var change = from.pop();
363 if (change) {
364 var replaced = [], end = change.start + change.added;
365 for (var i = change.start; i < end; ++i) replaced.push(lines[i].text);
366 to.push({start: change.start, added: change.old.length, old: replaced});
367 var pos = clipPos({line: change.start + change.old.length - 1,
368 ch: editEnd(replaced[replaced.length-1], change.old[change.old.length-1])});
369 updateLinesNoUndo({line: change.start, ch: 0}, {line: end - 1, ch: lines[end-1].text.length}, change.old, pos, pos);
370 }
371 }
372 function undo() {unredoHelper(history.done, history.undone);}
373 function redo() {unredoHelper(history.undone, history.done);}
374
375 function updateLinesNoUndo(from, to, newText, selFrom, selTo) {
376 var nlines = to.line - from.line, firstLine = lines[from.line], lastLine = lines[to.line];
377 // First adjust the line structure, taking some care to leave highlighting intact.
378 if (firstLine == lastLine) {
379 if (newText.length == 1)
380 firstLine.replace(from.ch, to.ch, newText[0]);
381 else {
382 lastLine = firstLine.split(to.ch, newText[newText.length-1]);
383 var spliceargs = [from.line + 1, nlines];
384 firstLine.replace(from.ch, firstLine.text.length, newText[0]);
385 for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
386 spliceargs.push(lastLine);
387 lines.splice.apply(lines, spliceargs);
388 }
389 }
390 else if (newText.length == 1) {
391 firstLine.replace(from.ch, firstLine.text.length, newText[0] + lastLine.text.slice(to.ch));
392 lines.splice(from.line + 1, nlines);
393 }
394 else {
395 var spliceargs = [from.line + 1, nlines - 1];
396 firstLine.replace(from.ch, firstLine.text.length, newText[0]);
397 lastLine.replace(0, to.ch, newText[newText.length-1]);
398 for (var i = 1, e = newText.length - 1; i < e; ++i) spliceargs.push(new Line(newText[i]));
399 lines.splice.apply(lines, spliceargs);
400 }
401
402 // Add these lines to the work array, so that they will be
403 // highlighted. Adjust work lines if lines were added/removed.
404 var newWork = [], lendiff = newText.length - nlines - 1;
405 for (var i = 0, l = work.length; i < l; ++i) {
406 var task = work[i];
407 if (task < from.line) newWork.push(task);
408 else if (task > to.line) newWork.push(task + lendiff);
409 }
410 if (newText.length) newWork.push(from.line);
411 work = newWork;
412 startWorker(100);
413 // Remember that these lines changed, for updating the display
414 changes.push({from: from.line, to: to.line + 1, diff: lendiff});
415 textChanged = true;
416
417 // Update the selection
418 function updateLine(n) {return n <= Math.min(to.line, to.line + lendiff) ? n : n + lendiff;}
419 setSelection(selFrom, selTo, updateLine(sel.from.line), updateLine(sel.to.line));
420
421 // Make sure the scroll-size div has the correct height.
422 code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
423 }
424
425 function replaceRange(code, from, to) {
426 from = clipPos(from);
427 if (!to) to = from; else to = clipPos(to);
428 code = splitLines(code);
429 function adjustPos(pos) {
430 if (posLess(pos, from)) return pos;
431 if (!posLess(to, pos)) return end;
432 var line = pos.line + code.length - (to.line - from.line) - 1;
433 var ch = pos.ch;
434 if (pos.line == to.line)
435 ch += code[code.length-1].length - (to.ch - (to.line == from.line ? from.ch : 0));
436 return {line: line, ch: ch};
437 }
438 var end;
439 replaceRange1(code, from, to, function(end1) {
440 end = end1;
441 return {from: adjustPos(sel.from), to: adjustPos(sel.to)};
442 });
443 return end;
444 }
445 function replaceSelection(code, collapse) {
446 replaceRange1(splitLines(code), sel.from, sel.to, function(end) {
447 if (collapse == "end") return {from: end, to: end};
448 else if (collapse == "start") return {from: sel.from, to: sel.from};
449 else return {from: sel.from, to: end};
450 });
451 }
452 function replaceRange1(code, from, to, computeSel) {
453 var endch = code.length == 1 ? code[0].length + from.ch : code[code.length-1].length;
454 var newSel = computeSel({line: from.line + code.length - 1, ch: endch});
455 updateLines(from, to, code, newSel.from, newSel.to);
456 }
457
458 function getRange(from, to) {
459 var l1 = from.line, l2 = to.line;
460 if (l1 == l2) return lines[l1].text.slice(from.ch, to.ch);
461 var code = [lines[l1].text.slice(from.ch)];
462 for (var i = l1 + 1; i < l2; ++i) code.push(lines[i].text);
463 code.push(lines[l2].text.slice(0, to.ch));
464 return code.join("\n");
465 }
466 function getSelection() {
467 return getRange(sel.from, sel.to);
468 }
469
470 var pollingFast = false; // Ensures slowPoll doesn't cancel fastPoll
471 function slowPoll() {
472 if (pollingFast) return;
473 poll.set(2000, function() {
474 startOperation();
475 readInput();
476 if (focused) slowPoll();
477 endOperation();
478 });
479 }
480 function fastPoll(keyId) {
481 var missed = false;
482 pollingFast = true;
483 function p() {
484 startOperation();
485 var changed = readInput();
486 if (changed == "moved" && keyId) movementKeys[keyId] = true;
487 if (!changed && !missed) {missed = true; poll.set(80, p);}
488 else {pollingFast = false; slowPoll();}
489 endOperation();
490 }
491 poll.set(20, p);
492 }
493
494 // Inspects the textarea, compares its state (content, selection)
495 // to the data in the editing variable, and updates the editor
496 // content or cursor if something changed.
497 function readInput() {
498 var changed = false, text = input.value, sr = selRange(input);
499 if (!sr) return false;
500 var changed = editing.text != text, rs = reducedSelection;
501 var moved = changed || sr.start != editing.start || sr.end != (rs ? editing.start : editing.end);
502 if (reducedSelection && !moved && sel.from.line == 0 && sel.from.ch == 0)
503 reducedSelection = null;
504 else if (!moved) return false;
505 if (changed) {
506 shiftSelecting = reducedSelection = null;
507 if (options.readOnly) {updateInput = true; return "changed";}
508 }
509
510 // Compute selection start and end based on start/end offsets in textarea
511 function computeOffset(n, startLine) {
512 var pos = 0;
513 for (;;) {
514 var found = text.indexOf("\n", pos);
515 if (found == -1 || (text.charAt(found-1) == "\r" ? found - 1 : found) >= n)
516 return {line: startLine, ch: n - pos};
517 ++startLine;
518 pos = found + 1;
519 }
520 }
521 var from = computeOffset(sr.start, editing.from),
522 to = computeOffset(sr.end, editing.from);
523 // Here we have to take the reducedSelection hack into account,
524 // so that you can, for example, press shift-up at the start of
525 // your selection and have the right thing happen.
526 if (rs) {
527 from = sr.start == rs.anchor ? to : from;
528 to = shiftSelecting ? sel.to : sr.start == rs.anchor ? from : to;
529 if (!posLess(from, to)) {
530 reducedSelection = null;
531 sel.inverted = false;
532 var tmp = from; from = to; to = tmp;
533 }
534 }
535
536 // In some cases (cursor on same line as before), we don't have
537 // to update the textarea content at all.
538 if (from.line == to.line && from.line == sel.from.line && from.line == sel.to.line && !shiftSelecting)
539 updateInput = false;
540
541 // Magic mess to extract precise edited range from the changed
542 // string.
543 if (changed) {
544 var start = 0, end = text.length, len = Math.min(end, editing.text.length);
545 var c, line = editing.from, nl = -1;
546 while (start < len && (c = text.charAt(start)) == editing.text.charAt(start)) {
547 ++start;
548 if (c == "\n") {line++; nl = start;}
549 }
550 var ch = nl > -1 ? start - nl : start, endline = editing.to - 1, edend = editing.text.length;
551 for (;;) {
552 c = editing.text.charAt(edend);
553 if (c == "\n") endline--;
554 if (text.charAt(end) != c) {++end; ++edend; break;}
555 if (edend <= start || end <= start) break;
556 --end; --edend;
557 }
558 var nl = editing.text.lastIndexOf("\n", edend - 1), endch = nl == -1 ? edend : edend - nl - 1;
559 updateLines({line: line, ch: ch}, {line: endline, ch: endch}, splitLines(text.slice(start, end)), from, to);
560 if (line != endline || from.line != line) updateInput = true;
561 }
562 else setSelection(from, to);
563
564 editing.text = text; editing.start = sr.start; editing.end = sr.end;
565 return changed ? "changed" : moved ? "moved" : false;
566 }
567
568 // Set the textarea content and selection range to match the
569 // editor state.
570 function prepareInput() {
571 var text = [];
572 var from = Math.max(0, sel.from.line - 1), to = Math.min(lines.length, sel.to.line + 2);
573 for (var i = from; i < to; ++i) text.push(lines[i].text);
574 text = input.value = text.join(lineSep);
575 var startch = sel.from.ch, endch = sel.to.ch;
576 for (var i = from; i < sel.from.line; ++i)
577 startch += lineSep.length + lines[i].text.length;
578 for (var i = from; i < sel.to.line; ++i)
579 endch += lineSep.length + lines[i].text.length;
580 editing = {text: text, from: from, to: to, start: startch, end: endch};
581 setSelRange(input, startch, reducedSelection ? startch : endch);
582 }
583
584 function scrollCursorIntoView() {
585 var cursor = localCoords(sel.inverted ? sel.from : sel.to);
586 return scrollIntoView(cursor.x, cursor.y, cursor.x, cursor.yBot);
587 }
588 function scrollIntoView(x1, y1, x2, y2) {
589 var pl = paddingLeft(), pt = paddingTop();
590 y1 += pt; y2 += pt; x1 += pl; x2 += pl;
591 var screen = wrapper.clientHeight, screentop = wrapper.scrollTop, scrolled = false, result = true;
592 if (y1 < screentop) {wrapper.scrollTop = Math.max(0, y1 - 10); scrolled = true;}
593 else if (y2 > screentop + screen) {wrapper.scrollTop = y2 + 10 - screen; scrolled = true;}
594
595 var screenw = wrapper.clientWidth, screenleft = wrapper.scrollLeft;
596 if (x1 < screenleft) {wrapper.scrollLeft = Math.max(0, x1 - 10); scrolled = true;}
597 else if (x2 > screenw + screenleft) {
598 wrapper.scrollLeft = x2 + 10 - screenw;
599 scrolled = true;
600 if (x2 > code.clientWidth) result = false;
601 }
602 if (scrolled && options.onScroll) options.onScroll(instance);
603 return result;
604 }
605
606 function visibleLines() {
607 var lh = lineHeight(), top = wrapper.scrollTop - paddingTop();
608 return {from: Math.min(lines.length, Math.max(0, Math.floor(top / lh))),
609 to: Math.min(lines.length, Math.ceil((top + wrapper.clientHeight) / lh))};
610 }
611 // Uses a set of changes plus the current scroll position to
612 // determine which DOM updates have to be made, and makes the
613 // updates.
614 function updateDisplay(changes) {
615 if (!wrapper.clientWidth) {
616 showingFrom = showingTo = 0;
617 return;
618 }
619 // First create a range of theoretically intact lines, and punch
620 // holes in that using the change info.
621 var intact = changes === true ? [] : [{from: showingFrom, to: showingTo, domStart: 0}];
622 for (var i = 0, l = changes.length || 0; i < l; ++i) {
623 var change = changes[i], intact2 = [], diff = change.diff || 0;
624 for (var j = 0, l2 = intact.length; j < l2; ++j) {
625 var range = intact[j];
626 if (change.to <= range.from)
627 intact2.push({from: range.from + diff, to: range.to + diff, domStart: range.domStart});
628 else if (range.to <= change.from)
629 intact2.push(range);
630 else {
631 if (change.from > range.from)
632 intact2.push({from: range.from, to: change.from, domStart: range.domStart})
633 if (change.to < range.to)
634 intact2.push({from: change.to + diff, to: range.to + diff,
635 domStart: range.domStart + (change.to - range.from)});
636 }
637 }
638 intact = intact2;
639 }
640
641 // Then, determine which lines we'd want to see, and which
642 // updates have to be made to get there.
643 var visible = visibleLines();
644 var from = Math.min(showingFrom, Math.max(visible.from - 3, 0)),
645 to = Math.min(lines.length, Math.max(showingTo, visible.to + 3)),
646 updates = [], domPos = 0, domEnd = showingTo - showingFrom, pos = from, changedLines = 0;
647
648 for (var i = 0, l = intact.length; i < l; ++i) {
649 var range = intact[i];
650 if (range.to <= from) continue;
651 if (range.from >= to) break;
652 if (range.domStart > domPos || range.from > pos) {
653 updates.push({from: pos, to: range.from, domSize: range.domStart - domPos, domStart: domPos});
654 changedLines += range.from - pos;
655 }
656 pos = range.to;
657 domPos = range.domStart + (range.to - range.from);
658 }
659 if (domPos != domEnd || pos != to) {
660 changedLines += Math.abs(to - pos);
661 updates.push({from: pos, to: to, domSize: domEnd - domPos, domStart: domPos});
662 }
663
664 if (!updates.length) return;
665 lineDiv.style.display = "none";
666 // If more than 30% of the screen needs update, just do a full
667 // redraw (which is quicker than patching)
668 if (changedLines > (visible.to - visible.from) * .3)
669 refreshDisplay(from = Math.max(visible.from - 10, 0), to = Math.min(visible.to + 7, lines.length));
670 // Otherwise, only update the stuff that needs updating.
671 else
672 patchDisplay(updates);
673 lineDiv.style.display = "";
674
675 // Position the mover div to align with the lines it's supposed
676 // to be showing (which will cover the visible display)
677 var different = from != showingFrom || to != showingTo || lastHeight != wrapper.clientHeight;
678 showingFrom = from; showingTo = to;
679 mover.style.top = (from * lineHeight()) + "px";
680 if (different) {
681 lastHeight = wrapper.clientHeight;
682 code.style.height = (lines.length * lineHeight() + 2 * paddingTop()) + "px";
683 updateGutter();
684 }
685
686 // Since this is all rather error prone, it is honoured with the
687 // only assertion in the whole file.
688 if (lineDiv.childNodes.length != showingTo - showingFrom)
689 throw new Error("BAD PATCH! " + JSON.stringify(updates) + " size=" + (showingTo - showingFrom) +
690 " nodes=" + lineDiv.childNodes.length);
691 updateCursor();
692 }
693
694 function refreshDisplay(from, to) {
695 var html = [], start = {line: from, ch: 0}, inSel = posLess(sel.from, start) && !posLess(sel.to, start);
696 for (var i = from; i < to; ++i) {
697 var ch1 = null, ch2 = null;
698 if (inSel) {
699 ch1 = 0;
700 if (sel.to.line == i) {inSel = false; ch2 = sel.to.ch;}
701 }
702 else if (sel.from.line == i) {
703 if (sel.to.line == i) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
704 else {inSel = true; ch1 = sel.from.ch;}
705 }
706 html.push(lines[i].getHTML(ch1, ch2, true));
707 }
708 lineDiv.innerHTML = html.join("");
709 }
710 function patchDisplay(updates) {
711 // Slightly different algorithm for IE (badInnerHTML), since
712 // there .innerHTML on PRE nodes is dumb, and discards
713 // whitespace.
714 var sfrom = sel.from.line, sto = sel.to.line, off = 0,
715 scratch = badInnerHTML && document.createElement("div");
716 for (var i = 0, e = updates.length; i < e; ++i) {
717 var rec = updates[i];
718 var extra = (rec.to - rec.from) - rec.domSize;
719 var nodeAfter = lineDiv.childNodes[rec.domStart + rec.domSize + off] || null;
720 if (badInnerHTML)
721 for (var j = Math.max(-extra, rec.domSize); j > 0; --j)
722 lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
723 else if (extra) {
724 for (var j = Math.max(0, extra); j > 0; --j)
725 lineDiv.insertBefore(document.createElement("pre"), nodeAfter);
726 for (var j = Math.max(0, -extra); j > 0; --j)
727 lineDiv.removeChild(nodeAfter ? nodeAfter.previousSibling : lineDiv.lastChild);
728 }
729 var node = lineDiv.childNodes[rec.domStart + off], inSel = sfrom < rec.from && sto >= rec.from;
730 for (var j = rec.from; j < rec.to; ++j) {
731 var ch1 = null, ch2 = null;
732 if (inSel) {
733 ch1 = 0;
734 if (sto == j) {inSel = false; ch2 = sel.to.ch;}
735 }
736 else if (sfrom == j) {
737 if (sto == j) {ch1 = sel.from.ch; ch2 = sel.to.ch;}
738 else {inSel = true; ch1 = sel.from.ch;}
739 }
740 if (badInnerHTML) {
741 scratch.innerHTML = lines[j].getHTML(ch1, ch2, true);
742 lineDiv.insertBefore(scratch.firstChild, nodeAfter);
743 }
744 else {
745 node.innerHTML = lines[j].getHTML(ch1, ch2, false);
746 node.className = lines[j].className || "";
747 node = node.nextSibling;
748 }
749 }
750 off += extra;
751 }
752 }
753
754 function updateGutter() {
755 if (!options.gutter && !options.lineNumbers) return;
756 var hText = mover.offsetHeight, hEditor = wrapper.clientHeight;
757 gutter.style.height = (hText - hEditor < 2 ? hEditor : hText) + "px";
758 var html = [];
759 for (var i = showingFrom; i < showingTo; ++i) {
760 var marker = lines[i].gutterMarker;
761 var text = options.lineNumbers ? i + options.firstLineNumber : null;
762 if (marker && marker.text)
763 text = marker.text.replace("%N%", text != null ? text : "");
764 else if (text == null)
765 text = "\u00a0";
766 html.push((marker && marker.style ? '<pre class="' + marker.style + '">' : "<pre>"), text, "</pre>");
767 }
768 gutter.style.display = "none";
769 gutterText.innerHTML = html.join("");
770 var minwidth = String(lines.length).length, firstNode = gutterText.firstChild, val = eltText(firstNode), pad = "";
771 while (val.length + pad.length < minwidth) pad += "\u00a0";
772 if (pad) firstNode.insertBefore(document.createTextNode(pad), firstNode.firstChild);
773 gutter.style.display = "";
774 lineSpace.style.marginLeft = gutter.offsetWidth + "px";
775 }
776 function updateCursor() {
777 var head = sel.inverted ? sel.from : sel.to;
778 var x = charX(head.line, head.ch) + "px", y = (head.line - showingFrom) * lineHeight() + "px";
779 inputDiv.style.top = y; inputDiv.style.left = x;
780 if (posEq(sel.from, sel.to)) {
781 cursor.style.top = y; cursor.style.left = x;
782 cursor.style.display = "";
783 }
784 else cursor.style.display = "none";
785 }
786
787 // Update the selection. Last two args are only used by
788 // updateLines, since they have to be expressed in the line
789 // numbers before the update.
790 function setSelection(from, to, oldFrom, oldTo) {
791 if (posEq(sel.from, from) && posEq(sel.to, to)) return;
792 var sh = shiftSelecting && clipPos(shiftSelecting);
793 if (posLess(to, from)) {var tmp = to; to = from; from = tmp;}
794 if (sh) {
795 if (posLess(sh, from)) from = sh;
796 else if (posLess(to, sh)) to = sh;
797 }
798
799 var startEq = posEq(sel.to, to), endEq = posEq(sel.from, from);
800 if (posEq(from, to)) sel.inverted = false;
801 else if (startEq && !endEq) sel.inverted = true;
802 else if (endEq && !startEq) sel.inverted = false;
803
804 // Some ugly logic used to only mark the lines that actually did
805 // see a change in selection as changed, rather than the whole
806 // selected range.
807 if (oldFrom == null) {oldFrom = sel.from.line; oldTo = sel.to.line;}
808 if (posEq(from, to)) {
809 if (!posEq(sel.from, sel.to))
810 changes.push({from: oldFrom, to: oldTo + 1});
811 }
812 else if (posEq(sel.from, sel.to)) {
813 changes.push({from: from.line, to: to.line + 1});
814 }
815 else {
816 if (!posEq(from, sel.from)) {
817 if (from.line < oldFrom)
818 changes.push({from: from.line, to: Math.min(to.line, oldFrom) + 1});
819 else
820 changes.push({from: oldFrom, to: Math.min(oldTo, from.line) + 1});
821 }
822 if (!posEq(to, sel.to)) {
823 if (to.line < oldTo)
824 changes.push({from: Math.max(oldFrom, from.line), to: oldTo + 1});
825 else
826 changes.push({from: Math.max(from.line, oldTo), to: to.line + 1});
827 }
828 }
829 sel.from = from; sel.to = to;
830 selectionChanged = true;
831 }
832 function setCursor(line, ch) {
833 var pos = clipPos({line: line, ch: ch || 0});
834 setSelection(pos, pos);
835 }
836
837 function clipLine(n) {return Math.max(0, Math.min(n, lines.length-1));}
838 function clipPos(pos) {
839 if (pos.line < 0) return {line: 0, ch: 0};
840 if (pos.line >= lines.length) return {line: lines.length-1, ch: lines[lines.length-1].text.length};
841 var ch = pos.ch, linelen = lines[pos.line].text.length;
842 if (ch == null || ch > linelen) return {line: pos.line, ch: linelen};
843 else if (ch < 0) return {line: pos.line, ch: 0};
844 else return pos;
845 }
846
847 function scrollPage(down) {
848 var linesPerPage = Math.floor(wrapper.clientHeight / lineHeight()), head = sel.inverted ? sel.from : sel.to;
849 setCursor(head.line + (Math.max(linesPerPage - 1, 1) * (down ? 1 : -1)), head.ch);
850 }
851 function scrollEnd(top) {
852 setCursor(top ? 0 : lines.length - 1);
853 }
854 function selectAll() {
855 var endLine = lines.length - 1;
856 setSelection({line: 0, ch: 0}, {line: endLine, ch: lines[endLine].text.length});
857 }
858 function selectWordAt(pos) {
859 var line = lines[pos.line].text;
860 var start = pos.ch, end = pos.ch;
861 while (start > 0 && /\w/.test(line.charAt(start - 1))) --start;
862 while (end < line.length - 1 && /\w/.test(line.charAt(end))) ++end;
863 setSelection({line: pos.line, ch: start}, {line: pos.line, ch: end});
864 }
865 function handleEnter() {
866 replaceSelection("\n", "end");
867 if (options.enterMode != "flat")
868 indentLine(sel.from.line, options.enterMode == "keep" ? "prev" : "smart");
869 }
870 function handleTab(shift) {
871 shiftSelecting = null;
872 switch (options.tabMode) {
873 case "default":
874 return false;
875 case "indent":
876 for (var i = sel.from.line, e = sel.to.line; i <= e; ++i) indentLine(i, "smart");
877 break;
878 case "classic":
879 if (posEq(sel.from, sel.to)) {
880 if (shift) indentLine(sel.from.line, "smart");
881 else replaceSelection("\t", "end");
882 break;
883 }
884 case "shift":
885 for (var i = sel.from.line, e = sel.to.line; i <= e; ++i) indentLine(i, shift ? "subtract" : "add");
886 break;
887 }
888 return true;
889 }
890
891 function indentLine(n, how) {
892 if (how == "smart") {
893 if (!mode.indent) how = "prev";
894 else var state = getStateBefore(n);
895 }
896
897 var line = lines[n], curSpace = line.indentation(), curSpaceString = line.text.match(/^\s*/)[0], indentation;
898 if (how == "prev") {
899 if (n) indentation = lines[n-1].indentation();
900 else indentation = 0;
901 }
902 else if (how == "smart") indentation = mode.indent(state, line.text.slice(curSpaceString.length));
903 else if (how == "add") indentation = curSpace + options.indentUnit;
904 else if (how == "subtract") indentation = curSpace - options.indentUnit;
905 indentation = Math.max(0, indentation);
906 var diff = indentation - curSpace;
907
908 if (!diff) {
909 if (sel.from.line != n && sel.to.line != n) return;
910 var indentString = curSpaceString;
911 }
912 else {
913 var indentString = "", pos = 0;
914 if (options.indentWithTabs)
915 for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
916 while (pos < indentation) {++pos; indentString += " ";}
917 }
918
919 replaceRange(indentString, {line: n, ch: 0}, {line: n, ch: curSpaceString.length});
920 }
921
922 function loadMode() {
923 mode = CodeMirror.getMode(options, options.mode);
924 for (var i = 0, l = lines.length; i < l; ++i)
925 lines[i].stateAfter = null;
926 work = [0];
927 }
928 function gutterChanged() {
929 var visible = options.gutter || options.lineNumbers;
930 gutter.style.display = visible ? "" : "none";
931 if (visible) updateGutter();
932 else lineDiv.parentNode.style.marginLeft = 0;
933 }
934
935 function markText(from, to, className) {
936 from = clipPos(from); to = clipPos(to);
937 var accum = [];
938 function add(line, from, to, className) {
939 var line = lines[line], mark = line.addMark(from, to, className);
940 mark.line = line;
941 accum.push(mark);
942 }
943 if (from.line == to.line) add(from.line, from.ch, to.ch, className);
944 else {
945 add(from.line, from.ch, null, className);
946 for (var i = from.line + 1, e = to.line; i < e; ++i)
947 add(i, 0, null, className);
948 add(to.line, 0, to.ch, className);
949 }
950 changes.push({from: from.line, to: to.line + 1});
951 return function() {
952 var start, end;
953 for (var i = 0; i < accum.length; ++i) {
954 var mark = accum[i], found = indexOf(lines, mark.line);
955 mark.line.removeMark(mark);
956 if (found > -1) {
957 if (start == null) start = found;
958 end = found;
959 }
960 }
961 if (start != null) changes.push({from: start, to: end + 1});
962 };
963 }
964
965 function addGutterMarker(line, text, className) {
966 if (typeof line == "number") line = lines[clipLine(line)];
967 line.gutterMarker = {text: text, style: className};
968 updateGutter();
969 return line;
970 }
971 function removeGutterMarker(line) {
972 if (typeof line == "number") line = lines[clipLine(line)];
973 line.gutterMarker = null;
974 updateGutter();
975 }
976 function setLineClass(line, className) {
977 if (typeof line == "number") {
978 var no = line;
979 line = lines[clipLine(line)];
980 }
981 else {
982 var no = indexOf(lines, line);
983 if (no == -1) return null;
984 }
985 line.className = className;
986 changes.push({from: no, to: no + 1});
987 return line;
988 }
989
990 function lineInfo(line) {
991 if (typeof line == "number") {
992 var n = line;
993 line = lines[line];
994 if (!line) return null;
995 }
996 else {
997 var n = indexOf(lines, line);
998 if (n == -1) return null;
999 }
1000 var marker = line.gutterMarker;
1001 return {line: n, text: line.text, markerText: marker && marker.text, markerClass: marker && marker.style};
1002 }
1003
1004 // These are used to go from pixel positions to character
1005 // positions, taking tabs into account.
1006 function charX(line, pos) {
1007 var text = lines[line].text, span = measure.firstChild;
1008 if (text.lastIndexOf("\t", pos) == -1) return pos * charWidth();
1009 var old = span.firstChild.nodeValue;
1010 try {
1011 span.firstChild.nodeValue = text.slice(0, pos);
1012 return span.offsetWidth;
1013 } finally {span.firstChild.nodeValue = old;}
1014 }
1015 function charFromX(line, x) {
1016 var text = lines[line].text, cw = charWidth();
1017 if (x <= 0) return 0;
1018 if (text.indexOf("\t") == -1) return Math.min(text.length, Math.round(x / cw));
1019 var mspan = measure.firstChild, mtext = mspan.firstChild, old = mtext.nodeValue;
1020 try {
1021 mtext.nodeValue = text;
1022 var from = 0, fromX = 0, to = text.length, toX = mspan.offsetWidth;
1023 if (x > toX) return to;
1024 for (;;) {
1025 if (to - from <= 1) return (toX - x > x - fromX) ? from : to;
1026 var middle = Math.ceil((from + to) / 2);
1027 mtext.nodeValue = text.slice(0, middle);
1028 var curX = mspan.offsetWidth;
1029 if (curX > x) {to = middle; toX = curX;}
1030 else {from = middle; fromX = curX;}
1031 }
1032 } finally {mtext.nodeValue = old;}
1033 }
1034
1035 function localCoords(pos, inLineWrap) {
1036 var lh = lineHeight(), line = pos.line - (inLineWrap ? showingFrom : 0);
1037 return {x: charX(pos.line, pos.ch), y: line * lh, yBot: (line + 1) * lh};
1038 }
1039 function pageCoords(pos) {
1040 var local = localCoords(pos, true), off = eltOffset(lineSpace);
1041 return {x: off.left + local.x, y: off.top + local.y, yBot: off.top + local.yBot};
1042 }
1043
1044 function lineHeight() {
1045 var nlines = lineDiv.childNodes.length;
1046 if (nlines) return lineDiv.offsetHeight / nlines;
1047 else return measure.firstChild.offsetHeight || 1;
1048 }
1049 function charWidth() {return (measure.firstChild.offsetWidth || 320) / 40;}
1050 function paddingTop() {return lineSpace.offsetTop;}
1051 function paddingLeft() {return lineSpace.offsetLeft;}
1052
1053 function posFromMouse(e, liberal) {
1054 var off = eltOffset(lineSpace),
1055 x = e.pageX() - off.left,
1056 y = e.pageY() - off.top;
1057 if (!liberal && e.target() != lineSpace.parentNode && !(e.target() == wrapper && y > (lines.length * lineHeight())))
1058 for (var n = e.target(); n != lineDiv && n != cursor; n = n.parentNode)
1059 if (!n || n == wrapper) return null;
1060 var line = showingFrom + Math.floor(y / lineHeight());
1061 return clipPos({line: line, ch: charFromX(clipLine(line), x)});
1062 }
1063 function onContextMenu(e) {
1064 var pos = posFromMouse(e);
1065 if (!pos || window.opera) return; // Opera is difficult.
1066 if (posEq(sel.from, sel.to) || posLess(pos, sel.from) || !posLess(pos, sel.to))
1067 setCursor(pos.line, pos.ch);
1068
1069 var oldCSS = input.style.cssText;
1070 input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.pageY() - 1) +
1071 "px; left: " + (e.pageX() - 1) + "px; z-index: 1000; background: white; " +
1072 "border-width: 0; outline: none; overflow: hidden;";
1073 var val = input.value = getSelection();
1074 input.focus();
1075 setSelRange(input, 0, val.length);
1076 if (gecko) e.stop();
1077 leaveInputAlone = true;
1078 setTimeout(function() {
1079 if (input.value != val) operation(replaceSelection)(input.value, "end");
1080 input.style.cssText = oldCSS;
1081 leaveInputAlone = false;
1082 prepareInput();
1083 slowPoll();
1084 }, 50);
1085 }
1086
1087 // Cursor-blinking
1088 function restartBlink() {
1089 clearInterval(blinker);
1090 var on = true;
1091 cursor.style.visibility = "";
1092 blinker = setInterval(function() {
1093 cursor.style.visibility = (on = !on) ? "" : "hidden";
1094 }, 650);
1095 }
1096
1097 var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
1098 function matchBrackets(autoclear) {
1099 var head = sel.inverted ? sel.from : sel.to, line = lines[head.line], pos = head.ch - 1;
1100 var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
1101 if (!match) return;
1102 var ch = match.charAt(0), forward = match.charAt(1) == ">", d = forward ? 1 : -1, st = line.styles;
1103 for (var off = pos + 1, i = 0, e = st.length; i < e; i+=2)
1104 if ((off -= st[i].length) <= 0) {var style = st[i+1]; break;}
1105
1106 var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
1107 function scan(line, from, to) {
1108 if (!line.text) return;
1109 var st = line.styles, pos = forward ? 0 : line.text.length - 1, cur;
1110 for (var i = forward ? 0 : st.length - 2, e = forward ? st.length : -2; i != e; i += 2*d) {
1111 var text = st[i];
1112 if (st[i+1] != null && st[i+1] != style) {pos += d * text.length; continue;}
1113 for (var j = forward ? 0 : text.length - 1, te = forward ? text.length : -1; j != te; j += d, pos+=d) {
1114 if (pos >= from && pos < to && re.test(cur = text.charAt(j))) {
1115 var match = matching[cur];
1116 if (match.charAt(1) == ">" == forward) stack.push(cur);
1117 else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
1118 else if (!stack.length) return {pos: pos, match: true};
1119 }
1120 }
1121 }
1122 }
1123 for (var i = head.line, e = forward ? Math.min(i + 50, lines.length) : Math.max(0, i - 50); i != e; i+=d) {
1124 var line = lines[i], first = i == head.line;
1125 var found = scan(line, first && forward ? pos + 1 : 0, first && !forward ? pos : line.text.length);
1126 if (found) {
1127 var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
1128 var one = markText({line: head.line, ch: pos}, {line: head.line, ch: pos+1}, style),
1129 two = markText({line: i, ch: found.pos}, {line: i, ch: found.pos + 1}, style);
1130 var clear = operation(function(){one(); two();});
1131 if (autoclear) setTimeout(clear, 800);
1132 else bracketHighlighted = clear;
1133 break;
1134 }
1135 }
1136 }
1137
1138 // Finds the line to start with when starting a parse. Tries to
1139 // find a line with a stateAfter, so that it can start with a
1140 // valid state. If that fails, it returns the line with the
1141 // smallest indentation, which tends to need the least context to
1142 // parse correctly.
1143 function findStartLine(n) {
1144 var minindent, minline;
1145 for (var search = n, lim = n - 40; search > lim; --search) {
1146 if (search == 0) return 0;
1147 var line = lines[search-1];
1148 if (line.stateAfter) return search;
1149 var indented = line.indentation();
1150 if (minline == null || minindent > indented) {
1151 minline = search;
1152 minindent = indented;
1153 }
1154 }
1155 return minline;
1156 }
1157 function getStateBefore(n) {
1158 var start = findStartLine(n), state = start && lines[start-1].stateAfter;
1159 if (!state) state = startState(mode);
1160 else state = copyState(mode, state);
1161 for (var i = start; i < n; ++i) {
1162 var line = lines[i];
1163 line.highlight(mode, state);
1164 line.stateAfter = copyState(mode, state);
1165 }
1166 if (!lines[n].stateAfter) work.push(n);
1167 return state;
1168 }
1169 function highlightWorker() {
1170 var end = +new Date + options.workTime;
1171 while (work.length) {
1172 if (!lines[showingFrom].stateAfter) var task = showingFrom;
1173 else var task = work.pop();
1174 if (task >= lines.length) continue;
1175 var start = findStartLine(task), state = start && lines[start-1].stateAfter;
1176 if (state) state = copyState(mode, state);
1177 else state = startState(mode);
1178
1179 for (var i = start, l = lines.length; i < l; ++i) {
1180 var line = lines[i], hadState = line.stateAfter;
1181 if (+new Date > end) {
1182 work.push(i);
1183 startWorker(options.workDelay);
1184 changes.push({from: task, to: i});
1185 return;
1186 }
1187 var changed = line.highlight(mode, state);
1188 line.stateAfter = copyState(mode, state);
1189 if (hadState && !changed && line.text) break;
1190 }
1191 changes.push({from: task, to: i});
1192 }
1193 }
1194 function startWorker(time) {
1195 if (!work.length) return;
1196 highlight.set(time, operation(highlightWorker));
1197 }
1198
1199 // Operations are used to wrap changes in such a way that each
1200 // change won't have to update the cursor and display (which would
1201 // be awkward, slow, and error-prone), but instead updates are
1202 // batched and then all combined and executed at once.
1203 function startOperation() {
1204 updateInput = null; changes = []; textChanged = selectionChanged = false;
1205 }
1206 function endOperation() {
1207 var reScroll = false;
1208 if (selectionChanged) reScroll = !scrollCursorIntoView();
1209 if (changes.length) updateDisplay(changes);
1210 else if (selectionChanged) updateCursor();
1211 if (reScroll) scrollCursorIntoView();
1212 if (selectionChanged) restartBlink();
1213
1214 // updateInput can be set to a boolean value to force/prevent an
1215 // update.
1216 if (!leaveInputAlone && (updateInput === true || (updateInput !== false && selectionChanged)))
1217 prepareInput();
1218
1219 if (selectionChanged && options.onCursorActivity)
1220 options.onCursorActivity(instance);
1221 if (textChanged && options.onChange)
1222 options.onChange(instance);
1223 if (selectionChanged && options.matchBrackets)
1224 setTimeout(operation(function() {
1225 if (bracketHighlighted) {bracketHighlighted(); bracketHighlighted = null;}
1226 matchBrackets(false);
1227 }), 20);
1228 }
1229 var nestedOperation = 0;
1230 function operation(f) {
1231 return function() {
1232 if (!nestedOperation++) startOperation();
1233 try {var result = f.apply(this, arguments);}
1234 finally {if (!--nestedOperation) endOperation();}
1235 return result;
1236 };
1237 }
1238
1239 function SearchCursor(query, pos, caseFold) {
1240 this.atOccurrence = false;
1241 if (caseFold == null) caseFold = typeof query == "string" && query == query.toLowerCase();
1242
1243 if (pos && typeof pos == "object") pos = clipPos(pos);
1244 else pos = {line: 0, ch: 0};
1245 this.pos = {from: pos, to: pos};
1246
1247 // The matches method is filled in based on the type of query.
1248 // It takes a position and a direction, and returns an object
1249 // describing the next occurrence of the query, or null if no
1250 // more matches were found.
1251 if (typeof query != "string") // Regexp match
1252 this.matches = function(reverse, pos) {
1253 if (reverse) {
1254 var line = lines[pos.line].text.slice(0, pos.ch), match = line.match(query), start = 0;
1255 while (match) {
1256 var ind = line.indexOf(match[0]);
1257 start += ind;
1258 line = line.slice(ind + 1);
1259 var newmatch = line.match(query);
1260 if (newmatch) match = newmatch;
1261 else break;
1262 }
1263 }
1264 else {
1265 var line = lines[pos.line].text.slice(pos.ch), match = line.match(query),
1266 start = match && pos.ch + line.indexOf(match[0]);
1267 }
1268 if (match)
1269 return {from: {line: pos.line, ch: start},
1270 to: {line: pos.line, ch: start + match[0].length},
1271 match: match};
1272 };
1273 else { // String query
1274 if (caseFold) query = query.toLowerCase();
1275 var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
1276 var target = query.split("\n");
1277 // Different methods for single-line and multi-line queries
1278 if (target.length == 1)
1279 this.matches = function(reverse, pos) {
1280 var line = fold(lines[pos.line].text), len = query.length, match;
1281 if (reverse ? (pos.ch >= len && (match = line.lastIndexOf(query, pos.ch - len)) != -1)
1282 : (match = line.indexOf(query, pos.ch)) != -1)
1283 return {from: {line: pos.line, ch: match},
1284 to: {line: pos.line, ch: match + len}};
1285 };
1286 else
1287 this.matches = function(reverse, pos) {
1288 var ln = pos.line, idx = (reverse ? target.length - 1 : 0), match = target[idx], line = fold(lines[ln].text);
1289 var offsetA = (reverse ? line.indexOf(match) + match.length : line.lastIndexOf(match));
1290 if (reverse ? offsetA >= pos.ch || offsetA != match.length
1291 : offsetA <= pos.ch || offsetA != line.length - match.length)
1292 return;
1293 for (;;) {
1294 if (reverse ? !ln : ln == lines.length - 1) return;
1295 line = fold(lines[ln += reverse ? -1 : 1].text);
1296 match = target[reverse ? --idx : ++idx];
1297 if (idx > 0 && idx < target.length - 1) {
1298 if (line != match) return;
1299 else continue;
1300 }
1301 var offsetB = (reverse ? line.lastIndexOf(match) : line.indexOf(match) + match.length);
1302 if (reverse ? offsetB != line.length - match.length : offsetB != match.length)
1303 return;
1304 var start = {line: pos.line, ch: offsetA}, end = {line: ln, ch: offsetB};
1305 return {from: reverse ? end : start, to: reverse ? start : end};
1306 }
1307 };
1308 }
1309 }
1310
1311 SearchCursor.prototype = {
1312 findNext: function() {return this.find(false);},
1313 findPrevious: function() {return this.find(true);},
1314
1315 find: function(reverse) {
1316 var self = this, pos = clipPos(reverse ? this.pos.from : this.pos.to);
1317 function savePosAndFail(line) {
1318 var pos = {line: line, ch: 0};
1319 self.pos = {from: pos, to: pos};
1320 self.atOccurrence = false;
1321 return false;
1322 }
1323
1324 for (;;) {
1325 if (this.pos = this.matches(reverse, pos)) {
1326 this.atOccurrence = true;
1327 return this.pos.match || true;
1328 }
1329 if (reverse) {
1330 if (!pos.line) return savePosAndFail(0);
1331 pos = {line: pos.line-1, ch: lines[pos.line-1].text.length};
1332 }
1333 else {
1334 if (pos.line == lines.length - 1) return savePosAndFail(lines.length);
1335 pos = {line: pos.line+1, ch: 0};
1336 }
1337 }
1338 },
1339
1340 from: function() {if (this.atOccurrence) return copyPos(this.pos.from);},
1341 to: function() {if (this.atOccurrence) return copyPos(this.pos.to);}
1342 };
1343
1344 return instance;
1345 } // (end of function CodeMirror)
1346
1347 // The default configuration options.
1348 CodeMirror.defaults = {
1349 value: "",
1350 mode: null,
1351 indentUnit: 2,
1352 indentWithTabs: false,
1353 tabMode: "classic",
1354 enterMode: "indent",
1355 electricChars: true,
1356 onKeyEvent: null,
1357 lineNumbers: false,
1358 gutter: false,
1359 firstLineNumber: 1,
1360 readOnly: false,
1361 onChange: null,
1362 onCursorActivity: null,
1363 onGutterClick: null,
1364 onFocus: null, onBlur: null, onScroll: null,
1365 matchBrackets: false,
1366 workTime: 100,
1367 workDelay: 200,
1368 undoDepth: 40,
1369 tabindex: null
1370 };
1371
1372 // Known modes, by name and by MIME
1373 var modes = {}, mimeModes = {};
1374 CodeMirror.defineMode = function(name, mode) {
1375 if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
1376 modes[name] = mode;
1377 };
1378 CodeMirror.defineMIME = function(mime, spec) {
1379 mimeModes[mime] = spec;
1380 };
1381 CodeMirror.getMode = function(options, spec) {
1382 if (typeof spec == "string" && mimeModes.hasOwnProperty(spec))
1383 spec = mimeModes[spec];
1384 if (typeof spec == "string")
1385 var mname = spec, config = {};
1386 else
1387 var mname = spec.name, config = spec;
1388 var mfactory = modes[mname];
1389 if (!mfactory) {
1390 if (window.console) console.warn("No mode " + mname + " found, falling back to plain text.");
1391 return CodeMirror.getMode(options, "text/plain");
1392 }
1393 return mfactory(options, config);
1394 }
1395 CodeMirror.listModes = function() {
1396 var list = [];
1397 for (var m in modes)
1398 if (modes.propertyIsEnumerable(m)) list.push(m);
1399 return list;
1400 };
1401 CodeMirror.listMIMEs = function() {
1402 var list = [];
1403 for (var m in mimeModes)
1404 if (mimeModes.propertyIsEnumerable(m)) list.push(m);
1405 return list;
1406 };
1407
1408 CodeMirror.fromTextArea = function(textarea, options) {
1409 if (!options) options = {};
1410 options.value = textarea.value;
1411 if (!options.tabindex && textarea.tabindex)
1412 options.tabindex = textarea.tabindex;
1413
1414 function save() {textarea.value = instance.getValue();}
1415 if (textarea.form) {
1416 // Deplorable hack to make the submit method do the right thing.
1417 var rmSubmit = connect(textarea.form, "submit", save, true);
1418 if (typeof textarea.form.submit == "function") {
1419 var realSubmit = textarea.form.submit;
1420 function wrappedSubmit() {
1421 save();
1422 textarea.form.submit = realSubmit;
1423 textarea.form.submit();
1424 textarea.form.submit = wrappedSubmit;
1425 }
1426 textarea.form.submit = wrappedSubmit;
1427 }
1428 }
1429
1430 textarea.style.display = "none";
1431 var instance = CodeMirror(function(node) {
1432 textarea.parentNode.insertBefore(node, textarea.nextSibling);
1433 }, options);
1434 instance.save = save;
1435 instance.toTextArea = function() {
1436 save();
1437 textarea.parentNode.removeChild(instance.getWrapperElement());
1438 textarea.style.display = "";
1439 if (textarea.form) {
1440 rmSubmit();
1441 if (typeof textarea.form.submit == "function")
1442 textarea.form.submit = realSubmit;
1443 }
1444 };
1445 return instance;
1446 };
1447
1448 // Utility functions for working with state. Exported because modes
1449 // sometimes need to do this.
1450 function copyState(mode, state) {
1451 if (state === true) return state;
1452 if (mode.copyState) return mode.copyState(state);
1453 var nstate = {};
1454 for (var n in state) {
1455 var val = state[n];
1456 if (val instanceof Array) val = val.concat([]);
1457 nstate[n] = val;
1458 }
1459 return nstate;
1460 }
1461 CodeMirror.startState = startState;
1462 function startState(mode, a1, a2) {
1463 return mode.startState ? mode.startState(a1, a2) : true;
1464 }
1465 CodeMirror.copyState = copyState;
1466
1467 // The character stream used by a mode's parser.
1468 function StringStream(string) {
1469 this.pos = this.start = 0;
1470 this.string = string;
1471 }
1472 StringStream.prototype = {
1473 eol: function() {return this.pos >= this.string.length;},
1474 sol: function() {return this.pos == 0;},
1475 peek: function() {return this.string.charAt(this.pos);},
1476 next: function() {
1477 if (this.pos < this.string.length)
1478 return this.string.charAt(this.pos++);
1479 },
1480 eat: function(match) {
1481 var ch = this.string.charAt(this.pos);
1482 if (typeof match == "string") var ok = ch == match;
1483 else var ok = ch && (match.test ? match.test(ch) : match(ch));
1484 if (ok) {++this.pos; return ch;}
1485 },
1486 eatWhile: function(match) {
1487 var start = this.start;
1488 while (this.eat(match)){}
1489 return this.pos > start;
1490 },
1491 eatSpace: function() {
1492 var start = this.pos;
1493 while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
1494 return this.pos > start;
1495 },
1496 skipToEnd: function() {this.pos = this.string.length;},
1497 skipTo: function(ch) {
1498 var found = this.string.indexOf(ch, this.pos);
1499 if (found > -1) {this.pos = found; return true;}
1500 },
1501 backUp: function(n) {this.pos -= n;},
1502 column: function() {return countColumn(this.string, this.start);},
1503 indentation: function() {return countColumn(this.string);},
1504 match: function(pattern, consume, caseInsensitive) {
1505 if (typeof pattern == "string") {
1506 function cased(str) {return caseInsensitive ? str.toLowerCase() : str;}
1507 if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
1508 if (consume !== false) this.pos += pattern.length;
1509 return true;
1510 }
1511 }
1512 else {
1513 var match = this.string.slice(this.pos).match(pattern);
1514 if (match && consume !== false) this.pos += match[0].length;
1515 return match;
1516 }
1517 },
1518 current: function(){return this.string.slice(this.start, this.pos);}
1519 };
1520
1521 // Line objects. These hold state related to a line, including
1522 // highlighting info (the styles array).
1523 function Line(text, styles) {
1524 this.styles = styles || [text, null];
1525 this.stateAfter = null;
1526 this.text = text;
1527 this.marked = this.gutterMarker = this.className = null;
1528 }
1529 Line.prototype = {
1530 // Replace a piece of a line, keeping the styles around it intact.
1531 replace: function(from, to, text) {
1532 var st = [], mk = this.marked;
1533 copyStyles(0, from, this.styles, st);
1534 if (text) st.push(text, null);
1535 copyStyles(to, this.text.length, this.styles, st);
1536 this.styles = st;
1537 this.text = this.text.slice(0, from) + text + this.text.slice(to);
1538 this.stateAfter = null;
1539 if (mk) {
1540 var diff = text.length - (to - from), end = this.text.length;
1541 function fix(n) {return n <= Math.min(to, to + diff) ? n : n + diff;}
1542 for (var i = 0; i < mk.length; ++i) {
1543 var mark = mk[i], del = false;
1544 if (mark.from >= end) del = true;
1545 else {mark.from = fix(mark.from); if (mark.to != null) mark.to = fix(mark.to);}
1546 if (del || mark.from >= mark.to) {mk.splice(i, 1); i--;}
1547 }
1548 }
1549 },
1550 // Split a line in two, again keeping styles intact.
1551 split: function(pos, textBefore) {
1552 var st = [textBefore, null];
1553 copyStyles(pos, this.text.length, this.styles, st);
1554 return new Line(textBefore + this.text.slice(pos), st);
1555 },
1556 addMark: function(from, to, style) {
1557 var mk = this.marked, mark = {from: from, to: to, style: style};
1558 if (this.marked == null) this.marked = [];
1559 this.marked.push(mark);
1560 this.marked.sort(function(a, b){return a.from - b.from;});
1561 return mark;
1562 },
1563 removeMark: function(mark) {
1564 var mk = this.marked;
1565 if (!mk) return;
1566 for (var i = 0; i < mk.length; ++i)
1567 if (mk[i] == mark) {mk.splice(i, 1); break;}
1568 },
1569 // Run the given mode's parser over a line, update the styles
1570 // array, which contains alternating fragments of text and CSS
1571 // classes.
1572 highlight: function(mode, state) {
1573 var stream = new StringStream(this.text), st = this.styles, pos = 0, changed = false;
1574 while (!stream.eol()) {
1575 var style = mode.token(stream, state);
1576 var substr = this.text.slice(stream.start, stream.pos);
1577 stream.start = stream.pos;
1578 if (pos && st[pos-1] == style)
1579 st[pos-2] += substr;
1580 else if (substr) {
1581 if (!changed && st[pos] != substr || st[pos+1] != style) changed = true;
1582 st[pos++] = substr; st[pos++] = style;
1583 }
1584 // Give up when line is ridiculously long
1585 if (stream.pos > 5000) {
1586 st[pos++] = this.text.slice(stream.pos); st[pos++] = null;
1587 break;
1588 }
1589 }
1590 if (st.length != pos) {st.length = pos; changed = true;}
1591 return changed;
1592 },
1593 // Fetch the parser token for a given character. Useful for hacks
1594 // that want to inspect the mode state (say, for completion).
1595 getTokenAt: function(mode, state, ch) {
1596 var txt = this.text, stream = new StringStream(txt);
1597 while (stream.pos < ch && !stream.eol()) {
1598 stream.start = stream.pos;
1599 var style = mode.token(stream, state);
1600 }
1601 return {start: stream.start,
1602 end: stream.pos,
1603 string: stream.current(),
1604 className: style || null,
1605 state: state};
1606 },
1607 indentation: function() {return countColumn(this.text);},
1608 // Produces an HTML fragment for the line, taking selection,
1609 // marking, and highlighting into account.
1610 getHTML: function(sfrom, sto, includePre) {
1611 var html = [];
1612 if (includePre)
1613 html.push(this.className ? '<pre class="' + this.className + '">': "<pre>");
1614 function span(text, style) {
1615 if (!text) return;
1616 if (style) html.push('<span class="', style, '">', htmlEscape(text), "</span>");
1617 else html.push(htmlEscape(text));
1618 }
1619 var st = this.styles, allText = this.text, marked = this.marked;
1620 if (sfrom == sto) sfrom = null;
1621
1622 if (!allText)
1623 span(" ", sfrom != null && sto == null ? "CodeMirror-selected" : null);
1624 else if (!marked && sfrom == null)
1625 for (var i = 0, e = st.length; i < e; i+=2) span(st[i], st[i+1]);
1626 else {
1627 var pos = 0, i = 0, text = "", style, sg = 0;
1628 var markpos = -1, mark = null;
1629 function nextMark() {
1630 if (marked) {
1631 markpos += 1;
1632 mark = (markpos < marked.length) ? marked[markpos] : null;
1633 }
1634 }
1635 nextMark();
1636 while (pos < allText.length) {
1637 var upto = allText.length;
1638 var extraStyle = "";
1639 if (sfrom != null) {
1640 if (sfrom > pos) upto = sfrom;
1641 else if (sto == null || sto > pos) {
1642 extraStyle = " CodeMirror-selected";
1643 if (sto != null) upto = Math.min(upto, sto);
1644 }
1645 }
1646 while (mark && mark.to != null && mark.to <= pos) nextMark();
1647 if (mark) {
1648 if (mark.from > pos) upto = Math.min(upto, mark.from);
1649 else {
1650 extraStyle += " " + mark.style;
1651 if (mark.to != null) upto = Math.min(upto, mark.to);
1652 }
1653 }
1654 for (;;) {
1655 var end = pos + text.length;
1656 var apliedStyle = style;
1657 if (extraStyle) apliedStyle = style ? style + extraStyle : extraStyle;
1658 span(end > upto ? text.slice(0, upto - pos) : text, apliedStyle);
1659 if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
1660 pos = end;
1661 text = st[i++]; style = st[i++];
1662 }
1663 }
1664 if (sfrom != null && sto == null) span(" ", "CodeMirror-selected");
1665 }
1666 if (includePre) html.push("</pre>");
1667 return html.join("");
1668 }
1669 };
1670 // Utility used by replace and split above
1671 function copyStyles(from, to, source, dest) {
1672 for (var i = 0, pos = 0, state = 0; pos < to; i+=2) {
1673 var part = source[i], end = pos + part.length;
1674 if (state == 0) {
1675 if (end > from) dest.push(part.slice(from - pos, Math.min(part.length, to - pos)), source[i+1]);
1676 if (end >= from) state = 1;
1677 }
1678 else if (state == 1) {
1679 if (end > to) dest.push(part.slice(0, to - pos), source[i+1]);
1680 else dest.push(part, source[i+1]);
1681 }
1682 pos = end;
1683 }
1684 }
1685
1686 // The history object 'chunks' changes that are made close together
1687 // and at almost the same time into bigger undoable units.
1688 function History() {
1689 this.time = 0;
1690 this.done = []; this.undone = [];
1691 }
1692 History.prototype = {
1693 addChange: function(start, added, old) {
1694 this.undone.length = 0;
1695 var time = +new Date, last = this.done[this.done.length - 1];
1696 if (time - this.time > 400 || !last ||
1697 last.start > start + added || last.start + last.added < start - last.added + last.old.length)
1698 this.done.push({start: start, added: added, old: old});
1699 else {
1700 var oldoff = 0;
1701 if (start < last.start) {
1702 for (var i = last.start - start - 1; i >= 0; --i)
1703 last.old.unshift(old[i]);
1704 last.added += last.start - start;
1705 last.start = start;
1706 }
1707 else if (last.start < start) {
1708 oldoff = start - last.start;
1709 added += oldoff;
1710 }
1711 for (var i = last.added - oldoff, e = old.length; i < e; ++i)
1712 last.old.push(old[i]);
1713 if (last.added < added) last.added = added;
1714 }
1715 this.time = time;
1716 }
1717 };
1718
1719 // Event stopping compatibility wrapper.
1720 function stopEvent() {
1721 if (this.preventDefault) {this.preventDefault(); this.stopPropagation();}
1722 else {this.returnValue = false; this.cancelBubble = true;}
1723 }
1724 // Ensure an event has a stop method.
1725 function addStop(event) {
1726 if (!event.stop) event.stop = stopEvent;
1727 return event;
1728 }
1729
1730 // Event wrapper, exposing the few operations we need.
1731 function Event(orig) {this.e = orig;}
1732 Event.prototype = {
1733 stop: function() {stopEvent.call(this.e);},
1734 target: function() {return this.e.target || this.e.srcElement;},
1735 button: function() {
1736 if (this.e.which) return this.e.which;
1737 else if (this.e.button & 1) return 1;
1738 else if (this.e.button & 2) return 3;
1739 else if (this.e.button & 4) return 2;
1740 },
1741 pageX: function() {
1742 if (this.e.pageX != null) return this.e.pageX;
1743 else return this.e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
1744 },
1745 pageY: function() {
1746 if (this.e.pageY != null) return this.e.pageY;
1747 else return this.e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
1748 }
1749 };
1750
1751 // Event handler registration. If disconnect is true, it'll return a
1752 // function that unregisters the handler.
1753 function connect(node, type, handler, disconnect) {
1754 function wrapHandler(event) {handler(new Event(event || window.event));}
1755 if (typeof node.addEventListener == "function") {
1756 node.addEventListener(type, wrapHandler, false);
1757 if (disconnect) return function() {node.removeEventListener(type, wrapHandler, false);};
1758 }
1759 else {
1760 node.attachEvent("on" + type, wrapHandler);
1761 if (disconnect) return function() {node.detachEvent("on" + type, wrapHandler);};
1762 }
1763 }
1764
1765 function Delayed() {this.id = null;}
1766 Delayed.prototype = {set: function(ms, f) {clearTimeout(this.id); this.id = setTimeout(f, ms);}};
1767
1768 // Some IE versions don't preserve whitespace when setting the
1769 // innerHTML of a PRE tag.
1770 var badInnerHTML = (function() {
1771 var pre = document.createElement("pre");
1772 pre.innerHTML = " "; return !pre.innerHTML;
1773 })();
1774
1775 var gecko = /gecko\/\d{7}/i.test(navigator.userAgent);
1776
1777 var lineSep = "\n";
1778 // Feature-detect whether newlines in textareas are converted to \r\n
1779 (function () {
1780 var te = document.createElement("textarea");
1781 te.value = "foo\nbar";
1782 if (te.value.indexOf("\r") > -1) lineSep = "\r\n";
1783 }());
1784
1785 var tabSize = 8;
1786 var mac = /Mac/.test(navigator.platform);
1787 var movementKeys = {};
1788 for (var i = 35; i <= 40; ++i)
1789 movementKeys[i] = movementKeys["c" + i] = true;
1790
1791 // Counts the column offset in a string, taking tabs into account.
1792 // Used mostly to find indentation.
1793 function countColumn(string, end) {
1794 if (end == null) {
1795 end = string.search(/[^\s\u00a0]/);
1796 if (end == -1) end = string.length;
1797 }
1798 for (var i = 0, n = 0; i < end; ++i) {
1799 if (string.charAt(i) == "\t") n += tabSize - (n % tabSize);
1800 else ++n;
1801 }
1802 return n;
1803 }
1804
1805 // Find the position of an element by following the offsetParent chain.
1806 function eltOffset(node) {
1807 var x = 0, y = 0, n2 = node;
1808 for (var n = node; n; n = n.offsetParent) {x += n.offsetLeft; y += n.offsetTop;}
1809 for (var n = node; n != document.body; n = n.parentNode) {x -= n.scrollLeft; y -= n.scrollTop;}
1810 return {left: x, top: y};
1811 }
1812 // Get a node's text content.
1813 function eltText(node) {
1814 return node.textContent || node.innerText || node.nodeValue || "";
1815 }
1816
1817 // Operations on {line, ch} objects.
1818 function posEq(a, b) {return a.line == b.line && a.ch == b.ch;}
1819 function posLess(a, b) {return a.line < b.line || (a.line == b.line && a.ch < b.ch);}
1820 function copyPos(x) {return {line: x.line, ch: x.ch};}
1821
1822 function htmlEscape(str) {
1823 return str.replace(/[<&]/g, function(str) {return str == "&" ? "&amp;" : "&lt;";});
1824 }
1825
1826 // Used to position the cursor after an undo/redo by finding the
1827 // last edited character.
1828 function editEnd(from, to) {
1829 if (!to) return from ? from.length : 0;
1830 if (!from) return to.length;
1831 for (var i = from.length, j = to.length; i >= 0 && j >= 0; --i, --j)
1832 if (from.charAt(i) != to.charAt(j)) break;
1833 return j + 1;
1834 }
1835
1836 function indexOf(collection, elt) {
1837 if (collection.indexOf) return collection.indexOf(elt);
1838 for (var i = 0, e = collection.length; i < e; ++i)
1839 if (collection[i] == elt) return i;
1840 return -1;
1841 }
1842
1843 // See if "".split is the broken IE version, if so, provide an
1844 // alternative way to split lines.
1845 if ("\n\nb".split(/\n/).length != 3)
1846 var splitLines = function(string) {
1847 var pos = 0, nl, result = [];
1848 while ((nl = string.indexOf("\n", pos)) > -1) {
1849 result.push(string.slice(pos, string.charAt(nl-1) == "\r" ? nl - 1 : nl));
1850 pos = nl + 1;
1851 }
1852 result.push(string.slice(pos));
1853 return result;
1854 };
1855 else
1856 var splitLines = function(string){return string.split(/\r?\n/);};
1857
1858 // Sane model of finding and setting the selection in a textarea
1859 if (window.getSelection) {
1860 var selRange = function(te) {
1861 try {return {start: te.selectionStart, end: te.selectionEnd};}
1862 catch(e) {return null;}
1863 };
1864 var setSelRange = function(te, start, end) {
1865 try {te.setSelectionRange(start, end);}
1866 catch(e) {} // Fails on Firefox when textarea isn't part of the document
1867 };
1868 }
1869 // IE model. Don't ask.
1870 else {
1871 var selRange = function(te) {
1872 try {var range = document.selection.createRange();}
1873 catch(e) {return null;}
1874 if (!range || range.parentElement() != te) return null;
1875 var val = te.value, len = val.length, localRange = te.createTextRange();
1876 localRange.moveToBookmark(range.getBookmark());
1877 var endRange = te.createTextRange();
1878 endRange.collapse(false);
1879
1880 if (localRange.compareEndPoints("StartToEnd", endRange) > -1)
1881 return {start: len, end: len};
1882
1883 var start = -localRange.moveStart("character", -len);
1884 for (var i = val.indexOf("\r"); i > -1 && i < start; i = val.indexOf("\r", i+1), start++) {}
1885
1886 if (localRange.compareEndPoints("EndToEnd", endRange) > -1)
1887 return {start: start, end: len};
1888
1889 var end = -localRange.moveEnd("character", -len);
1890 for (var i = val.indexOf("\r"); i > -1 && i < end; i = val.indexOf("\r", i+1), end++) {}
1891 return {start: start, end: end};
1892 };
1893 var setSelRange = function(te, start, end) {
1894 var range = te.createTextRange();
1895 range.collapse(true);
1896 var endrange = range.duplicate();
1897 var newlines = 0, txt = te.value;
1898 for (var pos = txt.indexOf("\n"); pos > -1 && pos < start; pos = txt.indexOf("\n", pos + 1))
1899 ++newlines;
1900 range.move("character", start - newlines);
1901 for (; pos > -1 && pos < end; pos = txt.indexOf("\n", pos + 1))
1902 ++newlines;
1903 endrange.move("character", end - newlines);
1904 range.setEndPoint("EndToEnd", endrange);
1905 range.select();
1906 };
1907 }
1908
1909 CodeMirror.defineMode("null", function() {
1910 return {token: function(stream) {stream.skipToEnd();}};
1911 });
1912 CodeMirror.defineMIME("text/plain", "null");
1913
1914 return CodeMirror;
1915 })();
@@ -0,0 +1,66 b''
1 <%inherit file="/base/base.html"/>
2
3 <%def name="title()">
4 ${c.repo_name} ${_('Edit file')} - ${c.rhodecode_name}
5 </%def>
6
7 <%def name="js_extra()">
8 <script type="text/javascript" src="${h.url('/js/codemirror.js')}"></script>
9 </%def>
10 <%def name="css_extra()">
11 <link rel="stylesheet" type="text/css" href="${h.url('/css/codemirror.css')}"/>
12 </%def>
13
14 <%def name="breadcrumbs_links()">
15 ${h.link_to(u'Home',h.url('/'))}
16 &raquo;
17 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
18 &raquo;
19 ${_('edit file')} @ R${c.cs.revision}:${h.short_id(c.cs.raw_id)}
20 </%def>
21
22 <%def name="page_nav()">
23 ${self.menu('files')}
24 </%def>
25 <%def name="main()">
26 <div class="box">
27 <!-- box / title -->
28 <div class="title">
29 ${self.breadcrumbs()}
30 <ul class="links">
31 <li>
32 <span style="text-transform: uppercase;">
33 <a href="#">${_('branch')}: ${c.cs.branch}</a></span>
34 </li>
35 </ul>
36 </div>
37 <div class="table">
38 <div id="files_data">
39 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cs.revision,c.file.path)}</h3>
40 ${h.form(h.url.current(),method='post',id='eform')}
41 <div id="body" class="codeblock">
42 <pre id="editor_pre"></pre>
43 <textarea id="editor" name="content" style="display:none">${c.file.content|n}</textarea>
44
45 <div style="padding-top: 10px;">${_('commit message')}</div>
46 <textarea id="commit" name="message" style="height: 100px;width: 99%"></textarea>
47
48 </div>
49 <div style="text-align: right;padding-top: 5px">
50 <input id="reset" type="button" value="${_('Reset')}" class="ui-button-small" />
51 ${h.submit('commit',_('Commit changes'),class_="ui-button-small-blue")}
52 </div>
53 ${h.end_form()}
54 <script type="text/javascript">
55 var myCodeMirror = CodeMirror.fromTextArea(YUD.get('editor'),{
56 mode: "null",
57 lineNumbers:true
58 });
59 YUE.on('reset','click',function(){
60 window.location="${h.url('files_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.file.path)}";
61 })
62 </script>
63 </div>
64 </div>
65 </div>
66 </%def> No newline at end of file
@@ -1,348 +1,353 b''
1 """
1 """
2 Routes configuration
2 Routes configuration
3
3
4 The more specific and detailed routes should be defined first so they
4 The more specific and detailed routes should be defined first so they
5 may take precedent over the more generic routes. For more information
5 may take precedent over the more generic routes. For more information
6 refer to the routes manual at http://routes.groovie.org/docs/
6 refer to the routes manual at http://routes.groovie.org/docs/
7 """
7 """
8 from __future__ import with_statement
8 from __future__ import with_statement
9 from routes import Mapper
9 from routes import Mapper
10 from rhodecode.lib.utils import check_repo_fast as cr
10 from rhodecode.lib.utils import check_repo_fast as cr
11
11
12
12
13 def make_map(config):
13 def make_map(config):
14 """Create, configure and return the routes Mapper"""
14 """Create, configure and return the routes Mapper"""
15 rmap = Mapper(directory=config['pylons.paths']['controllers'],
15 rmap = Mapper(directory=config['pylons.paths']['controllers'],
16 always_scan=config['debug'])
16 always_scan=config['debug'])
17 rmap.minimization = False
17 rmap.minimization = False
18 rmap.explicit = False
18 rmap.explicit = False
19
19
20 def check_repo(environ, match_dict):
20 def check_repo(environ, match_dict):
21 """
21 """
22 check for valid repository for proper 404 handling
22 check for valid repository for proper 404 handling
23 :param environ:
23 :param environ:
24 :param match_dict:
24 :param match_dict:
25 """
25 """
26 repo_name = match_dict.get('repo_name')
26 repo_name = match_dict.get('repo_name')
27 return not cr(repo_name, config['base_path'])
27 return not cr(repo_name, config['base_path'])
28
28
29 # The ErrorController route (handles 404/500 error pages); it should
29 # The ErrorController route (handles 404/500 error pages); it should
30 # likely stay at the top, ensuring it can always be resolved
30 # likely stay at the top, ensuring it can always be resolved
31 rmap.connect('/error/{action}', controller='error')
31 rmap.connect('/error/{action}', controller='error')
32 rmap.connect('/error/{action}/{id}', controller='error')
32 rmap.connect('/error/{action}/{id}', controller='error')
33
33
34 #==========================================================================
34 #==========================================================================
35 # CUSTOM ROUTES HERE
35 # CUSTOM ROUTES HERE
36 #==========================================================================
36 #==========================================================================
37
37
38 #MAIN PAGE
38 #MAIN PAGE
39 rmap.connect('home', '/', controller='home', action='index')
39 rmap.connect('home', '/', controller='home', action='index')
40 rmap.connect('repo_switcher', '/repos', controller='home',
40 rmap.connect('repo_switcher', '/repos', controller='home',
41 action='repo_switcher')
41 action='repo_switcher')
42 rmap.connect('bugtracker',
42 rmap.connect('bugtracker',
43 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
43 "http://bitbucket.org/marcinkuzminski/rhodecode/issues",
44 _static=True)
44 _static=True)
45 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
45 rmap.connect('rhodecode_official', "http://rhodecode.org", _static=True)
46
46
47 #ADMIN REPOSITORY REST ROUTES
47 #ADMIN REPOSITORY REST ROUTES
48 with rmap.submapper(path_prefix='/_admin', controller='admin/repos') as m:
48 with rmap.submapper(path_prefix='/_admin', controller='admin/repos') as m:
49 m.connect("repos", "/repos",
49 m.connect("repos", "/repos",
50 action="create", conditions=dict(method=["POST"]))
50 action="create", conditions=dict(method=["POST"]))
51 m.connect("repos", "/repos",
51 m.connect("repos", "/repos",
52 action="index", conditions=dict(method=["GET"]))
52 action="index", conditions=dict(method=["GET"]))
53 m.connect("formatted_repos", "/repos.{format}",
53 m.connect("formatted_repos", "/repos.{format}",
54 action="index",
54 action="index",
55 conditions=dict(method=["GET"]))
55 conditions=dict(method=["GET"]))
56 m.connect("new_repo", "/repos/new",
56 m.connect("new_repo", "/repos/new",
57 action="new", conditions=dict(method=["GET"]))
57 action="new", conditions=dict(method=["GET"]))
58 m.connect("formatted_new_repo", "/repos/new.{format}",
58 m.connect("formatted_new_repo", "/repos/new.{format}",
59 action="new", conditions=dict(method=["GET"]))
59 action="new", conditions=dict(method=["GET"]))
60 m.connect("/repos/{repo_name:.*}",
60 m.connect("/repos/{repo_name:.*}",
61 action="update", conditions=dict(method=["PUT"],
61 action="update", conditions=dict(method=["PUT"],
62 function=check_repo))
62 function=check_repo))
63 m.connect("/repos/{repo_name:.*}",
63 m.connect("/repos/{repo_name:.*}",
64 action="delete", conditions=dict(method=["DELETE"],
64 action="delete", conditions=dict(method=["DELETE"],
65 function=check_repo))
65 function=check_repo))
66 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
66 m.connect("edit_repo", "/repos/{repo_name:.*}/edit",
67 action="edit", conditions=dict(method=["GET"],
67 action="edit", conditions=dict(method=["GET"],
68 function=check_repo))
68 function=check_repo))
69 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
69 m.connect("formatted_edit_repo", "/repos/{repo_name:.*}.{format}/edit",
70 action="edit", conditions=dict(method=["GET"],
70 action="edit", conditions=dict(method=["GET"],
71 function=check_repo))
71 function=check_repo))
72 m.connect("repo", "/repos/{repo_name:.*}",
72 m.connect("repo", "/repos/{repo_name:.*}",
73 action="show", conditions=dict(method=["GET"],
73 action="show", conditions=dict(method=["GET"],
74 function=check_repo))
74 function=check_repo))
75 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
75 m.connect("formatted_repo", "/repos/{repo_name:.*}.{format}",
76 action="show", conditions=dict(method=["GET"],
76 action="show", conditions=dict(method=["GET"],
77 function=check_repo))
77 function=check_repo))
78 #ajax delete repo perm user
78 #ajax delete repo perm user
79 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
79 m.connect('delete_repo_user', "/repos_delete_user/{repo_name:.*}",
80 action="delete_perm_user", conditions=dict(method=["DELETE"],
80 action="delete_perm_user", conditions=dict(method=["DELETE"],
81 function=check_repo))
81 function=check_repo))
82 #ajax delete repo perm users_group
82 #ajax delete repo perm users_group
83 m.connect('delete_repo_users_group',
83 m.connect('delete_repo_users_group',
84 "/repos_delete_users_group/{repo_name:.*}",
84 "/repos_delete_users_group/{repo_name:.*}",
85 action="delete_perm_users_group",
85 action="delete_perm_users_group",
86 conditions=dict(method=["DELETE"], function=check_repo))
86 conditions=dict(method=["DELETE"], function=check_repo))
87
87
88 #settings actions
88 #settings actions
89 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
89 m.connect('repo_stats', "/repos_stats/{repo_name:.*}",
90 action="repo_stats", conditions=dict(method=["DELETE"],
90 action="repo_stats", conditions=dict(method=["DELETE"],
91 function=check_repo))
91 function=check_repo))
92 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
92 m.connect('repo_cache', "/repos_cache/{repo_name:.*}",
93 action="repo_cache", conditions=dict(method=["DELETE"],
93 action="repo_cache", conditions=dict(method=["DELETE"],
94 function=check_repo))
94 function=check_repo))
95 m.connect('repo_public_journal',
95 m.connect('repo_public_journal',
96 "/repos_public_journal/{repo_name:.*}",
96 "/repos_public_journal/{repo_name:.*}",
97 action="repo_public_journal", conditions=dict(method=["PUT"],
97 action="repo_public_journal", conditions=dict(method=["PUT"],
98 function=check_repo))
98 function=check_repo))
99 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
99 m.connect('repo_pull', "/repo_pull/{repo_name:.*}",
100 action="repo_pull", conditions=dict(method=["PUT"],
100 action="repo_pull", conditions=dict(method=["PUT"],
101 function=check_repo))
101 function=check_repo))
102
102
103 #ADMIN REPOS GROUP REST ROUTES
103 #ADMIN REPOS GROUP REST ROUTES
104 rmap.resource('repos_group', 'repos_groups',
104 rmap.resource('repos_group', 'repos_groups',
105 controller='admin/repos_groups', path_prefix='/_admin')
105 controller='admin/repos_groups', path_prefix='/_admin')
106
106
107 #ADMIN USER REST ROUTES
107 #ADMIN USER REST ROUTES
108 with rmap.submapper(path_prefix='/_admin', controller='admin/users') as m:
108 with rmap.submapper(path_prefix='/_admin', controller='admin/users') as m:
109 m.connect("users", "/users",
109 m.connect("users", "/users",
110 action="create", conditions=dict(method=["POST"]))
110 action="create", conditions=dict(method=["POST"]))
111 m.connect("users", "/users",
111 m.connect("users", "/users",
112 action="index", conditions=dict(method=["GET"]))
112 action="index", conditions=dict(method=["GET"]))
113 m.connect("formatted_users", "/users.{format}",
113 m.connect("formatted_users", "/users.{format}",
114 action="index", conditions=dict(method=["GET"]))
114 action="index", conditions=dict(method=["GET"]))
115 m.connect("new_user", "/users/new",
115 m.connect("new_user", "/users/new",
116 action="new", conditions=dict(method=["GET"]))
116 action="new", conditions=dict(method=["GET"]))
117 m.connect("formatted_new_user", "/users/new.{format}",
117 m.connect("formatted_new_user", "/users/new.{format}",
118 action="new", conditions=dict(method=["GET"]))
118 action="new", conditions=dict(method=["GET"]))
119 m.connect("update_user", "/users/{id}",
119 m.connect("update_user", "/users/{id}",
120 action="update", conditions=dict(method=["PUT"]))
120 action="update", conditions=dict(method=["PUT"]))
121 m.connect("delete_user", "/users/{id}",
121 m.connect("delete_user", "/users/{id}",
122 action="delete", conditions=dict(method=["DELETE"]))
122 action="delete", conditions=dict(method=["DELETE"]))
123 m.connect("edit_user", "/users/{id}/edit",
123 m.connect("edit_user", "/users/{id}/edit",
124 action="edit", conditions=dict(method=["GET"]))
124 action="edit", conditions=dict(method=["GET"]))
125 m.connect("formatted_edit_user",
125 m.connect("formatted_edit_user",
126 "/users/{id}.{format}/edit",
126 "/users/{id}.{format}/edit",
127 action="edit", conditions=dict(method=["GET"]))
127 action="edit", conditions=dict(method=["GET"]))
128 m.connect("user", "/users/{id}",
128 m.connect("user", "/users/{id}",
129 action="show", conditions=dict(method=["GET"]))
129 action="show", conditions=dict(method=["GET"]))
130 m.connect("formatted_user", "/users/{id}.{format}",
130 m.connect("formatted_user", "/users/{id}.{format}",
131 action="show", conditions=dict(method=["GET"]))
131 action="show", conditions=dict(method=["GET"]))
132
132
133 #EXTRAS USER ROUTES
133 #EXTRAS USER ROUTES
134 m.connect("user_perm", "/users_perm/{id}",
134 m.connect("user_perm", "/users_perm/{id}",
135 action="update_perm", conditions=dict(method=["PUT"]))
135 action="update_perm", conditions=dict(method=["PUT"]))
136
136
137 #ADMIN USERS REST ROUTES
137 #ADMIN USERS REST ROUTES
138 with rmap.submapper(path_prefix='/_admin',
138 with rmap.submapper(path_prefix='/_admin',
139 controller='admin/users_groups') as m:
139 controller='admin/users_groups') as m:
140 m.connect("users_groups", "/users_groups",
140 m.connect("users_groups", "/users_groups",
141 action="create", conditions=dict(method=["POST"]))
141 action="create", conditions=dict(method=["POST"]))
142 m.connect("users_groups", "/users_groups",
142 m.connect("users_groups", "/users_groups",
143 action="index", conditions=dict(method=["GET"]))
143 action="index", conditions=dict(method=["GET"]))
144 m.connect("formatted_users_groups", "/users_groups.{format}",
144 m.connect("formatted_users_groups", "/users_groups.{format}",
145 action="index", conditions=dict(method=["GET"]))
145 action="index", conditions=dict(method=["GET"]))
146 m.connect("new_users_group", "/users_groups/new",
146 m.connect("new_users_group", "/users_groups/new",
147 action="new", conditions=dict(method=["GET"]))
147 action="new", conditions=dict(method=["GET"]))
148 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
148 m.connect("formatted_new_users_group", "/users_groups/new.{format}",
149 action="new", conditions=dict(method=["GET"]))
149 action="new", conditions=dict(method=["GET"]))
150 m.connect("update_users_group", "/users_groups/{id}",
150 m.connect("update_users_group", "/users_groups/{id}",
151 action="update", conditions=dict(method=["PUT"]))
151 action="update", conditions=dict(method=["PUT"]))
152 m.connect("delete_users_group", "/users_groups/{id}",
152 m.connect("delete_users_group", "/users_groups/{id}",
153 action="delete", conditions=dict(method=["DELETE"]))
153 action="delete", conditions=dict(method=["DELETE"]))
154 m.connect("edit_users_group", "/users_groups/{id}/edit",
154 m.connect("edit_users_group", "/users_groups/{id}/edit",
155 action="edit", conditions=dict(method=["GET"]))
155 action="edit", conditions=dict(method=["GET"]))
156 m.connect("formatted_edit_users_group",
156 m.connect("formatted_edit_users_group",
157 "/users_groups/{id}.{format}/edit",
157 "/users_groups/{id}.{format}/edit",
158 action="edit", conditions=dict(method=["GET"]))
158 action="edit", conditions=dict(method=["GET"]))
159 m.connect("users_group", "/users_groups/{id}",
159 m.connect("users_group", "/users_groups/{id}",
160 action="show", conditions=dict(method=["GET"]))
160 action="show", conditions=dict(method=["GET"]))
161 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
161 m.connect("formatted_users_group", "/users_groups/{id}.{format}",
162 action="show", conditions=dict(method=["GET"]))
162 action="show", conditions=dict(method=["GET"]))
163
163
164 #EXTRAS USER ROUTES
164 #EXTRAS USER ROUTES
165 m.connect("users_group_perm", "/users_groups_perm/{id}",
165 m.connect("users_group_perm", "/users_groups_perm/{id}",
166 action="update_perm", conditions=dict(method=["PUT"]))
166 action="update_perm", conditions=dict(method=["PUT"]))
167
167
168 #ADMIN GROUP REST ROUTES
168 #ADMIN GROUP REST ROUTES
169 rmap.resource('group', 'groups',
169 rmap.resource('group', 'groups',
170 controller='admin/groups', path_prefix='/_admin')
170 controller='admin/groups', path_prefix='/_admin')
171
171
172 #ADMIN PERMISSIONS REST ROUTES
172 #ADMIN PERMISSIONS REST ROUTES
173 rmap.resource('permission', 'permissions',
173 rmap.resource('permission', 'permissions',
174 controller='admin/permissions', path_prefix='/_admin')
174 controller='admin/permissions', path_prefix='/_admin')
175
175
176 ##ADMIN LDAP SETTINGS
176 ##ADMIN LDAP SETTINGS
177 rmap.connect('ldap_settings', '/_admin/ldap',
177 rmap.connect('ldap_settings', '/_admin/ldap',
178 controller='admin/ldap_settings', action='ldap_settings',
178 controller='admin/ldap_settings', action='ldap_settings',
179 conditions=dict(method=["POST"]))
179 conditions=dict(method=["POST"]))
180
180
181 rmap.connect('ldap_home', '/_admin/ldap',
181 rmap.connect('ldap_home', '/_admin/ldap',
182 controller='admin/ldap_settings')
182 controller='admin/ldap_settings')
183
183
184 #ADMIN SETTINGS REST ROUTES
184 #ADMIN SETTINGS REST ROUTES
185 with rmap.submapper(path_prefix='/_admin',
185 with rmap.submapper(path_prefix='/_admin',
186 controller='admin/settings') as m:
186 controller='admin/settings') as m:
187 m.connect("admin_settings", "/settings",
187 m.connect("admin_settings", "/settings",
188 action="create", conditions=dict(method=["POST"]))
188 action="create", conditions=dict(method=["POST"]))
189 m.connect("admin_settings", "/settings",
189 m.connect("admin_settings", "/settings",
190 action="index", conditions=dict(method=["GET"]))
190 action="index", conditions=dict(method=["GET"]))
191 m.connect("formatted_admin_settings", "/settings.{format}",
191 m.connect("formatted_admin_settings", "/settings.{format}",
192 action="index", conditions=dict(method=["GET"]))
192 action="index", conditions=dict(method=["GET"]))
193 m.connect("admin_new_setting", "/settings/new",
193 m.connect("admin_new_setting", "/settings/new",
194 action="new", conditions=dict(method=["GET"]))
194 action="new", conditions=dict(method=["GET"]))
195 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
195 m.connect("formatted_admin_new_setting", "/settings/new.{format}",
196 action="new", conditions=dict(method=["GET"]))
196 action="new", conditions=dict(method=["GET"]))
197 m.connect("/settings/{setting_id}",
197 m.connect("/settings/{setting_id}",
198 action="update", conditions=dict(method=["PUT"]))
198 action="update", conditions=dict(method=["PUT"]))
199 m.connect("/settings/{setting_id}",
199 m.connect("/settings/{setting_id}",
200 action="delete", conditions=dict(method=["DELETE"]))
200 action="delete", conditions=dict(method=["DELETE"]))
201 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
201 m.connect("admin_edit_setting", "/settings/{setting_id}/edit",
202 action="edit", conditions=dict(method=["GET"]))
202 action="edit", conditions=dict(method=["GET"]))
203 m.connect("formatted_admin_edit_setting",
203 m.connect("formatted_admin_edit_setting",
204 "/settings/{setting_id}.{format}/edit",
204 "/settings/{setting_id}.{format}/edit",
205 action="edit", conditions=dict(method=["GET"]))
205 action="edit", conditions=dict(method=["GET"]))
206 m.connect("admin_setting", "/settings/{setting_id}",
206 m.connect("admin_setting", "/settings/{setting_id}",
207 action="show", conditions=dict(method=["GET"]))
207 action="show", conditions=dict(method=["GET"]))
208 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
208 m.connect("formatted_admin_setting", "/settings/{setting_id}.{format}",
209 action="show", conditions=dict(method=["GET"]))
209 action="show", conditions=dict(method=["GET"]))
210 m.connect("admin_settings_my_account", "/my_account",
210 m.connect("admin_settings_my_account", "/my_account",
211 action="my_account", conditions=dict(method=["GET"]))
211 action="my_account", conditions=dict(method=["GET"]))
212 m.connect("admin_settings_my_account_update", "/my_account_update",
212 m.connect("admin_settings_my_account_update", "/my_account_update",
213 action="my_account_update", conditions=dict(method=["PUT"]))
213 action="my_account_update", conditions=dict(method=["PUT"]))
214 m.connect("admin_settings_create_repository", "/create_repository",
214 m.connect("admin_settings_create_repository", "/create_repository",
215 action="create_repository", conditions=dict(method=["GET"]))
215 action="create_repository", conditions=dict(method=["GET"]))
216
216
217 #ADMIN MAIN PAGES
217 #ADMIN MAIN PAGES
218 with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
218 with rmap.submapper(path_prefix='/_admin', controller='admin/admin') as m:
219 m.connect('admin_home', '', action='index')
219 m.connect('admin_home', '', action='index')
220 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
220 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
221 action='add_repo')
221 action='add_repo')
222
222
223 #USER JOURNAL
223 #USER JOURNAL
224 rmap.connect('journal', '/_admin/journal', controller='journal')
224 rmap.connect('journal', '/_admin/journal', controller='journal')
225
225
226 rmap.connect('public_journal', '/_admin/public_journal',
226 rmap.connect('public_journal', '/_admin/public_journal',
227 controller='journal', action="public_journal")
227 controller='journal', action="public_journal")
228
228
229 rmap.connect('public_journal_rss', '/_admin/public_journal_rss',
229 rmap.connect('public_journal_rss', '/_admin/public_journal_rss',
230 controller='journal', action="public_journal_rss")
230 controller='journal', action="public_journal_rss")
231
231
232 rmap.connect('public_journal_atom', '/_admin/public_journal_atom',
232 rmap.connect('public_journal_atom', '/_admin/public_journal_atom',
233 controller='journal', action="public_journal_atom")
233 controller='journal', action="public_journal_atom")
234
234
235 rmap.connect('toggle_following', '/_admin/toggle_following',
235 rmap.connect('toggle_following', '/_admin/toggle_following',
236 controller='journal', action='toggle_following',
236 controller='journal', action='toggle_following',
237 conditions=dict(method=["POST"]))
237 conditions=dict(method=["POST"]))
238
238
239 #SEARCH
239 #SEARCH
240 rmap.connect('search', '/_admin/search', controller='search',)
240 rmap.connect('search', '/_admin/search', controller='search',)
241 rmap.connect('search_repo', '/_admin/search/{search_repo:.*}',
241 rmap.connect('search_repo', '/_admin/search/{search_repo:.*}',
242 controller='search')
242 controller='search')
243
243
244 #LOGIN/LOGOUT/REGISTER/SIGN IN
244 #LOGIN/LOGOUT/REGISTER/SIGN IN
245 rmap.connect('login_home', '/_admin/login', controller='login')
245 rmap.connect('login_home', '/_admin/login', controller='login')
246 rmap.connect('logout_home', '/_admin/logout', controller='login',
246 rmap.connect('logout_home', '/_admin/logout', controller='login',
247 action='logout')
247 action='logout')
248
248
249 rmap.connect('register', '/_admin/register', controller='login',
249 rmap.connect('register', '/_admin/register', controller='login',
250 action='register')
250 action='register')
251
251
252 rmap.connect('reset_password', '/_admin/password_reset',
252 rmap.connect('reset_password', '/_admin/password_reset',
253 controller='login', action='password_reset')
253 controller='login', action='password_reset')
254
254
255 #FEEDS
255 #FEEDS
256 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
256 rmap.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
257 controller='feed', action='rss',
257 controller='feed', action='rss',
258 conditions=dict(function=check_repo))
258 conditions=dict(function=check_repo))
259
259
260 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
260 rmap.connect('atom_feed_home', '/{repo_name:.*}/feed/atom',
261 controller='feed', action='atom',
261 controller='feed', action='atom',
262 conditions=dict(function=check_repo))
262 conditions=dict(function=check_repo))
263
263
264 #==========================================================================
264 #==========================================================================
265 # REPOSITORY ROUTES
265 # REPOSITORY ROUTES
266 #==========================================================================
266 #==========================================================================
267 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
267 rmap.connect('changeset_home', '/{repo_name:.*}/changeset/{revision}',
268 controller='changeset', revision='tip',
268 controller='changeset', revision='tip',
269 conditions=dict(function=check_repo))
269 conditions=dict(function=check_repo))
270
270
271 rmap.connect('raw_changeset_home',
271 rmap.connect('raw_changeset_home',
272 '/{repo_name:.*}/raw-changeset/{revision}',
272 '/{repo_name:.*}/raw-changeset/{revision}',
273 controller='changeset', action='raw_changeset',
273 controller='changeset', action='raw_changeset',
274 revision='tip', conditions=dict(function=check_repo))
274 revision='tip', conditions=dict(function=check_repo))
275
275
276 rmap.connect('summary_home', '/{repo_name:.*}',
276 rmap.connect('summary_home', '/{repo_name:.*}',
277 controller='summary', conditions=dict(function=check_repo))
277 controller='summary', conditions=dict(function=check_repo))
278
278
279 rmap.connect('summary_home', '/{repo_name:.*}/summary',
279 rmap.connect('summary_home', '/{repo_name:.*}/summary',
280 controller='summary', conditions=dict(function=check_repo))
280 controller='summary', conditions=dict(function=check_repo))
281
281
282 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
282 rmap.connect('shortlog_home', '/{repo_name:.*}/shortlog',
283 controller='shortlog', conditions=dict(function=check_repo))
283 controller='shortlog', conditions=dict(function=check_repo))
284
284
285 rmap.connect('branches_home', '/{repo_name:.*}/branches',
285 rmap.connect('branches_home', '/{repo_name:.*}/branches',
286 controller='branches', conditions=dict(function=check_repo))
286 controller='branches', conditions=dict(function=check_repo))
287
287
288 rmap.connect('tags_home', '/{repo_name:.*}/tags',
288 rmap.connect('tags_home', '/{repo_name:.*}/tags',
289 controller='tags', conditions=dict(function=check_repo))
289 controller='tags', conditions=dict(function=check_repo))
290
290
291 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
291 rmap.connect('changelog_home', '/{repo_name:.*}/changelog',
292 controller='changelog', conditions=dict(function=check_repo))
292 controller='changelog', conditions=dict(function=check_repo))
293
293
294 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
294 rmap.connect('files_home', '/{repo_name:.*}/files/{revision}/{f_path:.*}',
295 controller='files', revision='tip', f_path='',
295 controller='files', revision='tip', f_path='',
296 conditions=dict(function=check_repo))
296 conditions=dict(function=check_repo))
297
297
298 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
298 rmap.connect('files_diff_home', '/{repo_name:.*}/diff/{f_path:.*}',
299 controller='files', action='diff', revision='tip', f_path='',
299 controller='files', action='diff', revision='tip', f_path='',
300 conditions=dict(function=check_repo))
300 conditions=dict(function=check_repo))
301
301
302 rmap.connect('files_rawfile_home',
302 rmap.connect('files_rawfile_home',
303 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
303 '/{repo_name:.*}/rawfile/{revision}/{f_path:.*}',
304 controller='files', action='rawfile', revision='tip',
304 controller='files', action='rawfile', revision='tip',
305 f_path='', conditions=dict(function=check_repo))
305 f_path='', conditions=dict(function=check_repo))
306
306
307 rmap.connect('files_raw_home',
307 rmap.connect('files_raw_home',
308 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
308 '/{repo_name:.*}/raw/{revision}/{f_path:.*}',
309 controller='files', action='raw', revision='tip', f_path='',
309 controller='files', action='raw', revision='tip', f_path='',
310 conditions=dict(function=check_repo))
310 conditions=dict(function=check_repo))
311
311
312 rmap.connect('files_annotate_home',
312 rmap.connect('files_annotate_home',
313 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
313 '/{repo_name:.*}/annotate/{revision}/{f_path:.*}',
314 controller='files', action='annotate', revision='tip',
314 controller='files', action='annotate', revision='tip',
315 f_path='', conditions=dict(function=check_repo))
315 f_path='', conditions=dict(function=check_repo))
316
316
317 rmap.connect('files_edit_home',
318 '/{repo_name:.*}/edit/{revision}/{f_path:.*}',
319 controller='files', action='edit', revision='tip',
320 f_path='', conditions=dict(function=check_repo))
321
317 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
322 rmap.connect('files_archive_home', '/{repo_name:.*}/archive/{fname}',
318 controller='files', action='archivefile',
323 controller='files', action='archivefile',
319 conditions=dict(function=check_repo))
324 conditions=dict(function=check_repo))
320
325
321 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
326 rmap.connect('repo_settings_delete', '/{repo_name:.*}/settings',
322 controller='settings', action="delete",
327 controller='settings', action="delete",
323 conditions=dict(method=["DELETE"], function=check_repo))
328 conditions=dict(method=["DELETE"], function=check_repo))
324
329
325 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
330 rmap.connect('repo_settings_update', '/{repo_name:.*}/settings',
326 controller='settings', action="update",
331 controller='settings', action="update",
327 conditions=dict(method=["PUT"], function=check_repo))
332 conditions=dict(method=["PUT"], function=check_repo))
328
333
329 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
334 rmap.connect('repo_settings_home', '/{repo_name:.*}/settings',
330 controller='settings', action='index',
335 controller='settings', action='index',
331 conditions=dict(function=check_repo))
336 conditions=dict(function=check_repo))
332
337
333 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
338 rmap.connect('repo_fork_create_home', '/{repo_name:.*}/fork',
334 controller='settings', action='fork_create',
339 controller='settings', action='fork_create',
335 conditions=dict(function=check_repo, method=["POST"]))
340 conditions=dict(function=check_repo, method=["POST"]))
336
341
337 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
342 rmap.connect('repo_fork_home', '/{repo_name:.*}/fork',
338 controller='settings', action='fork',
343 controller='settings', action='fork',
339 conditions=dict(function=check_repo))
344 conditions=dict(function=check_repo))
340
345
341 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
346 rmap.connect('repo_followers_home', '/{repo_name:.*}/followers',
342 controller='followers', action='followers',
347 controller='followers', action='followers',
343 conditions=dict(function=check_repo))
348 conditions=dict(function=check_repo))
344
349
345 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
350 rmap.connect('repo_forks_home', '/{repo_name:.*}/forks',
346 controller='forks', action='forks',
351 controller='forks', action='forks',
347 conditions=dict(function=check_repo))
352 conditions=dict(function=check_repo))
348 return rmap
353 return rmap
@@ -1,339 +1,396 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import os
26 import os
27 import logging
27 import logging
28 import mimetypes
28 import mimetypes
29 import rhodecode.lib.helpers as h
29 import traceback
30
30
31 from pylons import request, response, session, tmpl_context as c, url
31 from pylons import request, response, session, tmpl_context as c, url
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34
34
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.utils import EmptyChangeset
38 from rhodecode.model.repo import RepoModel
39
40 from vcs.backends import ARCHIVE_SPECS
35 from vcs.backends import ARCHIVE_SPECS
41 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
36 from vcs.exceptions import RepositoryError, ChangesetDoesNotExistError, \
42 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
37 EmptyRepositoryError, ImproperArchiveTypeError, VCSError
43 from vcs.nodes import FileNode, NodeKind
38 from vcs.nodes import FileNode, NodeKind
44 from vcs.utils import diffs as differ
39 from vcs.utils import diffs as differ
45
40
41 from rhodecode.lib import convert_line_endings, detect_mode
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
43 from rhodecode.lib.base import BaseRepoController, render
44 from rhodecode.lib.utils import EmptyChangeset
45 import rhodecode.lib.helpers as h
46 from rhodecode.model.repo import RepoModel
47
46 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
47
49
48
50
49 class FilesController(BaseRepoController):
51 class FilesController(BaseRepoController):
50
52
51 @LoginRequired()
53 @LoginRequired()
52 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
53 'repository.admin')
54 def __before__(self):
54 def __before__(self):
55 super(FilesController, self).__before__()
55 super(FilesController, self).__before__()
56 c.cut_off_limit = self.cut_off_limit
56 c.cut_off_limit = self.cut_off_limit
57
57
58 def __get_cs_or_redirect(self, rev, repo_name):
58 def __get_cs_or_redirect(self, rev, repo_name):
59 """
59 """
60 Safe way to get changeset if error occur it redirects to tip with
60 Safe way to get changeset if error occur it redirects to tip with
61 proper message
61 proper message
62
62
63 :param rev: revision to fetch
63 :param rev: revision to fetch
64 :param repo_name: repo name to redirect after
64 :param repo_name: repo name to redirect after
65 """
65 """
66
66
67 try:
67 try:
68 return c.rhodecode_repo.get_changeset(rev)
68 return c.rhodecode_repo.get_changeset(rev)
69 except EmptyRepositoryError, e:
69 except EmptyRepositoryError, e:
70 h.flash(_('There are no files yet'), category='warning')
70 h.flash(_('There are no files yet'), category='warning')
71 redirect(h.url('summary_home', repo_name=repo_name))
71 redirect(h.url('summary_home', repo_name=repo_name))
72
72
73 except RepositoryError, e:
73 except RepositoryError, e:
74 h.flash(str(e), category='warning')
74 h.flash(str(e), category='warning')
75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
75 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
76
76
77 def __get_filenode_or_redirect(self, repo_name, cs, path):
77 def __get_filenode_or_redirect(self, repo_name, cs, path):
78 """
78 """
79 Returns file_node, if error occurs or given path is directory,
79 Returns file_node, if error occurs or given path is directory,
80 it'll redirect to top level path
80 it'll redirect to top level path
81
81
82 :param repo_name: repo_name
82 :param repo_name: repo_name
83 :param cs: given changeset
83 :param cs: given changeset
84 :param path: path to lookup
84 :param path: path to lookup
85 """
85 """
86
86
87 try:
87 try:
88 file_node = cs.get_node(path)
88 file_node = cs.get_node(path)
89 if file_node.is_dir():
89 if file_node.is_dir():
90 raise RepositoryError('given path is a directory')
90 raise RepositoryError('given path is a directory')
91 except RepositoryError, e:
91 except RepositoryError, e:
92 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
93 redirect(h.url('files_home', repo_name=repo_name,
93 redirect(h.url('files_home', repo_name=repo_name,
94 revision=cs.raw_id))
94 revision=cs.raw_id))
95
95
96 return file_node
96 return file_node
97
97
98 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
99 'repository.admin')
98 def index(self, repo_name, revision, f_path):
100 def index(self, repo_name, revision, f_path):
99 #reditect to given revision from form if given
101 #reditect to given revision from form if given
100 post_revision = request.POST.get('at_rev', None)
102 post_revision = request.POST.get('at_rev', None)
101 if post_revision:
103 if post_revision:
102 cs = self.__get_cs_or_redirect(post_revision, repo_name)
104 cs = self.__get_cs_or_redirect(post_revision, repo_name)
103 redirect(url('files_home', repo_name=c.repo_name,
105 redirect(url('files_home', repo_name=c.repo_name,
104 revision=cs.raw_id, f_path=f_path))
106 revision=cs.raw_id, f_path=f_path))
105
107
106 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
108 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
107 c.branch = request.GET.get('branch', None)
109 c.branch = request.GET.get('branch', None)
108 c.f_path = f_path
110 c.f_path = f_path
109
111
110 cur_rev = c.changeset.revision
112 cur_rev = c.changeset.revision
111
113
112 #prev link
114 #prev link
113 try:
115 try:
114 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
116 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
115 c.url_prev = url('files_home', repo_name=c.repo_name,
117 c.url_prev = url('files_home', repo_name=c.repo_name,
116 revision=prev_rev.raw_id, f_path=f_path)
118 revision=prev_rev.raw_id, f_path=f_path)
117 if c.branch:
119 if c.branch:
118 c.url_prev += '?branch=%s' % c.branch
120 c.url_prev += '?branch=%s' % c.branch
119 except (ChangesetDoesNotExistError, VCSError):
121 except (ChangesetDoesNotExistError, VCSError):
120 c.url_prev = '#'
122 c.url_prev = '#'
121
123
122 #next link
124 #next link
123 try:
125 try:
124 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
126 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
125 c.url_next = url('files_home', repo_name=c.repo_name,
127 c.url_next = url('files_home', repo_name=c.repo_name,
126 revision=next_rev.raw_id, f_path=f_path)
128 revision=next_rev.raw_id, f_path=f_path)
127 if c.branch:
129 if c.branch:
128 c.url_next += '?branch=%s' % c.branch
130 c.url_next += '?branch=%s' % c.branch
129 except (ChangesetDoesNotExistError, VCSError):
131 except (ChangesetDoesNotExistError, VCSError):
130 c.url_next = '#'
132 c.url_next = '#'
131
133
132 #files or dirs
134 #files or dirs
133 try:
135 try:
134 c.files_list = c.changeset.get_node(f_path)
136 c.files_list = c.changeset.get_node(f_path)
135
137
136 if c.files_list.is_file():
138 if c.files_list.is_file():
137 c.file_history = self._get_node_history(c.changeset, f_path)
139 c.file_history = self._get_node_history(c.changeset, f_path)
138 else:
140 else:
139 c.file_history = []
141 c.file_history = []
140 except RepositoryError, e:
142 except RepositoryError, e:
141 h.flash(str(e), category='warning')
143 h.flash(str(e), category='warning')
142 redirect(h.url('files_home', repo_name=repo_name,
144 redirect(h.url('files_home', repo_name=repo_name,
143 revision=revision))
145 revision=revision))
144
146
145 return render('files/files.html')
147 return render('files/files.html')
146
148
149 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
150 'repository.admin')
147 def rawfile(self, repo_name, revision, f_path):
151 def rawfile(self, repo_name, revision, f_path):
148 cs = self.__get_cs_or_redirect(revision, repo_name)
152 cs = self.__get_cs_or_redirect(revision, repo_name)
149 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
153 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
150
154
151 response.content_disposition = 'attachment; filename=%s' % \
155 response.content_disposition = 'attachment; filename=%s' % \
152 f_path.split(os.sep)[-1].encode('utf8', 'replace')
156 f_path.split(os.sep)[-1].encode('utf8', 'replace')
153
157
154 response.content_type = file_node.mimetype
158 response.content_type = file_node.mimetype
155 return file_node.content
159 return file_node.content
156
160
161 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
162 'repository.admin')
157 def raw(self, repo_name, revision, f_path):
163 def raw(self, repo_name, revision, f_path):
158 cs = self.__get_cs_or_redirect(revision, repo_name)
164 cs = self.__get_cs_or_redirect(revision, repo_name)
159 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
165 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
160
166
161 raw_mimetype_mapping = {
167 raw_mimetype_mapping = {
162 # map original mimetype to a mimetype used for "show as raw"
168 # map original mimetype to a mimetype used for "show as raw"
163 # you can also provide a content-disposition to override the
169 # you can also provide a content-disposition to override the
164 # default "attachment" disposition.
170 # default "attachment" disposition.
165 # orig_type: (new_type, new_dispo)
171 # orig_type: (new_type, new_dispo)
166
172
167 # show images inline:
173 # show images inline:
168 'image/x-icon': ('image/x-icon', 'inline'),
174 'image/x-icon': ('image/x-icon', 'inline'),
169 'image/png': ('image/png', 'inline'),
175 'image/png': ('image/png', 'inline'),
170 'image/gif': ('image/gif', 'inline'),
176 'image/gif': ('image/gif', 'inline'),
171 'image/jpeg': ('image/jpeg', 'inline'),
177 'image/jpeg': ('image/jpeg', 'inline'),
172 'image/svg+xml': ('image/svg+xml', 'inline'),
178 'image/svg+xml': ('image/svg+xml', 'inline'),
173 }
179 }
174
180
175 mimetype = file_node.mimetype
181 mimetype = file_node.mimetype
176 try:
182 try:
177 mimetype, dispo = raw_mimetype_mapping[mimetype]
183 mimetype, dispo = raw_mimetype_mapping[mimetype]
178 except KeyError:
184 except KeyError:
179 # we don't know anything special about this, handle it safely
185 # we don't know anything special about this, handle it safely
180 if file_node.is_binary:
186 if file_node.is_binary:
181 # do same as download raw for binary files
187 # do same as download raw for binary files
182 mimetype, dispo = 'application/octet-stream', 'attachment'
188 mimetype, dispo = 'application/octet-stream', 'attachment'
183 else:
189 else:
184 # do not just use the original mimetype, but force text/plain,
190 # do not just use the original mimetype, but force text/plain,
185 # otherwise it would serve text/html and that might be unsafe.
191 # otherwise it would serve text/html and that might be unsafe.
186 # Note: underlying vcs library fakes text/plain mimetype if the
192 # Note: underlying vcs library fakes text/plain mimetype if the
187 # mimetype can not be determined and it thinks it is not
193 # mimetype can not be determined and it thinks it is not
188 # binary.This might lead to erroneous text display in some
194 # binary.This might lead to erroneous text display in some
189 # cases, but helps in other cases, like with text files
195 # cases, but helps in other cases, like with text files
190 # without extension.
196 # without extension.
191 mimetype, dispo = 'text/plain', 'inline'
197 mimetype, dispo = 'text/plain', 'inline'
192
198
193 if dispo == 'attachment':
199 if dispo == 'attachment':
194 dispo = 'attachment; filename=%s' % \
200 dispo = 'attachment; filename=%s' % \
195 f_path.split(os.sep)[-1].encode('utf8', 'replace')
201 f_path.split(os.sep)[-1].encode('utf8', 'replace')
196
202
197 response.content_disposition = dispo
203 response.content_disposition = dispo
198 response.content_type = mimetype
204 response.content_type = mimetype
199 return file_node.content
205 return file_node.content
200
206
207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
208 'repository.admin')
201 def annotate(self, repo_name, revision, f_path):
209 def annotate(self, repo_name, revision, f_path):
202 c.cs = self.__get_cs_or_redirect(revision, repo_name)
210 c.cs = self.__get_cs_or_redirect(revision, repo_name)
203 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
211 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
204
212
205 c.file_history = self._get_node_history(c.cs, f_path)
213 c.file_history = self._get_node_history(c.cs, f_path)
206 c.f_path = f_path
214 c.f_path = f_path
207 return render('files/files_annotate.html')
215 return render('files/files_annotate.html')
208
216
217 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
218 def edit(self, repo_name, revision, f_path):
219 r_post = request.POST
220
221 if c.rhodecode_repo.alias == 'hg':
222 from vcs.backends.hg import MercurialInMemoryChangeset as IMC
223 elif c.rhodecode_repo.alias == 'git':
224 from vcs.backends.git import GitInMemoryChangeset as IMC
225
226 c.cs = self.__get_cs_or_redirect(revision, repo_name)
227 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
228
229 c.file_history = self._get_node_history(c.cs, f_path)
230 c.f_path = f_path
231
232 if r_post:
233
234 old_content = c.file.content
235 # modes: 0 - Unix, 1 - Mac, 2 - DOS
236 mode = detect_mode(old_content.splitlines(1)[0], 0)
237 content = convert_line_endings(r_post.get('content'), mode)
238 message = r_post.get('message') or (_('Edited %s via RhodeCode')
239 % (f_path))
240
241 if content == old_content:
242 h.flash(_('No changes'),
243 category='warning')
244 return redirect(url('changeset_home',
245 repo_name=c.repo_name, revision='tip'))
246 try:
247 new_node = FileNode(f_path, content)
248 m = IMC(c.rhodecode_repo)
249 m.change(new_node)
250 m.commit(message=message,
251 author=self.rhodecode_user.full_contact,
252 parents=[c.cs], branch=c.cs.branch)
253 h.flash(_('Successfully committed to %s' % f_path),
254 category='success')
255 except Exception, e:
256 log.error(traceback.format_exc())
257 h.flash(_('Error occurred during commit'), category='error')
258 return redirect(url('changeset_home',
259 repo_name=c.repo_name, revision='tip'))
260
261 return render('files/files_edit.html')
262
263 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
264 'repository.admin')
209 def archivefile(self, repo_name, fname):
265 def archivefile(self, repo_name, fname):
210
266
211 fileformat = None
267 fileformat = None
212 revision = None
268 revision = None
213 ext = None
269 ext = None
214
270
215 for a_type, ext_data in ARCHIVE_SPECS.items():
271 for a_type, ext_data in ARCHIVE_SPECS.items():
216 archive_spec = fname.split(ext_data[1])
272 archive_spec = fname.split(ext_data[1])
217 if len(archive_spec) == 2 and archive_spec[1] == '':
273 if len(archive_spec) == 2 and archive_spec[1] == '':
218 fileformat = a_type or ext_data[1]
274 fileformat = a_type or ext_data[1]
219 revision = archive_spec[0]
275 revision = archive_spec[0]
220 ext = ext_data[1]
276 ext = ext_data[1]
221
277
222 try:
278 try:
223 dbrepo = RepoModel().get_by_repo_name(repo_name)
279 dbrepo = RepoModel().get_by_repo_name(repo_name)
224 if dbrepo.enable_downloads is False:
280 if dbrepo.enable_downloads is False:
225 return _('downloads disabled')
281 return _('downloads disabled')
226
282
227 cs = c.rhodecode_repo.get_changeset(revision)
283 cs = c.rhodecode_repo.get_changeset(revision)
228 content_type = ARCHIVE_SPECS[fileformat][0]
284 content_type = ARCHIVE_SPECS[fileformat][0]
229 except ChangesetDoesNotExistError:
285 except ChangesetDoesNotExistError:
230 return _('Unknown revision %s') % revision
286 return _('Unknown revision %s') % revision
231 except EmptyRepositoryError:
287 except EmptyRepositoryError:
232 return _('Empty repository')
288 return _('Empty repository')
233 except (ImproperArchiveTypeError, KeyError):
289 except (ImproperArchiveTypeError, KeyError):
234 return _('Unknown archive type')
290 return _('Unknown archive type')
235
291
236 response.content_type = content_type
292 response.content_type = content_type
237 response.content_disposition = 'attachment; filename=%s-%s%s' \
293 response.content_disposition = 'attachment; filename=%s-%s%s' \
238 % (repo_name, revision, ext)
294 % (repo_name, revision, ext)
239
295
240 return cs.get_chunked_archive(stream=None, kind=fileformat)
296 return cs.get_chunked_archive(stream=None, kind=fileformat)
241
297
298 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
299 'repository.admin')
242 def diff(self, repo_name, f_path):
300 def diff(self, repo_name, f_path):
243 diff1 = request.GET.get('diff1')
301 diff1 = request.GET.get('diff1')
244 diff2 = request.GET.get('diff2')
302 diff2 = request.GET.get('diff2')
245 c.action = request.GET.get('diff')
303 c.action = request.GET.get('diff')
246 c.no_changes = diff1 == diff2
304 c.no_changes = diff1 == diff2
247 c.f_path = f_path
305 c.f_path = f_path
248 c.big_diff = False
306 c.big_diff = False
249
307
250 try:
308 try:
251 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
309 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
252 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
310 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
253 node1 = c.changeset_1.get_node(f_path)
311 node1 = c.changeset_1.get_node(f_path)
254 else:
312 else:
255 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
313 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
256 node1 = FileNode('.', '', changeset=c.changeset_1)
314 node1 = FileNode('.', '', changeset=c.changeset_1)
257
315
258 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
316 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
259 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
317 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
260 node2 = c.changeset_2.get_node(f_path)
318 node2 = c.changeset_2.get_node(f_path)
261 else:
319 else:
262 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
320 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
263 node2 = FileNode('.', '', changeset=c.changeset_2)
321 node2 = FileNode('.', '', changeset=c.changeset_2)
264 except RepositoryError:
322 except RepositoryError:
265 return redirect(url('files_home',
323 return redirect(url('files_home',
266 repo_name=c.repo_name, f_path=f_path))
324 repo_name=c.repo_name, f_path=f_path))
267
325
268 if c.action == 'download':
326 if c.action == 'download':
269 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
327 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
270 format='gitdiff')
328 format='gitdiff')
271
329
272 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
330 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
273 response.content_type = 'text/plain'
331 response.content_type = 'text/plain'
274 response.content_disposition = 'attachment; filename=%s' \
332 response.content_disposition = 'attachment; filename=%s' \
275 % diff_name
333 % diff_name
276 return diff.raw_diff()
334 return diff.raw_diff()
277
335
278 elif c.action == 'raw':
336 elif c.action == 'raw':
279 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
337 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
280 format='gitdiff')
338 format='gitdiff')
281 response.content_type = 'text/plain'
339 response.content_type = 'text/plain'
282 return diff.raw_diff()
340 return diff.raw_diff()
283
341
284 elif c.action == 'diff':
342 elif c.action == 'diff':
285
286 if node1.is_binary or node2.is_binary:
343 if node1.is_binary or node2.is_binary:
287 c.cur_diff = _('Binary file')
344 c.cur_diff = _('Binary file')
288 elif node1.size > self.cut_off_limit or \
345 elif node1.size > self.cut_off_limit or \
289 node2.size > self.cut_off_limit:
346 node2.size > self.cut_off_limit:
290 c.cur_diff = ''
347 c.cur_diff = ''
291 c.big_diff = True
348 c.big_diff = True
292 else:
349 else:
293 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
350 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
294 format='gitdiff')
351 format='gitdiff')
295 c.cur_diff = diff.as_html()
352 c.cur_diff = diff.as_html()
296 else:
353 else:
297
354
298 #default option
355 #default option
299 if node1.is_binary or node2.is_binary:
356 if node1.is_binary or node2.is_binary:
300 c.cur_diff = _('Binary file')
357 c.cur_diff = _('Binary file')
301 elif node1.size > self.cut_off_limit or \
358 elif node1.size > self.cut_off_limit or \
302 node2.size > self.cut_off_limit:
359 node2.size > self.cut_off_limit:
303 c.cur_diff = ''
360 c.cur_diff = ''
304 c.big_diff = True
361 c.big_diff = True
305
362
306 else:
363 else:
307 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
364 diff = differ.DiffProcessor(differ.get_gitdiff(node1, node2),
308 format='gitdiff')
365 format='gitdiff')
309 c.cur_diff = diff.as_html()
366 c.cur_diff = diff.as_html()
310
367
311 if not c.cur_diff and not c.big_diff:
368 if not c.cur_diff and not c.big_diff:
312 c.no_changes = True
369 c.no_changes = True
313 return render('files/file_diff.html')
370 return render('files/file_diff.html')
314
371
315 def _get_node_history(self, cs, f_path):
372 def _get_node_history(self, cs, f_path):
316 changesets = cs.get_file_history(f_path)
373 changesets = cs.get_file_history(f_path)
317 hist_l = []
374 hist_l = []
318
375
319 changesets_group = ([], _("Changesets"))
376 changesets_group = ([], _("Changesets"))
320 branches_group = ([], _("Branches"))
377 branches_group = ([], _("Branches"))
321 tags_group = ([], _("Tags"))
378 tags_group = ([], _("Tags"))
322
379
323 for chs in changesets:
380 for chs in changesets:
324 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
381 n_desc = 'r%s:%s' % (chs.revision, chs.short_id)
325 changesets_group[0].append((chs.raw_id, n_desc,))
382 changesets_group[0].append((chs.raw_id, n_desc,))
326
383
327 hist_l.append(changesets_group)
384 hist_l.append(changesets_group)
328
385
329 for name, chs in c.rhodecode_repo.branches.items():
386 for name, chs in c.rhodecode_repo.branches.items():
330 #chs = chs.split(':')[-1]
387 #chs = chs.split(':')[-1]
331 branches_group[0].append((chs, name),)
388 branches_group[0].append((chs, name),)
332 hist_l.append(branches_group)
389 hist_l.append(branches_group)
333
390
334 for name, chs in c.rhodecode_repo.tags.items():
391 for name, chs in c.rhodecode_repo.tags.items():
335 #chs = chs.split(':')[-1]
392 #chs = chs.split(':')[-1]
336 tags_group[0].append((chs, name),)
393 tags_group[0].append((chs, name),)
337 hist_l.append(tags_group)
394 hist_l.append(tags_group)
338
395
339 return hist_l
396 return hist_l
@@ -1,142 +1,166 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.__init__
3 rhodecode.lib.__init__
4 ~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Some simple helper functions
6 Some simple helper functions
7
7
8 :created_on: Jan 5, 2011
8 :created_on: Jan 5, 2011
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26
26
27
27
28 def __get_lem():
28 def __get_lem():
29 from pygments import lexers
29 from pygments import lexers
30 from string import lower
30 from string import lower
31 from collections import defaultdict
31 from collections import defaultdict
32
32
33 d = defaultdict(lambda: [])
33 d = defaultdict(lambda: [])
34
34
35 def __clean(s):
35 def __clean(s):
36 s = s.lstrip('*')
36 s = s.lstrip('*')
37 s = s.lstrip('.')
37 s = s.lstrip('.')
38
38
39 if s.find('[') != -1:
39 if s.find('[') != -1:
40 exts = []
40 exts = []
41 start, stop = s.find('['), s.find(']')
41 start, stop = s.find('['), s.find(']')
42
42
43 for suffix in s[start + 1:stop]:
43 for suffix in s[start + 1:stop]:
44 exts.append(s[:s.find('[')] + suffix)
44 exts.append(s[:s.find('[')] + suffix)
45 return map(lower, exts)
45 return map(lower, exts)
46 else:
46 else:
47 return map(lower, [s])
47 return map(lower, [s])
48
48
49 for lx, t in sorted(lexers.LEXERS.items()):
49 for lx, t in sorted(lexers.LEXERS.items()):
50 m = map(__clean, t[-2])
50 m = map(__clean, t[-2])
51 if m:
51 if m:
52 m = reduce(lambda x, y: x + y, m)
52 m = reduce(lambda x, y: x + y, m)
53 for ext in m:
53 for ext in m:
54 desc = lx.replace('Lexer', '')
54 desc = lx.replace('Lexer', '')
55 d[ext].append(desc)
55 d[ext].append(desc)
56
56
57 return dict(d)
57 return dict(d)
58
58
59 # language map is also used by whoosh indexer, which for those specified
59 # language map is also used by whoosh indexer, which for those specified
60 # extensions will index it's content
60 # extensions will index it's content
61 LANGUAGES_EXTENSIONS_MAP = __get_lem()
61 LANGUAGES_EXTENSIONS_MAP = __get_lem()
62
62
63 #Additional mappings that are not present in the pygments lexers
63 #Additional mappings that are not present in the pygments lexers
64 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
64 # NOTE: that this will overide any mappings in LANGUAGES_EXTENSIONS_MAP
65 ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}
65 ADDITIONAL_MAPPINGS = {'xaml': 'XAML'}
66
66
67 LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS)
67 LANGUAGES_EXTENSIONS_MAP.update(ADDITIONAL_MAPPINGS)
68
68
69 def str2bool(_str):
69 def str2bool(_str):
70 """
70 """
71 returs True/False value from given string, it tries to translate the
71 returs True/False value from given string, it tries to translate the
72 string into boolean
72 string into boolean
73
73
74 :param _str: string value to translate into boolean
74 :param _str: string value to translate into boolean
75 :rtype: boolean
75 :rtype: boolean
76 :returns: boolean from given string
76 :returns: boolean from given string
77 """
77 """
78 if _str is None:
78 if _str is None:
79 return False
79 return False
80 if _str in (True, False):
80 if _str in (True, False):
81 return _str
81 return _str
82 _str = str(_str).strip().lower()
82 _str = str(_str).strip().lower()
83 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
83 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
84
84
85 def convert_line_endings(temp, mode):
86 from string import replace
87 #modes: 0 - Unix, 1 - Mac, 2 - DOS
88 if mode == 0:
89 temp = replace(temp, '\r\n', '\n')
90 temp = replace(temp, '\r', '\n')
91 elif mode == 1:
92 temp = replace(temp, '\r\n', '\r')
93 temp = replace(temp, '\n', '\r')
94 elif mode == 2:
95 import re
96 temp = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", temp)
97 return temp
98
99
100 def detect_mode(line, default):
101 if line.endswith('\r\n'):
102 return 2
103 elif line.endswith('\n'):
104 return 0
105 elif line.endswith('\r'):
106 return 1
107 else:
108 return default
85
109
86 def generate_api_key(username, salt=None):
110 def generate_api_key(username, salt=None):
87 """
111 """
88 Generates unique API key for given username,if salt is not given
112 Generates unique API key for given username,if salt is not given
89 it'll be generated from some random string
113 it'll be generated from some random string
90
114
91 :param username: username as string
115 :param username: username as string
92 :param salt: salt to hash generate KEY
116 :param salt: salt to hash generate KEY
93 :rtype: str
117 :rtype: str
94 :returns: sha1 hash from username+salt
118 :returns: sha1 hash from username+salt
95 """
119 """
96 from tempfile import _RandomNameSequence
120 from tempfile import _RandomNameSequence
97 import hashlib
121 import hashlib
98
122
99 if salt is None:
123 if salt is None:
100 salt = _RandomNameSequence().next()
124 salt = _RandomNameSequence().next()
101
125
102 return hashlib.sha1(username + salt).hexdigest()
126 return hashlib.sha1(username + salt).hexdigest()
103
127
104
128
105 def safe_unicode(_str, from_encoding='utf8'):
129 def safe_unicode(_str, from_encoding='utf8'):
106 """
130 """
107 safe unicode function. In case of UnicodeDecode error we try to return
131 safe unicode function. In case of UnicodeDecode error we try to return
108 unicode with errors replace
132 unicode with errors replace
109
133
110 :param _str: string to decode
134 :param _str: string to decode
111 :rtype: unicode
135 :rtype: unicode
112 :returns: unicode object
136 :returns: unicode object
113 """
137 """
114
138
115 if isinstance(_str, unicode):
139 if isinstance(_str, unicode):
116 return _str
140 return _str
117
141
118 try:
142 try:
119 u_str = unicode(_str, from_encoding)
143 u_str = unicode(_str, from_encoding)
120 except UnicodeDecodeError:
144 except UnicodeDecodeError:
121 u_str = unicode(_str, from_encoding, 'replace')
145 u_str = unicode(_str, from_encoding, 'replace')
122
146
123 return u_str
147 return u_str
124
148
125
149
126 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
150 def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
127 """
151 """
128 Custom engine_from_config functions that makes sure we use NullPool for
152 Custom engine_from_config functions that makes sure we use NullPool for
129 file based sqlite databases. This prevents errors on sqlite.
153 file based sqlite databases. This prevents errors on sqlite.
130
154
131 """
155 """
132 from sqlalchemy import engine_from_config as efc
156 from sqlalchemy import engine_from_config as efc
133 from sqlalchemy.pool import NullPool
157 from sqlalchemy.pool import NullPool
134
158
135 url = configuration[prefix + 'url']
159 url = configuration[prefix + 'url']
136
160
137 if url.startswith('sqlite'):
161 if url.startswith('sqlite'):
138 kwargs.update({'poolclass':NullPool})
162 kwargs.update({'poolclass':NullPool})
139
163
140 return efc(configuration, prefix, **kwargs)
164 return efc(configuration, prefix, **kwargs)
141
165
142
166
@@ -1,601 +1,605 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.auth
3 rhodecode.lib.auth
4 ~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~
5
5
6 authentication and permission libraries
6 authentication and permission libraries
7
7
8 :created_on: Apr 4, 2010
8 :created_on: Apr 4, 2010
9 :copyright: (c) 2010 by marcink.
9 :copyright: (c) 2010 by marcink.
10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
10 :license: LICENSE_NAME, see LICENSE_FILE for more details.
11 """
11 """
12 # This program is free software: you can redistribute it and/or modify
12 # This program is free software: you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation, either version 3 of the License, or
14 # the Free Software Foundation, either version 3 of the License, or
15 # (at your option) any later version.
15 # (at your option) any later version.
16 #
16 #
17 # This program is distributed in the hope that it will be useful,
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
20 # GNU General Public License for more details.
21 #
21 #
22 # You should have received a copy of the GNU General Public License
22 # You should have received a copy of the GNU General Public License
23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
23 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24
24
25 import random
25 import random
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import hashlib
28 import hashlib
29
29
30 from tempfile import _RandomNameSequence
30 from tempfile import _RandomNameSequence
31 from decorator import decorator
31 from decorator import decorator
32
32
33 from pylons import config, session, url, request
33 from pylons import config, session, url, request
34 from pylons.controllers.util import abort, redirect
34 from pylons.controllers.util import abort, redirect
35 from pylons.i18n.translation import _
35 from pylons.i18n.translation import _
36
36
37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
37 from rhodecode import __platform__, PLATFORM_WIN, PLATFORM_OTHERS
38
38
39 if __platform__ in PLATFORM_WIN:
39 if __platform__ in PLATFORM_WIN:
40 from hashlib import sha256
40 from hashlib import sha256
41 if __platform__ in PLATFORM_OTHERS:
41 if __platform__ in PLATFORM_OTHERS:
42 import bcrypt
42 import bcrypt
43
43
44 from rhodecode.lib import str2bool
44 from rhodecode.lib import str2bool
45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
45 from rhodecode.lib.exceptions import LdapPasswordError, LdapUsernameError
46 from rhodecode.lib.utils import get_repo_slug
46 from rhodecode.lib.utils import get_repo_slug
47 from rhodecode.lib.auth_ldap import AuthLdap
47 from rhodecode.lib.auth_ldap import AuthLdap
48
48
49 from rhodecode.model import meta
49 from rhodecode.model import meta
50 from rhodecode.model.user import UserModel
50 from rhodecode.model.user import UserModel
51 from rhodecode.model.db import Permission, RhodeCodeSettings
51 from rhodecode.model.db import Permission, RhodeCodeSettings
52
52
53 log = logging.getLogger(__name__)
53 log = logging.getLogger(__name__)
54
54
55
55
56 class PasswordGenerator(object):
56 class PasswordGenerator(object):
57 """This is a simple class for generating password from
57 """This is a simple class for generating password from
58 different sets of characters
58 different sets of characters
59 usage:
59 usage:
60 passwd_gen = PasswordGenerator()
60 passwd_gen = PasswordGenerator()
61 #print 8-letter password containing only big and small letters
61 #print 8-letter password containing only big and small letters
62 of alphabet
62 of alphabet
63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
63 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
64 """
64 """
65 ALPHABETS_NUM = r'''1234567890'''
65 ALPHABETS_NUM = r'''1234567890'''
66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
66 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''
67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
67 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''
68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
68 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?'''
69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
69 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL \
70 + ALPHABETS_NUM + ALPHABETS_SPECIAL
70 + ALPHABETS_NUM + ALPHABETS_SPECIAL
71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
71 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM
72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
72 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
73 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM
74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
74 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM
75
75
76 def __init__(self, passwd=''):
76 def __init__(self, passwd=''):
77 self.passwd = passwd
77 self.passwd = passwd
78
78
79 def gen_password(self, len, type):
79 def gen_password(self, len, type):
80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
80 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
81 return self.passwd
81 return self.passwd
82
82
83
83
84 class RhodeCodeCrypto(object):
84 class RhodeCodeCrypto(object):
85
85
86 @classmethod
86 @classmethod
87 def hash_string(cls, str_):
87 def hash_string(cls, str_):
88 """
88 """
89 Cryptographic function used for password hashing based on pybcrypt
89 Cryptographic function used for password hashing based on pybcrypt
90 or pycrypto in windows
90 or pycrypto in windows
91
91
92 :param password: password to hash
92 :param password: password to hash
93 """
93 """
94 if __platform__ in PLATFORM_WIN:
94 if __platform__ in PLATFORM_WIN:
95 return sha256(str_).hexdigest()
95 return sha256(str_).hexdigest()
96 elif __platform__ in PLATFORM_OTHERS:
96 elif __platform__ in PLATFORM_OTHERS:
97 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
97 return bcrypt.hashpw(str_, bcrypt.gensalt(10))
98 else:
98 else:
99 raise Exception('Unknown or unsupported platform %s' \
99 raise Exception('Unknown or unsupported platform %s' \
100 % __platform__)
100 % __platform__)
101
101
102 @classmethod
102 @classmethod
103 def hash_check(cls, password, hashed):
103 def hash_check(cls, password, hashed):
104 """
104 """
105 Checks matching password with it's hashed value, runs different
105 Checks matching password with it's hashed value, runs different
106 implementation based on platform it runs on
106 implementation based on platform it runs on
107
107
108 :param password: password
108 :param password: password
109 :param hashed: password in hashed form
109 :param hashed: password in hashed form
110 """
110 """
111
111
112 if __platform__ in PLATFORM_WIN:
112 if __platform__ in PLATFORM_WIN:
113 return sha256(password).hexdigest() == hashed
113 return sha256(password).hexdigest() == hashed
114 elif __platform__ in PLATFORM_OTHERS:
114 elif __platform__ in PLATFORM_OTHERS:
115 return bcrypt.hashpw(password, hashed) == hashed
115 return bcrypt.hashpw(password, hashed) == hashed
116 else:
116 else:
117 raise Exception('Unknown or unsupported platform %s' \
117 raise Exception('Unknown or unsupported platform %s' \
118 % __platform__)
118 % __platform__)
119
119
120
120
121 def get_crypt_password(password):
121 def get_crypt_password(password):
122 return RhodeCodeCrypto.hash_string(password)
122 return RhodeCodeCrypto.hash_string(password)
123
123
124
124
125 def check_password(password, hashed):
125 def check_password(password, hashed):
126 return RhodeCodeCrypto.hash_check(password, hashed)
126 return RhodeCodeCrypto.hash_check(password, hashed)
127
127
128
128
129 def generate_api_key(username, salt=None):
129 def generate_api_key(username, salt=None):
130 if salt is None:
130 if salt is None:
131 salt = _RandomNameSequence().next()
131 salt = _RandomNameSequence().next()
132
132
133 return hashlib.sha1(username + salt).hexdigest()
133 return hashlib.sha1(username + salt).hexdigest()
134
134
135
135
136 def authfunc(environ, username, password):
136 def authfunc(environ, username, password):
137 """Dummy authentication function used in Mercurial/Git/ and access control,
137 """Dummy authentication function used in Mercurial/Git/ and access control,
138
138
139 :param environ: needed only for using in Basic auth
139 :param environ: needed only for using in Basic auth
140 """
140 """
141 return authenticate(username, password)
141 return authenticate(username, password)
142
142
143
143
144 def authenticate(username, password):
144 def authenticate(username, password):
145 """Authentication function used for access control,
145 """Authentication function used for access control,
146 firstly checks for db authentication then if ldap is enabled for ldap
146 firstly checks for db authentication then if ldap is enabled for ldap
147 authentication, also creates ldap user if not in database
147 authentication, also creates ldap user if not in database
148
148
149 :param username: username
149 :param username: username
150 :param password: password
150 :param password: password
151 """
151 """
152
152
153 user_model = UserModel()
153 user_model = UserModel()
154 user = user_model.get_by_username(username, cache=False)
154 user = user_model.get_by_username(username, cache=False)
155
155
156 log.debug('Authenticating user using RhodeCode account')
156 log.debug('Authenticating user using RhodeCode account')
157 if user is not None and not user.ldap_dn:
157 if user is not None and not user.ldap_dn:
158 if user.active:
158 if user.active:
159 if user.username == 'default' and user.active:
159 if user.username == 'default' and user.active:
160 log.info('user %s authenticated correctly as anonymous user',
160 log.info('user %s authenticated correctly as anonymous user',
161 username)
161 username)
162 return True
162 return True
163
163
164 elif user.username == username and check_password(password,
164 elif user.username == username and check_password(password,
165 user.password):
165 user.password):
166 log.info('user %s authenticated correctly', username)
166 log.info('user %s authenticated correctly', username)
167 return True
167 return True
168 else:
168 else:
169 log.warning('user %s is disabled', username)
169 log.warning('user %s is disabled', username)
170
170
171 else:
171 else:
172 log.debug('Regular authentication failed')
172 log.debug('Regular authentication failed')
173 user_obj = user_model.get_by_username(username, cache=False,
173 user_obj = user_model.get_by_username(username, cache=False,
174 case_insensitive=True)
174 case_insensitive=True)
175
175
176 if user_obj is not None and not user_obj.ldap_dn:
176 if user_obj is not None and not user_obj.ldap_dn:
177 log.debug('this user already exists as non ldap')
177 log.debug('this user already exists as non ldap')
178 return False
178 return False
179
179
180 ldap_settings = RhodeCodeSettings.get_ldap_settings()
180 ldap_settings = RhodeCodeSettings.get_ldap_settings()
181 #======================================================================
181 #======================================================================
182 # FALLBACK TO LDAP AUTH IF ENABLE
182 # FALLBACK TO LDAP AUTH IF ENABLE
183 #======================================================================
183 #======================================================================
184 if str2bool(ldap_settings.get('ldap_active')):
184 if str2bool(ldap_settings.get('ldap_active')):
185 log.debug("Authenticating user using ldap")
185 log.debug("Authenticating user using ldap")
186 kwargs = {
186 kwargs = {
187 'server': ldap_settings.get('ldap_host', ''),
187 'server': ldap_settings.get('ldap_host', ''),
188 'base_dn': ldap_settings.get('ldap_base_dn', ''),
188 'base_dn': ldap_settings.get('ldap_base_dn', ''),
189 'port': ldap_settings.get('ldap_port'),
189 'port': ldap_settings.get('ldap_port'),
190 'bind_dn': ldap_settings.get('ldap_dn_user'),
190 'bind_dn': ldap_settings.get('ldap_dn_user'),
191 'bind_pass': ldap_settings.get('ldap_dn_pass'),
191 'bind_pass': ldap_settings.get('ldap_dn_pass'),
192 'tls_kind': ldap_settings.get('ldap_tls_kind'),
192 'tls_kind': ldap_settings.get('ldap_tls_kind'),
193 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
193 'tls_reqcert': ldap_settings.get('ldap_tls_reqcert'),
194 'ldap_filter': ldap_settings.get('ldap_filter'),
194 'ldap_filter': ldap_settings.get('ldap_filter'),
195 'search_scope': ldap_settings.get('ldap_search_scope'),
195 'search_scope': ldap_settings.get('ldap_search_scope'),
196 'attr_login': ldap_settings.get('ldap_attr_login'),
196 'attr_login': ldap_settings.get('ldap_attr_login'),
197 'ldap_version': 3,
197 'ldap_version': 3,
198 }
198 }
199 log.debug('Checking for ldap authentication')
199 log.debug('Checking for ldap authentication')
200 try:
200 try:
201 aldap = AuthLdap(**kwargs)
201 aldap = AuthLdap(**kwargs)
202 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
202 (user_dn, ldap_attrs) = aldap.authenticate_ldap(username,
203 password)
203 password)
204 log.debug('Got ldap DN response %s', user_dn)
204 log.debug('Got ldap DN response %s', user_dn)
205
205
206 get_ldap_attr = lambda k:ldap_attrs.get(ldap_settings\
206 get_ldap_attr = lambda k:ldap_attrs.get(ldap_settings\
207 .get(k), [''])[0]
207 .get(k), [''])[0]
208
208
209 user_attrs = {
209 user_attrs = {
210 'name': get_ldap_attr('ldap_attr_firstname'),
210 'name': get_ldap_attr('ldap_attr_firstname'),
211 'lastname': get_ldap_attr('ldap_attr_lastname'),
211 'lastname': get_ldap_attr('ldap_attr_lastname'),
212 'email': get_ldap_attr('ldap_attr_email'),
212 'email': get_ldap_attr('ldap_attr_email'),
213 }
213 }
214
214
215 if user_model.create_ldap(username, password, user_dn,
215 if user_model.create_ldap(username, password, user_dn,
216 user_attrs):
216 user_attrs):
217 log.info('created new ldap user %s', username)
217 log.info('created new ldap user %s', username)
218
218
219 return True
219 return True
220 except (LdapUsernameError, LdapPasswordError,):
220 except (LdapUsernameError, LdapPasswordError,):
221 pass
221 pass
222 except (Exception,):
222 except (Exception,):
223 log.error(traceback.format_exc())
223 log.error(traceback.format_exc())
224 pass
224 pass
225 return False
225 return False
226
226
227
227
228 class AuthUser(object):
228 class AuthUser(object):
229 """
229 """
230 A simple object that handles all attributes of user in RhodeCode
230 A simple object that handles all attributes of user in RhodeCode
231
231
232 It does lookup based on API key,given user, or user present in session
232 It does lookup based on API key,given user, or user present in session
233 Then it fills all required information for such user. It also checks if
233 Then it fills all required information for such user. It also checks if
234 anonymous access is enabled and if so, it returns default user as logged
234 anonymous access is enabled and if so, it returns default user as logged
235 in
235 in
236 """
236 """
237
237
238 def __init__(self, user_id=None, api_key=None):
238 def __init__(self, user_id=None, api_key=None):
239
239
240 self.user_id = user_id
240 self.user_id = user_id
241 self.api_key = None
241 self.api_key = None
242
242
243 self.username = 'None'
243 self.username = 'None'
244 self.name = ''
244 self.name = ''
245 self.lastname = ''
245 self.lastname = ''
246 self.email = ''
246 self.email = ''
247 self.is_authenticated = False
247 self.is_authenticated = False
248 self.admin = False
248 self.admin = False
249 self.permissions = {}
249 self.permissions = {}
250 self._api_key = api_key
250 self._api_key = api_key
251 self.propagate_data()
251 self.propagate_data()
252
252
253 def propagate_data(self):
253 def propagate_data(self):
254 user_model = UserModel()
254 user_model = UserModel()
255 self.anonymous_user = user_model.get_by_username('default', cache=True)
255 self.anonymous_user = user_model.get_by_username('default', cache=True)
256 if self._api_key and self._api_key != self.anonymous_user.api_key:
256 if self._api_key and self._api_key != self.anonymous_user.api_key:
257 #try go get user by api key
257 #try go get user by api key
258 log.debug('Auth User lookup by API KEY %s', self._api_key)
258 log.debug('Auth User lookup by API KEY %s', self._api_key)
259 user_model.fill_data(self, api_key=self._api_key)
259 user_model.fill_data(self, api_key=self._api_key)
260 else:
260 else:
261 log.debug('Auth User lookup by USER ID %s', self.user_id)
261 log.debug('Auth User lookup by USER ID %s', self.user_id)
262 if self.user_id is not None \
262 if self.user_id is not None \
263 and self.user_id != self.anonymous_user.user_id:
263 and self.user_id != self.anonymous_user.user_id:
264 user_model.fill_data(self, user_id=self.user_id)
264 user_model.fill_data(self, user_id=self.user_id)
265 else:
265 else:
266 if self.anonymous_user.active is True:
266 if self.anonymous_user.active is True:
267 user_model.fill_data(self,
267 user_model.fill_data(self,
268 user_id=self.anonymous_user.user_id)
268 user_id=self.anonymous_user.user_id)
269 #then we set this user is logged in
269 #then we set this user is logged in
270 self.is_authenticated = True
270 self.is_authenticated = True
271 else:
271 else:
272 self.is_authenticated = False
272 self.is_authenticated = False
273
273
274 log.debug('Auth User is now %s', self)
274 log.debug('Auth User is now %s', self)
275 user_model.fill_perms(self)
275 user_model.fill_perms(self)
276
276
277 @property
277 @property
278 def is_admin(self):
278 def is_admin(self):
279 return self.admin
279 return self.admin
280
280
281 @property
282 def full_contact(self):
283 return '%s %s <%s>' % (self.name, self.lastname, self.email)
284
281 def __repr__(self):
285 def __repr__(self):
282 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
286 return "<AuthUser('id:%s:%s|%s')>" % (self.user_id, self.username,
283 self.is_authenticated)
287 self.is_authenticated)
284
288
285 def set_authenticated(self, authenticated=True):
289 def set_authenticated(self, authenticated=True):
286
290
287 if self.user_id != self.anonymous_user.user_id:
291 if self.user_id != self.anonymous_user.user_id:
288 self.is_authenticated = authenticated
292 self.is_authenticated = authenticated
289
293
290
294
291 def set_available_permissions(config):
295 def set_available_permissions(config):
292 """This function will propagate pylons globals with all available defined
296 """This function will propagate pylons globals with all available defined
293 permission given in db. We don't want to check each time from db for new
297 permission given in db. We don't want to check each time from db for new
294 permissions since adding a new permission also requires application restart
298 permissions since adding a new permission also requires application restart
295 ie. to decorate new views with the newly created permission
299 ie. to decorate new views with the newly created permission
296
300
297 :param config: current pylons config instance
301 :param config: current pylons config instance
298
302
299 """
303 """
300 log.info('getting information about all available permissions')
304 log.info('getting information about all available permissions')
301 try:
305 try:
302 sa = meta.Session()
306 sa = meta.Session()
303 all_perms = sa.query(Permission).all()
307 all_perms = sa.query(Permission).all()
304 except:
308 except:
305 pass
309 pass
306 finally:
310 finally:
307 meta.Session.remove()
311 meta.Session.remove()
308
312
309 config['available_permissions'] = [x.permission_name for x in all_perms]
313 config['available_permissions'] = [x.permission_name for x in all_perms]
310
314
311
315
312 #==============================================================================
316 #==============================================================================
313 # CHECK DECORATORS
317 # CHECK DECORATORS
314 #==============================================================================
318 #==============================================================================
315 class LoginRequired(object):
319 class LoginRequired(object):
316 """
320 """
317 Must be logged in to execute this function else
321 Must be logged in to execute this function else
318 redirect to login page
322 redirect to login page
319
323
320 :param api_access: if enabled this checks only for valid auth token
324 :param api_access: if enabled this checks only for valid auth token
321 and grants access based on valid token
325 and grants access based on valid token
322 """
326 """
323
327
324 def __init__(self, api_access=False):
328 def __init__(self, api_access=False):
325 self.api_access = api_access
329 self.api_access = api_access
326
330
327 def __call__(self, func):
331 def __call__(self, func):
328 return decorator(self.__wrapper, func)
332 return decorator(self.__wrapper, func)
329
333
330 def __wrapper(self, func, *fargs, **fkwargs):
334 def __wrapper(self, func, *fargs, **fkwargs):
331 cls = fargs[0]
335 cls = fargs[0]
332 user = cls.rhodecode_user
336 user = cls.rhodecode_user
333
337
334 api_access_ok = False
338 api_access_ok = False
335 if self.api_access:
339 if self.api_access:
336 log.debug('Checking API KEY access for %s', cls)
340 log.debug('Checking API KEY access for %s', cls)
337 if user.api_key == request.GET.get('api_key'):
341 if user.api_key == request.GET.get('api_key'):
338 api_access_ok = True
342 api_access_ok = True
339 else:
343 else:
340 log.debug("API KEY token not valid")
344 log.debug("API KEY token not valid")
341
345
342 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
346 log.debug('Checking if %s is authenticated @ %s', user.username, cls)
343 if user.is_authenticated or api_access_ok:
347 if user.is_authenticated or api_access_ok:
344 log.debug('user %s is authenticated', user.username)
348 log.debug('user %s is authenticated', user.username)
345 return func(*fargs, **fkwargs)
349 return func(*fargs, **fkwargs)
346 else:
350 else:
347 log.warn('user %s NOT authenticated', user.username)
351 log.warn('user %s NOT authenticated', user.username)
348 p = url.current()
352 p = url.current()
349
353
350 log.debug('redirecting to login page with %s', p)
354 log.debug('redirecting to login page with %s', p)
351 return redirect(url('login_home', came_from=p))
355 return redirect(url('login_home', came_from=p))
352
356
353
357
354 class NotAnonymous(object):
358 class NotAnonymous(object):
355 """Must be logged in to execute this function else
359 """Must be logged in to execute this function else
356 redirect to login page"""
360 redirect to login page"""
357
361
358 def __call__(self, func):
362 def __call__(self, func):
359 return decorator(self.__wrapper, func)
363 return decorator(self.__wrapper, func)
360
364
361 def __wrapper(self, func, *fargs, **fkwargs):
365 def __wrapper(self, func, *fargs, **fkwargs):
362 cls = fargs[0]
366 cls = fargs[0]
363 self.user = cls.rhodecode_user
367 self.user = cls.rhodecode_user
364
368
365 log.debug('Checking if user is not anonymous @%s', cls)
369 log.debug('Checking if user is not anonymous @%s', cls)
366
370
367 anonymous = self.user.username == 'default'
371 anonymous = self.user.username == 'default'
368
372
369 if anonymous:
373 if anonymous:
370 p = ''
374 p = ''
371 if request.environ.get('SCRIPT_NAME') != '/':
375 if request.environ.get('SCRIPT_NAME') != '/':
372 p += request.environ.get('SCRIPT_NAME')
376 p += request.environ.get('SCRIPT_NAME')
373
377
374 p += request.environ.get('PATH_INFO')
378 p += request.environ.get('PATH_INFO')
375 if request.environ.get('QUERY_STRING'):
379 if request.environ.get('QUERY_STRING'):
376 p += '?' + request.environ.get('QUERY_STRING')
380 p += '?' + request.environ.get('QUERY_STRING')
377
381
378 import rhodecode.lib.helpers as h
382 import rhodecode.lib.helpers as h
379 h.flash(_('You need to be a registered user to '
383 h.flash(_('You need to be a registered user to '
380 'perform this action'),
384 'perform this action'),
381 category='warning')
385 category='warning')
382 return redirect(url('login_home', came_from=p))
386 return redirect(url('login_home', came_from=p))
383 else:
387 else:
384 return func(*fargs, **fkwargs)
388 return func(*fargs, **fkwargs)
385
389
386
390
387 class PermsDecorator(object):
391 class PermsDecorator(object):
388 """Base class for controller decorators"""
392 """Base class for controller decorators"""
389
393
390 def __init__(self, *required_perms):
394 def __init__(self, *required_perms):
391 available_perms = config['available_permissions']
395 available_perms = config['available_permissions']
392 for perm in required_perms:
396 for perm in required_perms:
393 if perm not in available_perms:
397 if perm not in available_perms:
394 raise Exception("'%s' permission is not defined" % perm)
398 raise Exception("'%s' permission is not defined" % perm)
395 self.required_perms = set(required_perms)
399 self.required_perms = set(required_perms)
396 self.user_perms = None
400 self.user_perms = None
397
401
398 def __call__(self, func):
402 def __call__(self, func):
399 return decorator(self.__wrapper, func)
403 return decorator(self.__wrapper, func)
400
404
401 def __wrapper(self, func, *fargs, **fkwargs):
405 def __wrapper(self, func, *fargs, **fkwargs):
402 cls = fargs[0]
406 cls = fargs[0]
403 self.user = cls.rhodecode_user
407 self.user = cls.rhodecode_user
404 self.user_perms = self.user.permissions
408 self.user_perms = self.user.permissions
405 log.debug('checking %s permissions %s for %s %s',
409 log.debug('checking %s permissions %s for %s %s',
406 self.__class__.__name__, self.required_perms, cls,
410 self.__class__.__name__, self.required_perms, cls,
407 self.user)
411 self.user)
408
412
409 if self.check_permissions():
413 if self.check_permissions():
410 log.debug('Permission granted for %s %s', cls, self.user)
414 log.debug('Permission granted for %s %s', cls, self.user)
411 return func(*fargs, **fkwargs)
415 return func(*fargs, **fkwargs)
412
416
413 else:
417 else:
414 log.warning('Permission denied for %s %s', cls, self.user)
418 log.warning('Permission denied for %s %s', cls, self.user)
415 #redirect with forbidden ret code
419 #redirect with forbidden ret code
416 return abort(403)
420 return abort(403)
417
421
418 def check_permissions(self):
422 def check_permissions(self):
419 """Dummy function for overriding"""
423 """Dummy function for overriding"""
420 raise Exception('You have to write this function in child class')
424 raise Exception('You have to write this function in child class')
421
425
422
426
423 class HasPermissionAllDecorator(PermsDecorator):
427 class HasPermissionAllDecorator(PermsDecorator):
424 """Checks for access permission for all given predicates. All of them
428 """Checks for access permission for all given predicates. All of them
425 have to be meet in order to fulfill the request
429 have to be meet in order to fulfill the request
426 """
430 """
427
431
428 def check_permissions(self):
432 def check_permissions(self):
429 if self.required_perms.issubset(self.user_perms.get('global')):
433 if self.required_perms.issubset(self.user_perms.get('global')):
430 return True
434 return True
431 return False
435 return False
432
436
433
437
434 class HasPermissionAnyDecorator(PermsDecorator):
438 class HasPermissionAnyDecorator(PermsDecorator):
435 """Checks for access permission for any of given predicates. In order to
439 """Checks for access permission for any of given predicates. In order to
436 fulfill the request any of predicates must be meet
440 fulfill the request any of predicates must be meet
437 """
441 """
438
442
439 def check_permissions(self):
443 def check_permissions(self):
440 if self.required_perms.intersection(self.user_perms.get('global')):
444 if self.required_perms.intersection(self.user_perms.get('global')):
441 return True
445 return True
442 return False
446 return False
443
447
444
448
445 class HasRepoPermissionAllDecorator(PermsDecorator):
449 class HasRepoPermissionAllDecorator(PermsDecorator):
446 """Checks for access permission for all given predicates for specific
450 """Checks for access permission for all given predicates for specific
447 repository. All of them have to be meet in order to fulfill the request
451 repository. All of them have to be meet in order to fulfill the request
448 """
452 """
449
453
450 def check_permissions(self):
454 def check_permissions(self):
451 repo_name = get_repo_slug(request)
455 repo_name = get_repo_slug(request)
452 try:
456 try:
453 user_perms = set([self.user_perms['repositories'][repo_name]])
457 user_perms = set([self.user_perms['repositories'][repo_name]])
454 except KeyError:
458 except KeyError:
455 return False
459 return False
456 if self.required_perms.issubset(user_perms):
460 if self.required_perms.issubset(user_perms):
457 return True
461 return True
458 return False
462 return False
459
463
460
464
461 class HasRepoPermissionAnyDecorator(PermsDecorator):
465 class HasRepoPermissionAnyDecorator(PermsDecorator):
462 """Checks for access permission for any of given predicates for specific
466 """Checks for access permission for any of given predicates for specific
463 repository. In order to fulfill the request any of predicates must be meet
467 repository. In order to fulfill the request any of predicates must be meet
464 """
468 """
465
469
466 def check_permissions(self):
470 def check_permissions(self):
467 repo_name = get_repo_slug(request)
471 repo_name = get_repo_slug(request)
468
472
469 try:
473 try:
470 user_perms = set([self.user_perms['repositories'][repo_name]])
474 user_perms = set([self.user_perms['repositories'][repo_name]])
471 except KeyError:
475 except KeyError:
472 return False
476 return False
473 if self.required_perms.intersection(user_perms):
477 if self.required_perms.intersection(user_perms):
474 return True
478 return True
475 return False
479 return False
476
480
477
481
478 #==============================================================================
482 #==============================================================================
479 # CHECK FUNCTIONS
483 # CHECK FUNCTIONS
480 #==============================================================================
484 #==============================================================================
481 class PermsFunction(object):
485 class PermsFunction(object):
482 """Base function for other check functions"""
486 """Base function for other check functions"""
483
487
484 def __init__(self, *perms):
488 def __init__(self, *perms):
485 available_perms = config['available_permissions']
489 available_perms = config['available_permissions']
486
490
487 for perm in perms:
491 for perm in perms:
488 if perm not in available_perms:
492 if perm not in available_perms:
489 raise Exception("'%s' permission in not defined" % perm)
493 raise Exception("'%s' permission in not defined" % perm)
490 self.required_perms = set(perms)
494 self.required_perms = set(perms)
491 self.user_perms = None
495 self.user_perms = None
492 self.granted_for = ''
496 self.granted_for = ''
493 self.repo_name = None
497 self.repo_name = None
494
498
495 def __call__(self, check_Location=''):
499 def __call__(self, check_Location=''):
496 user = session.get('rhodecode_user', False)
500 user = session.get('rhodecode_user', False)
497 if not user:
501 if not user:
498 return False
502 return False
499 self.user_perms = user.permissions
503 self.user_perms = user.permissions
500 self.granted_for = user
504 self.granted_for = user
501 log.debug('checking %s %s %s', self.__class__.__name__,
505 log.debug('checking %s %s %s', self.__class__.__name__,
502 self.required_perms, user)
506 self.required_perms, user)
503
507
504 if self.check_permissions():
508 if self.check_permissions():
505 log.debug('Permission granted %s @ %s', self.granted_for,
509 log.debug('Permission granted %s @ %s', self.granted_for,
506 check_Location or 'unspecified location')
510 check_Location or 'unspecified location')
507 return True
511 return True
508
512
509 else:
513 else:
510 log.warning('Permission denied for %s @ %s', self.granted_for,
514 log.warning('Permission denied for %s @ %s', self.granted_for,
511 check_Location or 'unspecified location')
515 check_Location or 'unspecified location')
512 return False
516 return False
513
517
514 def check_permissions(self):
518 def check_permissions(self):
515 """Dummy function for overriding"""
519 """Dummy function for overriding"""
516 raise Exception('You have to write this function in child class')
520 raise Exception('You have to write this function in child class')
517
521
518
522
519 class HasPermissionAll(PermsFunction):
523 class HasPermissionAll(PermsFunction):
520 def check_permissions(self):
524 def check_permissions(self):
521 if self.required_perms.issubset(self.user_perms.get('global')):
525 if self.required_perms.issubset(self.user_perms.get('global')):
522 return True
526 return True
523 return False
527 return False
524
528
525
529
526 class HasPermissionAny(PermsFunction):
530 class HasPermissionAny(PermsFunction):
527 def check_permissions(self):
531 def check_permissions(self):
528 if self.required_perms.intersection(self.user_perms.get('global')):
532 if self.required_perms.intersection(self.user_perms.get('global')):
529 return True
533 return True
530 return False
534 return False
531
535
532
536
533 class HasRepoPermissionAll(PermsFunction):
537 class HasRepoPermissionAll(PermsFunction):
534
538
535 def __call__(self, repo_name=None, check_Location=''):
539 def __call__(self, repo_name=None, check_Location=''):
536 self.repo_name = repo_name
540 self.repo_name = repo_name
537 return super(HasRepoPermissionAll, self).__call__(check_Location)
541 return super(HasRepoPermissionAll, self).__call__(check_Location)
538
542
539 def check_permissions(self):
543 def check_permissions(self):
540 if not self.repo_name:
544 if not self.repo_name:
541 self.repo_name = get_repo_slug(request)
545 self.repo_name = get_repo_slug(request)
542
546
543 try:
547 try:
544 self.user_perms = set([self.user_perms['reposit'
548 self.user_perms = set([self.user_perms['reposit'
545 'ories'][self.repo_name]])
549 'ories'][self.repo_name]])
546 except KeyError:
550 except KeyError:
547 return False
551 return False
548 self.granted_for = self.repo_name
552 self.granted_for = self.repo_name
549 if self.required_perms.issubset(self.user_perms):
553 if self.required_perms.issubset(self.user_perms):
550 return True
554 return True
551 return False
555 return False
552
556
553
557
554 class HasRepoPermissionAny(PermsFunction):
558 class HasRepoPermissionAny(PermsFunction):
555
559
556 def __call__(self, repo_name=None, check_Location=''):
560 def __call__(self, repo_name=None, check_Location=''):
557 self.repo_name = repo_name
561 self.repo_name = repo_name
558 return super(HasRepoPermissionAny, self).__call__(check_Location)
562 return super(HasRepoPermissionAny, self).__call__(check_Location)
559
563
560 def check_permissions(self):
564 def check_permissions(self):
561 if not self.repo_name:
565 if not self.repo_name:
562 self.repo_name = get_repo_slug(request)
566 self.repo_name = get_repo_slug(request)
563
567
564 try:
568 try:
565 self.user_perms = set([self.user_perms['reposi'
569 self.user_perms = set([self.user_perms['reposi'
566 'tories'][self.repo_name]])
570 'tories'][self.repo_name]])
567 except KeyError:
571 except KeyError:
568 return False
572 return False
569 self.granted_for = self.repo_name
573 self.granted_for = self.repo_name
570 if self.required_perms.intersection(self.user_perms):
574 if self.required_perms.intersection(self.user_perms):
571 return True
575 return True
572 return False
576 return False
573
577
574
578
575 #==============================================================================
579 #==============================================================================
576 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
580 # SPECIAL VERSION TO HANDLE MIDDLEWARE AUTH
577 #==============================================================================
581 #==============================================================================
578 class HasPermissionAnyMiddleware(object):
582 class HasPermissionAnyMiddleware(object):
579 def __init__(self, *perms):
583 def __init__(self, *perms):
580 self.required_perms = set(perms)
584 self.required_perms = set(perms)
581
585
582 def __call__(self, user, repo_name):
586 def __call__(self, user, repo_name):
583 usr = AuthUser(user.user_id)
587 usr = AuthUser(user.user_id)
584 try:
588 try:
585 self.user_perms = set([usr.permissions['repositories'][repo_name]])
589 self.user_perms = set([usr.permissions['repositories'][repo_name]])
586 except:
590 except:
587 self.user_perms = set()
591 self.user_perms = set()
588 self.granted_for = ''
592 self.granted_for = ''
589 self.username = user.username
593 self.username = user.username
590 self.repo_name = repo_name
594 self.repo_name = repo_name
591 return self.check_permissions()
595 return self.check_permissions()
592
596
593 def check_permissions(self):
597 def check_permissions(self):
594 log.debug('checking mercurial protocol '
598 log.debug('checking mercurial protocol '
595 'permissions %s for user:%s repository:%s', self.user_perms,
599 'permissions %s for user:%s repository:%s', self.user_perms,
596 self.username, self.repo_name)
600 self.username, self.repo_name)
597 if self.required_perms.intersection(self.user_perms):
601 if self.required_perms.intersection(self.user_perms):
598 log.debug('permission granted')
602 log.debug('permission granted')
599 return True
603 return True
600 log.debug('permission denied')
604 log.debug('permission denied')
601 return False
605 return False
@@ -1,2567 +1,2576 b''
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
1 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td {
2 border:0;
2 border:0;
3 outline:0;
3 outline:0;
4 font-size:100%;
4 font-size:100%;
5 vertical-align:baseline;
5 vertical-align:baseline;
6 background:transparent;
6 background:transparent;
7 margin:0;
7 margin:0;
8 padding:0;
8 padding:0;
9 }
9 }
10
10
11 body {
11 body {
12 line-height:1;
12 line-height:1;
13 height:100%;
13 height:100%;
14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
14 background:url("../images/background.png") repeat scroll 0 0 #B0B0B0;
15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
15 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
16 font-size:12px;
16 font-size:12px;
17 color:#000;
17 color:#000;
18 margin:0;
18 margin:0;
19 padding:0;
19 padding:0;
20 }
20 }
21
21
22 ol,ul {
22 ol,ul {
23 list-style:none;
23 list-style:none;
24 }
24 }
25
25
26 blockquote,q {
26 blockquote,q {
27 quotes:none;
27 quotes:none;
28 }
28 }
29
29
30 blockquote:before,blockquote:after,q:before,q:after {
30 blockquote:before,blockquote:after,q:before,q:after {
31 content:none;
31 content:none;
32 }
32 }
33
33
34 :focus {
34 :focus {
35 outline:0;
35 outline:0;
36 }
36 }
37
37
38 del {
38 del {
39 text-decoration:line-through;
39 text-decoration:line-through;
40 }
40 }
41
41
42 table {
42 table {
43 border-collapse:collapse;
43 border-collapse:collapse;
44 border-spacing:0;
44 border-spacing:0;
45 }
45 }
46
46
47 html {
47 html {
48 height:100%;
48 height:100%;
49 }
49 }
50
50
51 a {
51 a {
52 color:#003367;
52 color:#003367;
53 text-decoration:none;
53 text-decoration:none;
54 cursor:pointer;
54 cursor:pointer;
55 font-weight:700;
55 font-weight:700;
56 }
56 }
57
57
58 a:hover {
58 a:hover {
59 color:#316293;
59 color:#316293;
60 text-decoration:underline;
60 text-decoration:underline;
61 }
61 }
62
62
63 h1,h2,h3,h4,h5,h6 {
63 h1,h2,h3,h4,h5,h6 {
64 color:#292929;
64 color:#292929;
65 font-weight:700;
65 font-weight:700;
66 }
66 }
67
67
68 h1 {
68 h1 {
69 font-size:22px;
69 font-size:22px;
70 }
70 }
71
71
72 h2 {
72 h2 {
73 font-size:20px;
73 font-size:20px;
74 }
74 }
75
75
76 h3 {
76 h3 {
77 font-size:18px;
77 font-size:18px;
78 }
78 }
79
79
80 h4 {
80 h4 {
81 font-size:16px;
81 font-size:16px;
82 }
82 }
83
83
84 h5 {
84 h5 {
85 font-size:14px;
85 font-size:14px;
86 }
86 }
87
87
88 h6 {
88 h6 {
89 font-size:11px;
89 font-size:11px;
90 }
90 }
91
91
92 ul.circle {
92 ul.circle {
93 list-style-type:circle;
93 list-style-type:circle;
94 }
94 }
95
95
96 ul.disc {
96 ul.disc {
97 list-style-type:disc;
97 list-style-type:disc;
98 }
98 }
99
99
100 ul.square {
100 ul.square {
101 list-style-type:square;
101 list-style-type:square;
102 }
102 }
103
103
104 ol.lower-roman {
104 ol.lower-roman {
105 list-style-type:lower-roman;
105 list-style-type:lower-roman;
106 }
106 }
107
107
108 ol.upper-roman {
108 ol.upper-roman {
109 list-style-type:upper-roman;
109 list-style-type:upper-roman;
110 }
110 }
111
111
112 ol.lower-alpha {
112 ol.lower-alpha {
113 list-style-type:lower-alpha;
113 list-style-type:lower-alpha;
114 }
114 }
115
115
116 ol.upper-alpha {
116 ol.upper-alpha {
117 list-style-type:upper-alpha;
117 list-style-type:upper-alpha;
118 }
118 }
119
119
120 ol.decimal {
120 ol.decimal {
121 list-style-type:decimal;
121 list-style-type:decimal;
122 }
122 }
123
123
124 div.color {
124 div.color {
125 clear:both;
125 clear:both;
126 overflow:hidden;
126 overflow:hidden;
127 position:absolute;
127 position:absolute;
128 background:#FFF;
128 background:#FFF;
129 margin:7px 0 0 60px;
129 margin:7px 0 0 60px;
130 padding:1px 1px 1px 0;
130 padding:1px 1px 1px 0;
131 }
131 }
132
132
133 div.color a {
133 div.color a {
134 width:15px;
134 width:15px;
135 height:15px;
135 height:15px;
136 display:block;
136 display:block;
137 float:left;
137 float:left;
138 margin:0 0 0 1px;
138 margin:0 0 0 1px;
139 padding:0;
139 padding:0;
140 }
140 }
141
141
142 div.options {
142 div.options {
143 clear:both;
143 clear:both;
144 overflow:hidden;
144 overflow:hidden;
145 position:absolute;
145 position:absolute;
146 background:#FFF;
146 background:#FFF;
147 margin:7px 0 0 162px;
147 margin:7px 0 0 162px;
148 padding:0;
148 padding:0;
149 }
149 }
150
150
151 div.options a {
151 div.options a {
152 height:1%;
152 height:1%;
153 display:block;
153 display:block;
154 text-decoration:none;
154 text-decoration:none;
155 margin:0;
155 margin:0;
156 padding:3px 8px;
156 padding:3px 8px;
157 }
157 }
158
158
159 .top-left-rounded-corner {
159 .top-left-rounded-corner {
160 -webkit-border-top-left-radius: 8px;
160 -webkit-border-top-left-radius: 8px;
161 -khtml-border-radius-topleft: 8px;
161 -khtml-border-radius-topleft: 8px;
162 -moz-border-radius-topleft: 8px;
162 -moz-border-radius-topleft: 8px;
163 border-top-left-radius: 8px;
163 border-top-left-radius: 8px;
164 }
164 }
165
165
166 .top-right-rounded-corner {
166 .top-right-rounded-corner {
167 -webkit-border-top-right-radius: 8px;
167 -webkit-border-top-right-radius: 8px;
168 -khtml-border-radius-topright: 8px;
168 -khtml-border-radius-topright: 8px;
169 -moz-border-radius-topright: 8px;
169 -moz-border-radius-topright: 8px;
170 border-top-right-radius: 8px;
170 border-top-right-radius: 8px;
171 }
171 }
172
172
173 .bottom-left-rounded-corner {
173 .bottom-left-rounded-corner {
174 -webkit-border-bottom-left-radius: 8px;
174 -webkit-border-bottom-left-radius: 8px;
175 -khtml-border-radius-bottomleft: 8px;
175 -khtml-border-radius-bottomleft: 8px;
176 -moz-border-radius-bottomleft: 8px;
176 -moz-border-radius-bottomleft: 8px;
177 border-bottom-left-radius: 8px;
177 border-bottom-left-radius: 8px;
178 }
178 }
179
179
180 .bottom-right-rounded-corner {
180 .bottom-right-rounded-corner {
181 -webkit-border-bottom-right-radius: 8px;
181 -webkit-border-bottom-right-radius: 8px;
182 -khtml-border-radius-bottomright: 8px;
182 -khtml-border-radius-bottomright: 8px;
183 -moz-border-radius-bottomright: 8px;
183 -moz-border-radius-bottomright: 8px;
184 border-bottom-right-radius: 8px;
184 border-bottom-right-radius: 8px;
185 }
185 }
186
186
187
187
188 #header {
188 #header {
189 margin:0;
189 margin:0;
190 padding:0 10px;
190 padding:0 10px;
191 }
191 }
192
192
193
193
194 #header ul#logged-user{
194 #header ul#logged-user{
195 margin-bottom:5px !important;
195 margin-bottom:5px !important;
196 -webkit-border-radius: 0px 0px 8px 8px;
196 -webkit-border-radius: 0px 0px 8px 8px;
197 -khtml-border-radius: 0px 0px 8px 8px;
197 -khtml-border-radius: 0px 0px 8px 8px;
198 -moz-border-radius: 0px 0px 8px 8px;
198 -moz-border-radius: 0px 0px 8px 8px;
199 border-radius: 0px 0px 8px 8px;
199 border-radius: 0px 0px 8px 8px;
200 height:37px;
200 height:37px;
201 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
201 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367
202 }
202 }
203
203
204 #header ul#logged-user li {
204 #header ul#logged-user li {
205 list-style:none;
205 list-style:none;
206 float:left;
206 float:left;
207 margin:8px 0 0;
207 margin:8px 0 0;
208 padding:4px 12px;
208 padding:4px 12px;
209 border-left: 1px solid #316293;
209 border-left: 1px solid #316293;
210 }
210 }
211
211
212 #header ul#logged-user li.first {
212 #header ul#logged-user li.first {
213 border-left:none;
213 border-left:none;
214 margin:4px;
214 margin:4px;
215 }
215 }
216
216
217 #header ul#logged-user li.first div.gravatar {
217 #header ul#logged-user li.first div.gravatar {
218 margin-top:-2px;
218 margin-top:-2px;
219 }
219 }
220
220
221 #header ul#logged-user li.first div.account {
221 #header ul#logged-user li.first div.account {
222 padding-top:4px;
222 padding-top:4px;
223 float:left;
223 float:left;
224 }
224 }
225
225
226 #header ul#logged-user li.last {
226 #header ul#logged-user li.last {
227 border-right:none;
227 border-right:none;
228 }
228 }
229
229
230 #header ul#logged-user li a {
230 #header ul#logged-user li a {
231 color:#fff;
231 color:#fff;
232 font-weight:700;
232 font-weight:700;
233 text-decoration:none;
233 text-decoration:none;
234 }
234 }
235
235
236 #header ul#logged-user li a:hover {
236 #header ul#logged-user li a:hover {
237 text-decoration:underline;
237 text-decoration:underline;
238 }
238 }
239
239
240 #header ul#logged-user li.highlight a {
240 #header ul#logged-user li.highlight a {
241 color:#fff;
241 color:#fff;
242 }
242 }
243
243
244 #header ul#logged-user li.highlight a:hover {
244 #header ul#logged-user li.highlight a:hover {
245 color:#FFF;
245 color:#FFF;
246 }
246 }
247
247
248 #header #header-inner {
248 #header #header-inner {
249 height:40px;
249 height:40px;
250 clear:both;
250 clear:both;
251 position:relative;
251 position:relative;
252 background:#003367 url("../images/header_inner.png") repeat-x;
252 background:#003367 url("../images/header_inner.png") repeat-x;
253 border-bottom:2px solid #fff;
253 border-bottom:2px solid #fff;
254 margin:0;
254 margin:0;
255 padding:0;
255 padding:0;
256 }
256 }
257
257
258 #header #header-inner #home a {
258 #header #header-inner #home a {
259 height:40px;
259 height:40px;
260 width:46px;
260 width:46px;
261 display:block;
261 display:block;
262 background:url("../images/button_home.png");
262 background:url("../images/button_home.png");
263 background-position:0 0;
263 background-position:0 0;
264 margin:0;
264 margin:0;
265 padding:0;
265 padding:0;
266 }
266 }
267
267
268 #header #header-inner #home a:hover {
268 #header #header-inner #home a:hover {
269 background-position:0 -40px;
269 background-position:0 -40px;
270 }
270 }
271
271
272 #header #header-inner #logo h1 {
272 #header #header-inner #logo h1 {
273 color:#FFF;
273 color:#FFF;
274 font-size:18px;
274 font-size:18px;
275 margin:10px 0 0 13px;
275 margin:10px 0 0 13px;
276 padding:0;
276 padding:0;
277 }
277 }
278
278
279 #header #header-inner #logo a {
279 #header #header-inner #logo a {
280 color:#fff;
280 color:#fff;
281 text-decoration:none;
281 text-decoration:none;
282 }
282 }
283
283
284 #header #header-inner #logo a:hover {
284 #header #header-inner #logo a:hover {
285 color:#bfe3ff;
285 color:#bfe3ff;
286 }
286 }
287
287
288 #header #header-inner #quick,#header #header-inner #quick ul {
288 #header #header-inner #quick,#header #header-inner #quick ul {
289 position:relative;
289 position:relative;
290 float:right;
290 float:right;
291 list-style-type:none;
291 list-style-type:none;
292 list-style-position:outside;
292 list-style-position:outside;
293 margin:10px 5px 0 0;
293 margin:10px 5px 0 0;
294 padding:0;
294 padding:0;
295 }
295 }
296
296
297 #header #header-inner #quick li {
297 #header #header-inner #quick li {
298 position:relative;
298 position:relative;
299 float:left;
299 float:left;
300 margin:0 5px 0 0;
300 margin:0 5px 0 0;
301 padding:0;
301 padding:0;
302 }
302 }
303
303
304 #header #header-inner #quick li a {
304 #header #header-inner #quick li a {
305 top:0;
305 top:0;
306 left:0;
306 left:0;
307 height:1%;
307 height:1%;
308 display:block;
308 display:block;
309 clear:both;
309 clear:both;
310 overflow:hidden;
310 overflow:hidden;
311 color:#FFF;
311 color:#FFF;
312 font-weight:700;
312 font-weight:700;
313 text-decoration:none;
313 text-decoration:none;
314 background:#369 url("../images/quick_l.png") no-repeat top left;
314 background:#369 url("../images/quick_l.png") no-repeat top left;
315 padding:0;
315 padding:0;
316 }
316 }
317
317
318 #header #header-inner #quick li span.short {
318 #header #header-inner #quick li span.short {
319 padding:9px 6px 8px 6px;
319 padding:9px 6px 8px 6px;
320 }
320 }
321
321
322 #header #header-inner #quick li span {
322 #header #header-inner #quick li span {
323 top:0;
323 top:0;
324 right:0;
324 right:0;
325 height:1%;
325 height:1%;
326 display:block;
326 display:block;
327 float:left;
327 float:left;
328 background:url("../images/quick_r.png") no-repeat top right;
328 background:url("../images/quick_r.png") no-repeat top right;
329 border-left:1px solid #3f6f9f;
329 border-left:1px solid #3f6f9f;
330 margin:0;
330 margin:0;
331 padding:10px 12px 8px 10px;
331 padding:10px 12px 8px 10px;
332 }
332 }
333
333
334 #header #header-inner #quick li span.normal {
334 #header #header-inner #quick li span.normal {
335 border:none;
335 border:none;
336 padding:10px 12px 8px;
336 padding:10px 12px 8px;
337 }
337 }
338
338
339 #header #header-inner #quick li span.icon {
339 #header #header-inner #quick li span.icon {
340 top:0;
340 top:0;
341 left:0;
341 left:0;
342 border-left:none;
342 border-left:none;
343 background:url("../images/quick_l.png") no-repeat top left;
343 background:url("../images/quick_l.png") no-repeat top left;
344 border-right:1px solid #2e5c89;
344 border-right:1px solid #2e5c89;
345 padding:8px 8px 4px;
345 padding:8px 8px 4px;
346 }
346 }
347
347
348 #header #header-inner #quick li span.icon_short {
348 #header #header-inner #quick li span.icon_short {
349 top:0;
349 top:0;
350 left:0;
350 left:0;
351 border-left:none;
351 border-left:none;
352 background:url("../images/quick_l.png") no-repeat top left;
352 background:url("../images/quick_l.png") no-repeat top left;
353 border-right:1px solid #2e5c89;
353 border-right:1px solid #2e5c89;
354 padding:9px 4px 4px;
354 padding:9px 4px 4px;
355 }
355 }
356
356
357 #header #header-inner #quick li a:hover {
357 #header #header-inner #quick li a:hover {
358 background:#4e4e4e url("../images/quick_l_selected.png") no-repeat top left;
358 background:#4e4e4e url("../images/quick_l_selected.png") no-repeat top left;
359 }
359 }
360
360
361 #header #header-inner #quick li a:hover span {
361 #header #header-inner #quick li a:hover span {
362 border-left:1px solid #545454;
362 border-left:1px solid #545454;
363 background:url("../images/quick_r_selected.png") no-repeat top right;
363 background:url("../images/quick_r_selected.png") no-repeat top right;
364 }
364 }
365
365
366 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
366 #header #header-inner #quick li a:hover span.icon,#header #header-inner #quick li a:hover span.icon_short {
367 border-left:none;
367 border-left:none;
368 border-right:1px solid #464646;
368 border-right:1px solid #464646;
369 background:url("../images/quick_l_selected.png") no-repeat top left;
369 background:url("../images/quick_l_selected.png") no-repeat top left;
370 }
370 }
371
371
372
372
373 #header #header-inner #quick ul {
373 #header #header-inner #quick ul {
374 top:29px;
374 top:29px;
375 right:0;
375 right:0;
376 min-width:200px;
376 min-width:200px;
377 display:none;
377 display:none;
378 position:absolute;
378 position:absolute;
379 background:#FFF;
379 background:#FFF;
380 border:1px solid #666;
380 border:1px solid #666;
381 border-top:1px solid #003367;
381 border-top:1px solid #003367;
382 z-index:100;
382 z-index:100;
383 margin:0;
383 margin:0;
384 padding:0;
384 padding:0;
385 }
385 }
386
386
387 #header #header-inner #quick ul.repo_switcher {
387 #header #header-inner #quick ul.repo_switcher {
388 max-height:275px;
388 max-height:275px;
389 overflow-x:hidden;
389 overflow-x:hidden;
390 overflow-y:auto;
390 overflow-y:auto;
391 }
391 }
392 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
392 #header #header-inner #quick ul.repo_switcher li.qfilter_rs {
393 float:none;
393 float:none;
394 margin:0;
394 margin:0;
395 border-bottom:2px solid #003367;
395 border-bottom:2px solid #003367;
396 }
396 }
397
397
398
398
399 #header #header-inner #quick .repo_switcher_type{
399 #header #header-inner #quick .repo_switcher_type{
400 position:absolute;
400 position:absolute;
401 left:0;
401 left:0;
402 top:9px;
402 top:9px;
403
403
404 }
404 }
405 #header #header-inner #quick li ul li {
405 #header #header-inner #quick li ul li {
406 border-bottom:1px solid #ddd;
406 border-bottom:1px solid #ddd;
407 }
407 }
408
408
409 #header #header-inner #quick li ul li a {
409 #header #header-inner #quick li ul li a {
410 width:182px;
410 width:182px;
411 height:auto;
411 height:auto;
412 display:block;
412 display:block;
413 float:left;
413 float:left;
414 background:#FFF;
414 background:#FFF;
415 color:#003367;
415 color:#003367;
416 font-weight:400;
416 font-weight:400;
417 margin:0;
417 margin:0;
418 padding:7px 9px;
418 padding:7px 9px;
419 }
419 }
420
420
421 #header #header-inner #quick li ul li a:hover {
421 #header #header-inner #quick li ul li a:hover {
422 color:#000;
422 color:#000;
423 background:#FFF;
423 background:#FFF;
424 }
424 }
425
425
426 #header #header-inner #quick ul ul {
426 #header #header-inner #quick ul ul {
427 top:auto;
427 top:auto;
428 }
428 }
429
429
430 #header #header-inner #quick li ul ul {
430 #header #header-inner #quick li ul ul {
431 right:200px;
431 right:200px;
432 max-height:275px;
432 max-height:275px;
433 overflow:auto;
433 overflow:auto;
434 overflow-x:hidden;
434 overflow-x:hidden;
435 white-space:normal;
435 white-space:normal;
436 }
436 }
437
437
438 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
438 #header #header-inner #quick li ul li a.journal,#header #header-inner #quick li ul li a.journal:hover {
439 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
439 background:url("../images/icons/book.png") no-repeat scroll 4px 9px #FFF;
440 width:167px;
440 width:167px;
441 margin:0;
441 margin:0;
442 padding:12px 9px 7px 24px;
442 padding:12px 9px 7px 24px;
443 }
443 }
444
444
445 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
445 #header #header-inner #quick li ul li a.private_repo,#header #header-inner #quick li ul li a.private_repo:hover {
446 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
446 background:url("../images/icons/lock.png") no-repeat scroll 4px 9px #FFF;
447 min-width:167px;
447 min-width:167px;
448 margin:0;
448 margin:0;
449 padding:12px 9px 7px 24px;
449 padding:12px 9px 7px 24px;
450 }
450 }
451
451
452 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
452 #header #header-inner #quick li ul li a.public_repo,#header #header-inner #quick li ul li a.public_repo:hover {
453 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
453 background:url("../images/icons/lock_open.png") no-repeat scroll 4px 9px #FFF;
454 min-width:167px;
454 min-width:167px;
455 margin:0;
455 margin:0;
456 padding:12px 9px 7px 24px;
456 padding:12px 9px 7px 24px;
457 }
457 }
458
458
459 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
459 #header #header-inner #quick li ul li a.hg,#header #header-inner #quick li ul li a.hg:hover {
460 background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
460 background:url("../images/icons/hgicon.png") no-repeat scroll 4px 9px #FFF;
461 min-width:167px;
461 min-width:167px;
462 margin:0 0 0 14px;
462 margin:0 0 0 14px;
463 padding:12px 9px 7px 24px;
463 padding:12px 9px 7px 24px;
464 }
464 }
465
465
466 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
466 #header #header-inner #quick li ul li a.git,#header #header-inner #quick li ul li a.git:hover {
467 background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
467 background:url("../images/icons/giticon.png") no-repeat scroll 4px 9px #FFF;
468 min-width:167px;
468 min-width:167px;
469 margin:0 0 0 14px;
469 margin:0 0 0 14px;
470 padding:12px 9px 7px 24px;
470 padding:12px 9px 7px 24px;
471 }
471 }
472
472
473 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
473 #header #header-inner #quick li ul li a.repos,#header #header-inner #quick li ul li a.repos:hover {
474 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
474 background:url("../images/icons/database_edit.png") no-repeat scroll 4px 9px #FFF;
475 width:167px;
475 width:167px;
476 margin:0;
476 margin:0;
477 padding:12px 9px 7px 24px;
477 padding:12px 9px 7px 24px;
478 }
478 }
479
479
480 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
480 #header #header-inner #quick li ul li a.users,#header #header-inner #quick li ul li a.users:hover {
481 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
481 background:#FFF url("../images/icons/user_edit.png") no-repeat 4px 9px;
482 width:167px;
482 width:167px;
483 margin:0;
483 margin:0;
484 padding:12px 9px 7px 24px;
484 padding:12px 9px 7px 24px;
485 }
485 }
486
486
487 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover {
487 #header #header-inner #quick li ul li a.groups,#header #header-inner #quick li ul li a.groups:hover {
488 background:#FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
488 background:#FFF url("../images/icons/group_edit.png") no-repeat 4px 9px;
489 width:167px;
489 width:167px;
490 margin:0;
490 margin:0;
491 padding:12px 9px 7px 24px;
491 padding:12px 9px 7px 24px;
492 }
492 }
493
493
494 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
494 #header #header-inner #quick li ul li a.settings,#header #header-inner #quick li ul li a.settings:hover {
495 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
495 background:#FFF url("../images/icons/cog.png") no-repeat 4px 9px;
496 width:167px;
496 width:167px;
497 margin:0;
497 margin:0;
498 padding:12px 9px 7px 24px;
498 padding:12px 9px 7px 24px;
499 }
499 }
500
500
501 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
501 #header #header-inner #quick li ul li a.permissions,#header #header-inner #quick li ul li a.permissions:hover {
502 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
502 background:#FFF url("../images/icons/key.png") no-repeat 4px 9px;
503 width:167px;
503 width:167px;
504 margin:0;
504 margin:0;
505 padding:12px 9px 7px 24px;
505 padding:12px 9px 7px 24px;
506 }
506 }
507
507
508 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
508 #header #header-inner #quick li ul li a.ldap,#header #header-inner #quick li ul li a.ldap:hover {
509 background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
509 background:#FFF url("../images/icons/server_key.png") no-repeat 4px 9px;
510 width:167px;
510 width:167px;
511 margin:0;
511 margin:0;
512 padding:12px 9px 7px 24px;
512 padding:12px 9px 7px 24px;
513 }
513 }
514
514
515 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
515 #header #header-inner #quick li ul li a.fork,#header #header-inner #quick li ul li a.fork:hover {
516 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
516 background:#FFF url("../images/icons/arrow_divide.png") no-repeat 4px 9px;
517 width:167px;
517 width:167px;
518 margin:0;
518 margin:0;
519 padding:12px 9px 7px 24px;
519 padding:12px 9px 7px 24px;
520 }
520 }
521
521
522 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
522 #header #header-inner #quick li ul li a.search,#header #header-inner #quick li ul li a.search:hover {
523 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
523 background:#FFF url("../images/icons/search_16.png") no-repeat 4px 9px;
524 width:167px;
524 width:167px;
525 margin:0;
525 margin:0;
526 padding:12px 9px 7px 24px;
526 padding:12px 9px 7px 24px;
527 }
527 }
528
528
529 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
529 #header #header-inner #quick li ul li a.delete,#header #header-inner #quick li ul li a.delete:hover {
530 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
530 background:#FFF url("../images/icons/delete.png") no-repeat 4px 9px;
531 width:167px;
531 width:167px;
532 margin:0;
532 margin:0;
533 padding:12px 9px 7px 24px;
533 padding:12px 9px 7px 24px;
534 }
534 }
535
535
536 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
536 #header #header-inner #quick li ul li a.branches,#header #header-inner #quick li ul li a.branches:hover {
537 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
537 background:#FFF url("../images/icons/arrow_branch.png") no-repeat 4px 9px;
538 width:167px;
538 width:167px;
539 margin:0;
539 margin:0;
540 padding:12px 9px 7px 24px;
540 padding:12px 9px 7px 24px;
541 }
541 }
542
542
543 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
543 #header #header-inner #quick li ul li a.tags,#header #header-inner #quick li ul li a.tags:hover {
544 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
544 background:#FFF url("../images/icons/tag_blue.png") no-repeat 4px 9px;
545 width:167px;
545 width:167px;
546 margin:0;
546 margin:0;
547 padding:12px 9px 7px 24px;
547 padding:12px 9px 7px 24px;
548 }
548 }
549
549
550 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
550 #header #header-inner #quick li ul li a.admin,#header #header-inner #quick li ul li a.admin:hover {
551 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
551 background:#FFF url("../images/icons/cog_edit.png") no-repeat 4px 9px;
552 width:167px;
552 width:167px;
553 margin:0;
553 margin:0;
554 padding:12px 9px 7px 24px;
554 padding:12px 9px 7px 24px;
555 }
555 }
556
556
557 #content #left {
557 #content #left {
558 left:0;
558 left:0;
559 width:280px;
559 width:280px;
560 position:absolute;
560 position:absolute;
561 }
561 }
562
562
563 #content #right {
563 #content #right {
564 margin:0 60px 10px 290px;
564 margin:0 60px 10px 290px;
565 }
565 }
566
566
567 #content div.box {
567 #content div.box {
568 clear:both;
568 clear:both;
569 overflow:hidden;
569 overflow:hidden;
570 background:#fff;
570 background:#fff;
571 margin:0 0 10px;
571 margin:0 0 10px;
572 padding:0 0 10px;
572 padding:0 0 10px;
573 }
573 }
574
574
575 #content div.box-left {
575 #content div.box-left {
576 width:49%;
576 width:49%;
577 clear:none;
577 clear:none;
578 float:left;
578 float:left;
579 margin:0 0 10px;
579 margin:0 0 10px;
580 }
580 }
581
581
582 #content div.box-right {
582 #content div.box-right {
583 width:49%;
583 width:49%;
584 clear:none;
584 clear:none;
585 float:right;
585 float:right;
586 margin:0 0 10px;
586 margin:0 0 10px;
587 }
587 }
588
588
589 #content div.box div.title {
589 #content div.box div.title {
590 clear:both;
590 clear:both;
591 overflow:hidden;
591 overflow:hidden;
592 background:#369 url("../images/header_inner.png") repeat-x;
592 background:#369 url("../images/header_inner.png") repeat-x;
593 margin:0 0 20px;
593 margin:0 0 20px;
594 padding:0;
594 padding:0;
595 }
595 }
596
596
597 #content div.box div.title h5 {
597 #content div.box div.title h5 {
598 float:left;
598 float:left;
599 border:none;
599 border:none;
600 color:#fff;
600 color:#fff;
601 text-transform:uppercase;
601 text-transform:uppercase;
602 margin:0;
602 margin:0;
603 padding:11px 0 11px 10px;
603 padding:11px 0 11px 10px;
604 }
604 }
605
605
606 #content div.box div.title ul.links li {
606 #content div.box div.title ul.links li {
607 list-style:none;
607 list-style:none;
608 float:left;
608 float:left;
609 margin:0;
609 margin:0;
610 padding:0;
610 padding:0;
611 }
611 }
612
612
613 #content div.box div.title ul.links li a {
613 #content div.box div.title ul.links li a {
614 border-left: 1px solid #316293;
614 border-left: 1px solid #316293;
615 color: #FFFFFF;
615 color: #FFFFFF;
616 display: block;
616 display: block;
617 float: left;
617 float: left;
618 font-size: 13px;
618 font-size: 13px;
619 font-weight: 700;
619 font-weight: 700;
620 height: 1%;
620 height: 1%;
621 margin: 0;
621 margin: 0;
622 padding: 11px 22px 12px;
622 padding: 11px 22px 12px;
623 text-decoration: none;
623 text-decoration: none;
624 }
624 }
625
625
626 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
626 #content div.box h1,#content div.box h2,#content div.box h3,#content div.box h4,#content div.box h5,#content div.box h6 {
627 clear:both;
627 clear:both;
628 overflow:hidden;
628 overflow:hidden;
629 border-bottom:1px solid #DDD;
629 border-bottom:1px solid #DDD;
630 margin:10px 20px;
630 margin:10px 20px;
631 padding:0 0 15px;
631 padding:0 0 15px;
632 }
632 }
633
633
634 #content div.box p {
634 #content div.box p {
635 color:#5f5f5f;
635 color:#5f5f5f;
636 font-size:12px;
636 font-size:12px;
637 line-height:150%;
637 line-height:150%;
638 margin:0 24px 10px;
638 margin:0 24px 10px;
639 padding:0;
639 padding:0;
640 }
640 }
641
641
642 #content div.box blockquote {
642 #content div.box blockquote {
643 border-left:4px solid #DDD;
643 border-left:4px solid #DDD;
644 color:#5f5f5f;
644 color:#5f5f5f;
645 font-size:11px;
645 font-size:11px;
646 line-height:150%;
646 line-height:150%;
647 margin:0 34px;
647 margin:0 34px;
648 padding:0 0 0 14px;
648 padding:0 0 0 14px;
649 }
649 }
650
650
651 #content div.box blockquote p {
651 #content div.box blockquote p {
652 margin:10px 0;
652 margin:10px 0;
653 padding:0;
653 padding:0;
654 }
654 }
655
655
656 #content div.box dl {
656 #content div.box dl {
657 margin:10px 24px;
657 margin:10px 24px;
658 }
658 }
659
659
660 #content div.box dt {
660 #content div.box dt {
661 font-size:12px;
661 font-size:12px;
662 margin:0;
662 margin:0;
663 }
663 }
664
664
665 #content div.box dd {
665 #content div.box dd {
666 font-size:12px;
666 font-size:12px;
667 margin:0;
667 margin:0;
668 padding:8px 0 8px 15px;
668 padding:8px 0 8px 15px;
669 }
669 }
670
670
671 #content div.box li {
671 #content div.box li {
672 font-size:12px;
672 font-size:12px;
673 padding:4px 0;
673 padding:4px 0;
674 }
674 }
675
675
676 #content div.box ul.disc,#content div.box ul.circle {
676 #content div.box ul.disc,#content div.box ul.circle {
677 margin:10px 24px 10px 38px;
677 margin:10px 24px 10px 38px;
678 }
678 }
679
679
680 #content div.box ul.square {
680 #content div.box ul.square {
681 margin:10px 24px 10px 40px;
681 margin:10px 24px 10px 40px;
682 }
682 }
683
683
684 #content div.box img.left {
684 #content div.box img.left {
685 border:none;
685 border:none;
686 float:left;
686 float:left;
687 margin:10px 10px 10px 0;
687 margin:10px 10px 10px 0;
688 }
688 }
689
689
690 #content div.box img.right {
690 #content div.box img.right {
691 border:none;
691 border:none;
692 float:right;
692 float:right;
693 margin:10px 0 10px 10px;
693 margin:10px 0 10px 10px;
694 }
694 }
695
695
696 #content div.box div.messages {
696 #content div.box div.messages {
697 clear:both;
697 clear:both;
698 overflow:hidden;
698 overflow:hidden;
699 margin:0 20px;
699 margin:0 20px;
700 padding:0;
700 padding:0;
701 }
701 }
702
702
703 #content div.box div.message {
703 #content div.box div.message {
704 clear:both;
704 clear:both;
705 overflow:hidden;
705 overflow:hidden;
706 margin:0;
706 margin:0;
707 padding:10px 0;
707 padding:10px 0;
708 }
708 }
709
709
710 #content div.box div.message a {
710 #content div.box div.message a {
711 font-weight:400 !important;
711 font-weight:400 !important;
712 }
712 }
713
713
714 #content div.box div.message div.image {
714 #content div.box div.message div.image {
715 float:left;
715 float:left;
716 margin:9px 0 0 5px;
716 margin:9px 0 0 5px;
717 padding:6px;
717 padding:6px;
718 }
718 }
719
719
720 #content div.box div.message div.image img {
720 #content div.box div.message div.image img {
721 vertical-align:middle;
721 vertical-align:middle;
722 margin:0;
722 margin:0;
723 }
723 }
724
724
725 #content div.box div.message div.text {
725 #content div.box div.message div.text {
726 float:left;
726 float:left;
727 margin:0;
727 margin:0;
728 padding:9px 6px;
728 padding:9px 6px;
729 }
729 }
730
730
731 #content div.box div.message div.dismiss a {
731 #content div.box div.message div.dismiss a {
732 height:16px;
732 height:16px;
733 width:16px;
733 width:16px;
734 display:block;
734 display:block;
735 background:url("../images/icons/cross.png") no-repeat;
735 background:url("../images/icons/cross.png") no-repeat;
736 margin:15px 14px 0 0;
736 margin:15px 14px 0 0;
737 padding:0;
737 padding:0;
738 }
738 }
739
739
740 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6 {
740 #content div.box div.message div.text h1,#content div.box div.message div.text h2,#content div.box div.message div.text h3,#content div.box div.message div.text h4,#content div.box div.message div.text h5,#content div.box div.message div.text h6 {
741 border:none;
741 border:none;
742 margin:0;
742 margin:0;
743 padding:0;
743 padding:0;
744 }
744 }
745
745
746 #content div.box div.message div.text span {
746 #content div.box div.message div.text span {
747 height:1%;
747 height:1%;
748 display:block;
748 display:block;
749 margin:0;
749 margin:0;
750 padding:5px 0 0;
750 padding:5px 0 0;
751 }
751 }
752
752
753 #content div.box div.message-error {
753 #content div.box div.message-error {
754 height:1%;
754 height:1%;
755 clear:both;
755 clear:both;
756 overflow:hidden;
756 overflow:hidden;
757 background:#FBE3E4;
757 background:#FBE3E4;
758 border:1px solid #FBC2C4;
758 border:1px solid #FBC2C4;
759 color:#860006;
759 color:#860006;
760 }
760 }
761
761
762 #content div.box div.message-error h6 {
762 #content div.box div.message-error h6 {
763 color:#860006;
763 color:#860006;
764 }
764 }
765
765
766 #content div.box div.message-warning {
766 #content div.box div.message-warning {
767 height:1%;
767 height:1%;
768 clear:both;
768 clear:both;
769 overflow:hidden;
769 overflow:hidden;
770 background:#FFF6BF;
770 background:#FFF6BF;
771 border:1px solid #FFD324;
771 border:1px solid #FFD324;
772 color:#5f5200;
772 color:#5f5200;
773 }
773 }
774
774
775 #content div.box div.message-warning h6 {
775 #content div.box div.message-warning h6 {
776 color:#5f5200;
776 color:#5f5200;
777 }
777 }
778
778
779 #content div.box div.message-notice {
779 #content div.box div.message-notice {
780 height:1%;
780 height:1%;
781 clear:both;
781 clear:both;
782 overflow:hidden;
782 overflow:hidden;
783 background:#8FBDE0;
783 background:#8FBDE0;
784 border:1px solid #6BACDE;
784 border:1px solid #6BACDE;
785 color:#003863;
785 color:#003863;
786 }
786 }
787
787
788 #content div.box div.message-notice h6 {
788 #content div.box div.message-notice h6 {
789 color:#003863;
789 color:#003863;
790 }
790 }
791
791
792 #content div.box div.message-success {
792 #content div.box div.message-success {
793 height:1%;
793 height:1%;
794 clear:both;
794 clear:both;
795 overflow:hidden;
795 overflow:hidden;
796 background:#E6EFC2;
796 background:#E6EFC2;
797 border:1px solid #C6D880;
797 border:1px solid #C6D880;
798 color:#4e6100;
798 color:#4e6100;
799 }
799 }
800
800
801 #content div.box div.message-success h6 {
801 #content div.box div.message-success h6 {
802 color:#4e6100;
802 color:#4e6100;
803 }
803 }
804
804
805 #content div.box div.form div.fields div.field {
805 #content div.box div.form div.fields div.field {
806 height:1%;
806 height:1%;
807 border-bottom:1px solid #DDD;
807 border-bottom:1px solid #DDD;
808 clear:both;
808 clear:both;
809 margin:0;
809 margin:0;
810 padding:10px 0;
810 padding:10px 0;
811 }
811 }
812
812
813 #content div.box div.form div.fields div.field-first {
813 #content div.box div.form div.fields div.field-first {
814 padding:0 0 10px;
814 padding:0 0 10px;
815 }
815 }
816
816
817 #content div.box div.form div.fields div.field-noborder {
817 #content div.box div.form div.fields div.field-noborder {
818 border-bottom:0 !important;
818 border-bottom:0 !important;
819 }
819 }
820
820
821 #content div.box div.form div.fields div.field span.error-message {
821 #content div.box div.form div.fields div.field span.error-message {
822 height:1%;
822 height:1%;
823 display:inline-block;
823 display:inline-block;
824 color:red;
824 color:red;
825 margin:8px 0 0 4px;
825 margin:8px 0 0 4px;
826 padding:0;
826 padding:0;
827 }
827 }
828
828
829 #content div.box div.form div.fields div.field span.success {
829 #content div.box div.form div.fields div.field span.success {
830 height:1%;
830 height:1%;
831 display:block;
831 display:block;
832 color:#316309;
832 color:#316309;
833 margin:8px 0 0;
833 margin:8px 0 0;
834 padding:0;
834 padding:0;
835 }
835 }
836
836
837 #content div.box div.form div.fields div.field div.label {
837 #content div.box div.form div.fields div.field div.label {
838 left:70px;
838 left:70px;
839 width:auto;
839 width:auto;
840 position:absolute;
840 position:absolute;
841 margin:0;
841 margin:0;
842 padding:8px 0 0 5px;
842 padding:8px 0 0 5px;
843 }
843 }
844
844
845 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
845 #content div.box-left div.form div.fields div.field div.label,#content div.box-right div.form div.fields div.field div.label {
846 clear:both;
846 clear:both;
847 overflow:hidden;
847 overflow:hidden;
848 left:0;
848 left:0;
849 width:auto;
849 width:auto;
850 position:relative;
850 position:relative;
851 margin:0;
851 margin:0;
852 padding:0 0 8px;
852 padding:0 0 8px;
853 }
853 }
854
854
855 #content div.box div.form div.fields div.field div.label-select {
855 #content div.box div.form div.fields div.field div.label-select {
856 padding:5px 0 0 5px;
856 padding:5px 0 0 5px;
857 }
857 }
858
858
859 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
859 #content div.box-left div.form div.fields div.field div.label-select,#content div.box-right div.form div.fields div.field div.label-select {
860 padding:0 0 8px;
860 padding:0 0 8px;
861 }
861 }
862
862
863 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
863 #content div.box-left div.form div.fields div.field div.label-textarea,#content div.box-right div.form div.fields div.field div.label-textarea {
864 padding:0 0 8px !important;
864 padding:0 0 8px !important;
865 }
865 }
866
866
867 #content div.box div.form div.fields div.field div.label label, div.label label{
867 #content div.box div.form div.fields div.field div.label label, div.label label{
868 color:#393939;
868 color:#393939;
869 font-weight:700;
869 font-weight:700;
870 }
870 }
871
871
872 #content div.box div.form div.fields div.field div.input {
872 #content div.box div.form div.fields div.field div.input {
873 margin:0 0 0 200px;
873 margin:0 0 0 200px;
874 }
874 }
875 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
875 #content div.box-left div.form div.fields div.field div.input,#content div.box-right div.form div.fields div.field div.input {
876 margin:0 0 0 0px;
876 margin:0 0 0 0px;
877 }
877 }
878
878
879 #content div.box div.form div.fields div.field div.input input {
879 #content div.box div.form div.fields div.field div.input input {
880 background:#FFF;
880 background:#FFF;
881 border-top:1px solid #b3b3b3;
881 border-top:1px solid #b3b3b3;
882 border-left:1px solid #b3b3b3;
882 border-left:1px solid #b3b3b3;
883 border-right:1px solid #eaeaea;
883 border-right:1px solid #eaeaea;
884 border-bottom:1px solid #eaeaea;
884 border-bottom:1px solid #eaeaea;
885 color:#000;
885 color:#000;
886 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
886 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
887 font-size:11px;
887 font-size:11px;
888 margin:0;
888 margin:0;
889 padding:7px 7px 6px;
889 padding:7px 7px 6px;
890 }
890 }
891
891
892
892
893
893
894 #content div.box div.form div.fields div.field div.input input.small {
894 #content div.box div.form div.fields div.field div.input input.small {
895 width:30%;
895 width:30%;
896 }
896 }
897
897
898 #content div.box div.form div.fields div.field div.input input.medium {
898 #content div.box div.form div.fields div.field div.input input.medium {
899 width:55%;
899 width:55%;
900 }
900 }
901
901
902 #content div.box div.form div.fields div.field div.input input.large {
902 #content div.box div.form div.fields div.field div.input input.large {
903 width:85%;
903 width:85%;
904 }
904 }
905
905
906 #content div.box div.form div.fields div.field div.input input.date {
906 #content div.box div.form div.fields div.field div.input input.date {
907 width:177px;
907 width:177px;
908 }
908 }
909
909
910 #content div.box div.form div.fields div.field div.input input.button {
910 #content div.box div.form div.fields div.field div.input input.button {
911 background:#D4D0C8;
911 background:#D4D0C8;
912 border-top:1px solid #FFF;
912 border-top:1px solid #FFF;
913 border-left:1px solid #FFF;
913 border-left:1px solid #FFF;
914 border-right:1px solid #404040;
914 border-right:1px solid #404040;
915 border-bottom:1px solid #404040;
915 border-bottom:1px solid #404040;
916 color:#000;
916 color:#000;
917 margin:0;
917 margin:0;
918 padding:4px 8px;
918 padding:4px 8px;
919 }
919 }
920
920
921 #content div.box div.form div.fields div.field div.textarea {
921 #content div.box div.form div.fields div.field div.textarea {
922 border-top:1px solid #b3b3b3;
922 border-top:1px solid #b3b3b3;
923 border-left:1px solid #b3b3b3;
923 border-left:1px solid #b3b3b3;
924 border-right:1px solid #eaeaea;
924 border-right:1px solid #eaeaea;
925 border-bottom:1px solid #eaeaea;
925 border-bottom:1px solid #eaeaea;
926 margin:0 0 0 200px;
926 margin:0 0 0 200px;
927 padding:10px;
927 padding:10px;
928 }
928 }
929
929
930 #content div.box div.form div.fields div.field div.textarea-editor {
930 #content div.box div.form div.fields div.field div.textarea-editor {
931 border:1px solid #ddd;
931 border:1px solid #ddd;
932 padding:0;
932 padding:0;
933 }
933 }
934
934
935 #content div.box div.form div.fields div.field div.textarea textarea {
935 #content div.box div.form div.fields div.field div.textarea textarea {
936 width:100%;
936 width:100%;
937 height:220px;
937 height:220px;
938 overflow:hidden;
938 overflow:hidden;
939 background:#FFF;
939 background:#FFF;
940 color:#000;
940 color:#000;
941 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
941 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
942 font-size:11px;
942 font-size:11px;
943 outline:none;
943 outline:none;
944 border-width:0;
944 border-width:0;
945 margin:0;
945 margin:0;
946 padding:0;
946 padding:0;
947 }
947 }
948
948
949 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea {
949 #content div.box-left div.form div.fields div.field div.textarea textarea,#content div.box-right div.form div.fields div.field div.textarea textarea {
950 width:100%;
950 width:100%;
951 height:100px;
951 height:100px;
952 }
952 }
953
953
954 #content div.box div.form div.fields div.field div.textarea table {
954 #content div.box div.form div.fields div.field div.textarea table {
955 width:100%;
955 width:100%;
956 border:none;
956 border:none;
957 margin:0;
957 margin:0;
958 padding:0;
958 padding:0;
959 }
959 }
960
960
961 #content div.box div.form div.fields div.field div.textarea table td {
961 #content div.box div.form div.fields div.field div.textarea table td {
962 background:#DDD;
962 background:#DDD;
963 border:none;
963 border:none;
964 padding:0;
964 padding:0;
965 }
965 }
966
966
967 #content div.box div.form div.fields div.field div.textarea table td table {
967 #content div.box div.form div.fields div.field div.textarea table td table {
968 width:auto;
968 width:auto;
969 border:none;
969 border:none;
970 margin:0;
970 margin:0;
971 padding:0;
971 padding:0;
972 }
972 }
973
973
974 #content div.box div.form div.fields div.field div.textarea table td table td {
974 #content div.box div.form div.fields div.field div.textarea table td table td {
975 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
975 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
976 font-size:11px;
976 font-size:11px;
977 padding:5px 5px 5px 0;
977 padding:5px 5px 5px 0;
978 }
978 }
979
979
980 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
980 #content div.box div.form div.fields div.field input[type=text]:focus,#content div.box div.form div.fields div.field input[type=password]:focus,#content div.box div.form div.fields div.field input[type=file]:focus,#content div.box div.form div.fields div.field textarea:focus,#content div.box div.form div.fields div.field select:focus {
981 background:#f6f6f6;
981 background:#f6f6f6;
982 border-color:#666;
982 border-color:#666;
983 }
983 }
984
984
985 div.form div.fields div.field div.button {
985 div.form div.fields div.field div.button {
986 margin:0;
986 margin:0;
987 padding:0 0 0 8px;
987 padding:0 0 0 8px;
988 }
988 }
989
989
990 div.form div.fields div.field div.highlight .ui-button {
990 div.form div.fields div.field div.highlight .ui-button {
991 background:#4e85bb url("../images/button_highlight.png") repeat-x;
991 background:#4e85bb url("../images/button_highlight.png") repeat-x;
992 border-top:1px solid #5c91a4;
992 border-top:1px solid #5c91a4;
993 border-left:1px solid #2a6f89;
993 border-left:1px solid #2a6f89;
994 border-right:1px solid #2b7089;
994 border-right:1px solid #2b7089;
995 border-bottom:1px solid #1a6480;
995 border-bottom:1px solid #1a6480;
996 color:#FFF;
996 color:#FFF;
997 margin:0;
997 margin:0;
998 padding:6px 12px;
998 padding:6px 12px;
999 }
999 }
1000
1000
1001 div.form div.fields div.field div.highlight .ui-state-hover {
1001 div.form div.fields div.field div.highlight .ui-state-hover {
1002 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1002 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1003 border-top:1px solid #78acbf;
1003 border-top:1px solid #78acbf;
1004 border-left:1px solid #34819e;
1004 border-left:1px solid #34819e;
1005 border-right:1px solid #35829f;
1005 border-right:1px solid #35829f;
1006 border-bottom:1px solid #257897;
1006 border-bottom:1px solid #257897;
1007 color:#FFF;
1007 color:#FFF;
1008 margin:0;
1008 margin:0;
1009 padding:6px 12px;
1009 padding:6px 12px;
1010 }
1010 }
1011
1011
1012 #content div.box div.form div.fields div.buttons div.highlight input.ui-button {
1012 #content div.box div.form div.fields div.buttons div.highlight input.ui-button {
1013 background:#4e85bb url("../images/button_highlight.png") repeat-x;
1013 background:#4e85bb url("../images/button_highlight.png") repeat-x;
1014 border-top:1px solid #5c91a4;
1014 border-top:1px solid #5c91a4;
1015 border-left:1px solid #2a6f89;
1015 border-left:1px solid #2a6f89;
1016 border-right:1px solid #2b7089;
1016 border-right:1px solid #2b7089;
1017 border-bottom:1px solid #1a6480;
1017 border-bottom:1px solid #1a6480;
1018 color:#fff;
1018 color:#fff;
1019 margin:0;
1019 margin:0;
1020 padding:6px 12px;
1020 padding:6px 12px;
1021 }
1021 }
1022
1022
1023 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
1023 #content div.box div.form div.fields div.buttons div.highlight input.ui-state-hover {
1024 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1024 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
1025 border-top:1px solid #78acbf;
1025 border-top:1px solid #78acbf;
1026 border-left:1px solid #34819e;
1026 border-left:1px solid #34819e;
1027 border-right:1px solid #35829f;
1027 border-right:1px solid #35829f;
1028 border-bottom:1px solid #257897;
1028 border-bottom:1px solid #257897;
1029 color:#fff;
1029 color:#fff;
1030 margin:0;
1030 margin:0;
1031 padding:6px 12px;
1031 padding:6px 12px;
1032 }
1032 }
1033
1033
1034 #content div.box table {
1034 #content div.box table {
1035 width:100%;
1035 width:100%;
1036 border-collapse:collapse;
1036 border-collapse:collapse;
1037 margin:0;
1037 margin:0;
1038 padding:0;
1038 padding:0;
1039 }
1039 }
1040
1040
1041 #content div.box table th {
1041 #content div.box table th {
1042 background:#eee;
1042 background:#eee;
1043 border-bottom:1px solid #ddd;
1043 border-bottom:1px solid #ddd;
1044 padding:5px 0px 5px 5px;
1044 padding:5px 0px 5px 5px;
1045 }
1045 }
1046
1046
1047 #content div.box table th.left {
1047 #content div.box table th.left {
1048 text-align:left;
1048 text-align:left;
1049 }
1049 }
1050
1050
1051 #content div.box table th.right {
1051 #content div.box table th.right {
1052 text-align:right;
1052 text-align:right;
1053 }
1053 }
1054
1054
1055 #content div.box table th.center {
1055 #content div.box table th.center {
1056 text-align:center;
1056 text-align:center;
1057 }
1057 }
1058
1058
1059 #content div.box table th.selected {
1059 #content div.box table th.selected {
1060 vertical-align:middle;
1060 vertical-align:middle;
1061 padding:0;
1061 padding:0;
1062 }
1062 }
1063
1063
1064 #content div.box table td {
1064 #content div.box table td {
1065 background:#fff;
1065 background:#fff;
1066 border-bottom:1px solid #cdcdcd;
1066 border-bottom:1px solid #cdcdcd;
1067 vertical-align:middle;
1067 vertical-align:middle;
1068 padding:5px;
1068 padding:5px;
1069 }
1069 }
1070
1070
1071 #content div.box table tr.selected td {
1071 #content div.box table tr.selected td {
1072 background:#FFC;
1072 background:#FFC;
1073 }
1073 }
1074
1074
1075 #content div.box table td.selected {
1075 #content div.box table td.selected {
1076 width:3%;
1076 width:3%;
1077 text-align:center;
1077 text-align:center;
1078 vertical-align:middle;
1078 vertical-align:middle;
1079 padding:0;
1079 padding:0;
1080 }
1080 }
1081
1081
1082 #content div.box table td.action {
1082 #content div.box table td.action {
1083 width:45%;
1083 width:45%;
1084 text-align:left;
1084 text-align:left;
1085 }
1085 }
1086
1086
1087 #content div.box table td.date {
1087 #content div.box table td.date {
1088 width:33%;
1088 width:33%;
1089 text-align:center;
1089 text-align:center;
1090 }
1090 }
1091
1091
1092 #content div.box div.action {
1092 #content div.box div.action {
1093 float:right;
1093 float:right;
1094 background:#FFF;
1094 background:#FFF;
1095 text-align:right;
1095 text-align:right;
1096 margin:10px 0 0;
1096 margin:10px 0 0;
1097 padding:0;
1097 padding:0;
1098 }
1098 }
1099
1099
1100 #content div.box div.action select {
1100 #content div.box div.action select {
1101 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1101 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1102 font-size:11px;
1102 font-size:11px;
1103 margin:0;
1103 margin:0;
1104 }
1104 }
1105
1105
1106 #content div.box div.action .ui-selectmenu {
1106 #content div.box div.action .ui-selectmenu {
1107 margin:0;
1107 margin:0;
1108 padding:0;
1108 padding:0;
1109 }
1109 }
1110
1110
1111 #content div.box div.pagination {
1111 #content div.box div.pagination {
1112 height:1%;
1112 height:1%;
1113 clear:both;
1113 clear:both;
1114 overflow:hidden;
1114 overflow:hidden;
1115 margin:10px 0 0;
1115 margin:10px 0 0;
1116 padding:0;
1116 padding:0;
1117 }
1117 }
1118
1118
1119 #content div.box div.pagination ul.pager {
1119 #content div.box div.pagination ul.pager {
1120 float:right;
1120 float:right;
1121 text-align:right;
1121 text-align:right;
1122 margin:0;
1122 margin:0;
1123 padding:0;
1123 padding:0;
1124 }
1124 }
1125
1125
1126 #content div.box div.pagination ul.pager li {
1126 #content div.box div.pagination ul.pager li {
1127 height:1%;
1127 height:1%;
1128 float:left;
1128 float:left;
1129 list-style:none;
1129 list-style:none;
1130 background:#ebebeb url("../images/pager.png") repeat-x;
1130 background:#ebebeb url("../images/pager.png") repeat-x;
1131 border-top:1px solid #dedede;
1131 border-top:1px solid #dedede;
1132 border-left:1px solid #cfcfcf;
1132 border-left:1px solid #cfcfcf;
1133 border-right:1px solid #c4c4c4;
1133 border-right:1px solid #c4c4c4;
1134 border-bottom:1px solid #c4c4c4;
1134 border-bottom:1px solid #c4c4c4;
1135 color:#4A4A4A;
1135 color:#4A4A4A;
1136 font-weight:700;
1136 font-weight:700;
1137 margin:0 0 0 4px;
1137 margin:0 0 0 4px;
1138 padding:0;
1138 padding:0;
1139 }
1139 }
1140
1140
1141 #content div.box div.pagination ul.pager li.separator {
1141 #content div.box div.pagination ul.pager li.separator {
1142 padding:6px;
1142 padding:6px;
1143 }
1143 }
1144
1144
1145 #content div.box div.pagination ul.pager li.current {
1145 #content div.box div.pagination ul.pager li.current {
1146 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1146 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1147 border-top:1px solid #ccc;
1147 border-top:1px solid #ccc;
1148 border-left:1px solid #bebebe;
1148 border-left:1px solid #bebebe;
1149 border-right:1px solid #b1b1b1;
1149 border-right:1px solid #b1b1b1;
1150 border-bottom:1px solid #afafaf;
1150 border-bottom:1px solid #afafaf;
1151 color:#515151;
1151 color:#515151;
1152 padding:6px;
1152 padding:6px;
1153 }
1153 }
1154
1154
1155 #content div.box div.pagination ul.pager li a {
1155 #content div.box div.pagination ul.pager li a {
1156 height:1%;
1156 height:1%;
1157 display:block;
1157 display:block;
1158 float:left;
1158 float:left;
1159 color:#515151;
1159 color:#515151;
1160 text-decoration:none;
1160 text-decoration:none;
1161 margin:0;
1161 margin:0;
1162 padding:6px;
1162 padding:6px;
1163 }
1163 }
1164
1164
1165 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1165 #content div.box div.pagination ul.pager li a:hover,#content div.box div.pagination ul.pager li a:active {
1166 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1166 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1167 border-top:1px solid #ccc;
1167 border-top:1px solid #ccc;
1168 border-left:1px solid #bebebe;
1168 border-left:1px solid #bebebe;
1169 border-right:1px solid #b1b1b1;
1169 border-right:1px solid #b1b1b1;
1170 border-bottom:1px solid #afafaf;
1170 border-bottom:1px solid #afafaf;
1171 margin:-1px;
1171 margin:-1px;
1172 }
1172 }
1173
1173
1174 #content div.box div.pagination-wh {
1174 #content div.box div.pagination-wh {
1175 height:1%;
1175 height:1%;
1176 clear:both;
1176 clear:both;
1177 overflow:hidden;
1177 overflow:hidden;
1178 text-align:right;
1178 text-align:right;
1179 margin:10px 0 0;
1179 margin:10px 0 0;
1180 padding:0;
1180 padding:0;
1181 }
1181 }
1182
1182
1183 #content div.box div.pagination-right {
1183 #content div.box div.pagination-right {
1184 float:right;
1184 float:right;
1185 }
1185 }
1186
1186
1187 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1187 #content div.box div.pagination-wh a,#content div.box div.pagination-wh span.pager_dotdot {
1188 height:1%;
1188 height:1%;
1189 float:left;
1189 float:left;
1190 background:#ebebeb url("../images/pager.png") repeat-x;
1190 background:#ebebeb url("../images/pager.png") repeat-x;
1191 border-top:1px solid #dedede;
1191 border-top:1px solid #dedede;
1192 border-left:1px solid #cfcfcf;
1192 border-left:1px solid #cfcfcf;
1193 border-right:1px solid #c4c4c4;
1193 border-right:1px solid #c4c4c4;
1194 border-bottom:1px solid #c4c4c4;
1194 border-bottom:1px solid #c4c4c4;
1195 color:#4A4A4A;
1195 color:#4A4A4A;
1196 font-weight:700;
1196 font-weight:700;
1197 margin:0 0 0 4px;
1197 margin:0 0 0 4px;
1198 padding:6px;
1198 padding:6px;
1199 }
1199 }
1200
1200
1201 #content div.box div.pagination-wh span.pager_curpage {
1201 #content div.box div.pagination-wh span.pager_curpage {
1202 height:1%;
1202 height:1%;
1203 float:left;
1203 float:left;
1204 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1204 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1205 border-top:1px solid #ccc;
1205 border-top:1px solid #ccc;
1206 border-left:1px solid #bebebe;
1206 border-left:1px solid #bebebe;
1207 border-right:1px solid #b1b1b1;
1207 border-right:1px solid #b1b1b1;
1208 border-bottom:1px solid #afafaf;
1208 border-bottom:1px solid #afafaf;
1209 color:#515151;
1209 color:#515151;
1210 font-weight:700;
1210 font-weight:700;
1211 margin:0 0 0 4px;
1211 margin:0 0 0 4px;
1212 padding:6px;
1212 padding:6px;
1213 }
1213 }
1214
1214
1215 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1215 #content div.box div.pagination-wh a:hover,#content div.box div.pagination-wh a:active {
1216 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1216 background:#b4b4b4 url("../images/pager_selected.png") repeat-x;
1217 border-top:1px solid #ccc;
1217 border-top:1px solid #ccc;
1218 border-left:1px solid #bebebe;
1218 border-left:1px solid #bebebe;
1219 border-right:1px solid #b1b1b1;
1219 border-right:1px solid #b1b1b1;
1220 border-bottom:1px solid #afafaf;
1220 border-bottom:1px solid #afafaf;
1221 text-decoration:none;
1221 text-decoration:none;
1222 }
1222 }
1223
1223
1224 #content div.box div.traffic div.legend {
1224 #content div.box div.traffic div.legend {
1225 clear:both;
1225 clear:both;
1226 overflow:hidden;
1226 overflow:hidden;
1227 border-bottom:1px solid #ddd;
1227 border-bottom:1px solid #ddd;
1228 margin:0 0 10px;
1228 margin:0 0 10px;
1229 padding:0 0 10px;
1229 padding:0 0 10px;
1230 }
1230 }
1231
1231
1232 #content div.box div.traffic div.legend h6 {
1232 #content div.box div.traffic div.legend h6 {
1233 float:left;
1233 float:left;
1234 border:none;
1234 border:none;
1235 margin:0;
1235 margin:0;
1236 padding:0;
1236 padding:0;
1237 }
1237 }
1238
1238
1239 #content div.box div.traffic div.legend li {
1239 #content div.box div.traffic div.legend li {
1240 list-style:none;
1240 list-style:none;
1241 float:left;
1241 float:left;
1242 font-size:11px;
1242 font-size:11px;
1243 margin:0;
1243 margin:0;
1244 padding:0 8px 0 4px;
1244 padding:0 8px 0 4px;
1245 }
1245 }
1246
1246
1247 #content div.box div.traffic div.legend li.visits {
1247 #content div.box div.traffic div.legend li.visits {
1248 border-left:12px solid #edc240;
1248 border-left:12px solid #edc240;
1249 }
1249 }
1250
1250
1251 #content div.box div.traffic div.legend li.pageviews {
1251 #content div.box div.traffic div.legend li.pageviews {
1252 border-left:12px solid #afd8f8;
1252 border-left:12px solid #afd8f8;
1253 }
1253 }
1254
1254
1255 #content div.box div.traffic table {
1255 #content div.box div.traffic table {
1256 width:auto;
1256 width:auto;
1257 }
1257 }
1258
1258
1259 #content div.box div.traffic table td {
1259 #content div.box div.traffic table td {
1260 background:transparent;
1260 background:transparent;
1261 border:none;
1261 border:none;
1262 padding:2px 3px 3px;
1262 padding:2px 3px 3px;
1263 }
1263 }
1264
1264
1265 #content div.box div.traffic table td.legendLabel {
1265 #content div.box div.traffic table td.legendLabel {
1266 padding:0 3px 2px;
1266 padding:0 3px 2px;
1267 }
1267 }
1268
1268
1269 #footer {
1269 #footer {
1270 clear:both;
1270 clear:both;
1271 overflow:hidden;
1271 overflow:hidden;
1272 text-align:right;
1272 text-align:right;
1273 margin:0;
1273 margin:0;
1274 padding:0 10px 4px;
1274 padding:0 10px 4px;
1275 margin:-10px 0 0;
1275 margin:-10px 0 0;
1276 }
1276 }
1277
1277
1278 #footer div#footer-inner {
1278 #footer div#footer-inner {
1279 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1279 background:url("../images/header_inner.png") repeat-x scroll 0 0 #003367;
1280 border-top:2px solid #FFFFFF;
1280 border-top:2px solid #FFFFFF;
1281 }
1281 }
1282
1282
1283 #footer div#footer-inner p {
1283 #footer div#footer-inner p {
1284 padding:15px 25px 15px 0;
1284 padding:15px 25px 15px 0;
1285 color:#FFF;
1285 color:#FFF;
1286 font-weight:700;
1286 font-weight:700;
1287 }
1287 }
1288 #footer div#footer-inner .footer-link {
1288 #footer div#footer-inner .footer-link {
1289 float:left;
1289 float:left;
1290 padding-left:10px;
1290 padding-left:10px;
1291 }
1291 }
1292 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a {
1292 #footer div#footer-inner .footer-link a,#footer div#footer-inner .footer-link-right a {
1293 color:#FFF;
1293 color:#FFF;
1294 }
1294 }
1295
1295
1296 #login div.title {
1296 #login div.title {
1297 width:420px;
1297 width:420px;
1298 clear:both;
1298 clear:both;
1299 overflow:hidden;
1299 overflow:hidden;
1300 position:relative;
1300 position:relative;
1301 background:#003367 url("../images/header_inner.png") repeat-x;
1301 background:#003367 url("../images/header_inner.png") repeat-x;
1302 margin:0 auto;
1302 margin:0 auto;
1303 padding:0;
1303 padding:0;
1304 }
1304 }
1305
1305
1306 #login div.inner {
1306 #login div.inner {
1307 width:380px;
1307 width:380px;
1308 background:#FFF url("../images/login.png") no-repeat top left;
1308 background:#FFF url("../images/login.png") no-repeat top left;
1309 border-top:none;
1309 border-top:none;
1310 border-bottom:none;
1310 border-bottom:none;
1311 margin:0 auto;
1311 margin:0 auto;
1312 padding:20px;
1312 padding:20px;
1313 }
1313 }
1314
1314
1315 #login div.form div.fields div.field div.label {
1315 #login div.form div.fields div.field div.label {
1316 width:173px;
1316 width:173px;
1317 float:left;
1317 float:left;
1318 text-align:right;
1318 text-align:right;
1319 margin:2px 10px 0 0;
1319 margin:2px 10px 0 0;
1320 padding:5px 0 0 5px;
1320 padding:5px 0 0 5px;
1321 }
1321 }
1322
1322
1323 #login div.form div.fields div.field div.input input {
1323 #login div.form div.fields div.field div.input input {
1324 width:176px;
1324 width:176px;
1325 background:#FFF;
1325 background:#FFF;
1326 border-top:1px solid #b3b3b3;
1326 border-top:1px solid #b3b3b3;
1327 border-left:1px solid #b3b3b3;
1327 border-left:1px solid #b3b3b3;
1328 border-right:1px solid #eaeaea;
1328 border-right:1px solid #eaeaea;
1329 border-bottom:1px solid #eaeaea;
1329 border-bottom:1px solid #eaeaea;
1330 color:#000;
1330 color:#000;
1331 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1331 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1332 font-size:11px;
1332 font-size:11px;
1333 margin:0;
1333 margin:0;
1334 padding:7px 7px 6px;
1334 padding:7px 7px 6px;
1335 }
1335 }
1336
1336
1337 #login div.form div.fields div.buttons {
1337 #login div.form div.fields div.buttons {
1338 clear:both;
1338 clear:both;
1339 overflow:hidden;
1339 overflow:hidden;
1340 border-top:1px solid #DDD;
1340 border-top:1px solid #DDD;
1341 text-align:right;
1341 text-align:right;
1342 margin:0;
1342 margin:0;
1343 padding:10px 0 0;
1343 padding:10px 0 0;
1344 }
1344 }
1345
1345
1346 #login div.form div.links {
1346 #login div.form div.links {
1347 clear:both;
1347 clear:both;
1348 overflow:hidden;
1348 overflow:hidden;
1349 margin:10px 0 0;
1349 margin:10px 0 0;
1350 padding:0 0 2px;
1350 padding:0 0 2px;
1351 }
1351 }
1352
1352
1353 #register div.title {
1353 #register div.title {
1354 clear:both;
1354 clear:both;
1355 overflow:hidden;
1355 overflow:hidden;
1356 position:relative;
1356 position:relative;
1357 background:#003367 url("../images/header_inner.png") repeat-x;
1357 background:#003367 url("../images/header_inner.png") repeat-x;
1358 margin:0 auto;
1358 margin:0 auto;
1359 padding:0;
1359 padding:0;
1360 }
1360 }
1361
1361
1362 #register div.inner {
1362 #register div.inner {
1363 background:#FFF;
1363 background:#FFF;
1364 border-top:none;
1364 border-top:none;
1365 border-bottom:none;
1365 border-bottom:none;
1366 margin:0 auto;
1366 margin:0 auto;
1367 padding:20px;
1367 padding:20px;
1368 }
1368 }
1369
1369
1370 #register div.form div.fields div.field div.label {
1370 #register div.form div.fields div.field div.label {
1371 width:135px;
1371 width:135px;
1372 float:left;
1372 float:left;
1373 text-align:right;
1373 text-align:right;
1374 margin:2px 10px 0 0;
1374 margin:2px 10px 0 0;
1375 padding:5px 0 0 5px;
1375 padding:5px 0 0 5px;
1376 }
1376 }
1377
1377
1378 #register div.form div.fields div.field div.input input {
1378 #register div.form div.fields div.field div.input input {
1379 width:300px;
1379 width:300px;
1380 background:#FFF;
1380 background:#FFF;
1381 border-top:1px solid #b3b3b3;
1381 border-top:1px solid #b3b3b3;
1382 border-left:1px solid #b3b3b3;
1382 border-left:1px solid #b3b3b3;
1383 border-right:1px solid #eaeaea;
1383 border-right:1px solid #eaeaea;
1384 border-bottom:1px solid #eaeaea;
1384 border-bottom:1px solid #eaeaea;
1385 color:#000;
1385 color:#000;
1386 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1386 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1387 font-size:11px;
1387 font-size:11px;
1388 margin:0;
1388 margin:0;
1389 padding:7px 7px 6px;
1389 padding:7px 7px 6px;
1390 }
1390 }
1391
1391
1392 #register div.form div.fields div.buttons {
1392 #register div.form div.fields div.buttons {
1393 clear:both;
1393 clear:both;
1394 overflow:hidden;
1394 overflow:hidden;
1395 border-top:1px solid #DDD;
1395 border-top:1px solid #DDD;
1396 text-align:left;
1396 text-align:left;
1397 margin:0;
1397 margin:0;
1398 padding:10px 0 0 150px;
1398 padding:10px 0 0 150px;
1399 }
1399 }
1400
1400
1401 #register div.form div.fields div.buttons div.highlight input.ui-button {
1401 #register div.form div.fields div.buttons div.highlight input.ui-button {
1402 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1402 background:url("../images/button_highlight.png") repeat-x scroll 0 0 #4E85BB;
1403 color:#FFF;
1403 color:#FFF;
1404 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1404 border-color:#5C91A4 #2B7089 #1A6480 #2A6F89;
1405 border-style:solid;
1405 border-style:solid;
1406 border-width:1px;
1406 border-width:1px;
1407 }
1407 }
1408
1408
1409 #register div.form div.activation_msg {
1409 #register div.form div.activation_msg {
1410 padding-top:4px;
1410 padding-top:4px;
1411 padding-bottom:4px;
1411 padding-bottom:4px;
1412 }
1412 }
1413
1413
1414 #journal .journal_day{
1414 #journal .journal_day{
1415 font-size:20px;
1415 font-size:20px;
1416 padding:10px 0px;
1416 padding:10px 0px;
1417 border-bottom:2px solid #DDD;
1417 border-bottom:2px solid #DDD;
1418 margin-left:10px;
1418 margin-left:10px;
1419 margin-right:10px;
1419 margin-right:10px;
1420 }
1420 }
1421
1421
1422 #journal .journal_container{
1422 #journal .journal_container{
1423 padding:5px;
1423 padding:5px;
1424 clear:both;
1424 clear:both;
1425 margin:0px 5px 0px 10px;
1425 margin:0px 5px 0px 10px;
1426 }
1426 }
1427
1427
1428 #journal .journal_action_container{
1428 #journal .journal_action_container{
1429 padding-left:38px;
1429 padding-left:38px;
1430 }
1430 }
1431
1431
1432 #journal .journal_user{
1432 #journal .journal_user{
1433 color: #747474;
1433 color: #747474;
1434 font-size: 14px;
1434 font-size: 14px;
1435 font-weight: bold;
1435 font-weight: bold;
1436 height: 30px;
1436 height: 30px;
1437 }
1437 }
1438 #journal .journal_icon{
1438 #journal .journal_icon{
1439 clear: both;
1439 clear: both;
1440 float: left;
1440 float: left;
1441 padding-right: 4px;
1441 padding-right: 4px;
1442 padding-top: 3px;
1442 padding-top: 3px;
1443 }
1443 }
1444 #journal .journal_action{
1444 #journal .journal_action{
1445 padding-top:4px;
1445 padding-top:4px;
1446 min-height:2px;
1446 min-height:2px;
1447 float:left
1447 float:left
1448 }
1448 }
1449 #journal .journal_action_params{
1449 #journal .journal_action_params{
1450 clear: left;
1450 clear: left;
1451 padding-left: 22px;
1451 padding-left: 22px;
1452 }
1452 }
1453 #journal .journal_repo{
1453 #journal .journal_repo{
1454 float: left;
1454 float: left;
1455 margin-left: 6px;
1455 margin-left: 6px;
1456 padding-top: 3px;
1456 padding-top: 3px;
1457 }
1457 }
1458 #journal .date{
1458 #journal .date{
1459 clear: both;
1459 clear: both;
1460 color: #777777;
1460 color: #777777;
1461 font-size: 11px;
1461 font-size: 11px;
1462 padding-left: 22px;
1462 padding-left: 22px;
1463 }
1463 }
1464 #journal .journal_repo .journal_repo_name{
1464 #journal .journal_repo .journal_repo_name{
1465 font-weight: bold;
1465 font-weight: bold;
1466 font-size: 1.1em;
1466 font-size: 1.1em;
1467 }
1467 }
1468 #journal .compare_view{
1468 #journal .compare_view{
1469 padding: 5px 0px 5px 0px;
1469 padding: 5px 0px 5px 0px;
1470 width: 95px;
1470 width: 95px;
1471 }
1471 }
1472 .journal_highlight{
1472 .journal_highlight{
1473 font-weight: bold;
1473 font-weight: bold;
1474 padding: 0 2px;
1474 padding: 0 2px;
1475 vertical-align: bottom;
1475 vertical-align: bottom;
1476 }
1476 }
1477 .trending_language_tbl,.trending_language_tbl td {
1477 .trending_language_tbl,.trending_language_tbl td {
1478 border:0 !important;
1478 border:0 !important;
1479 margin:0 !important;
1479 margin:0 !important;
1480 padding:0 !important;
1480 padding:0 !important;
1481 }
1481 }
1482
1482
1483 .trending_language {
1483 .trending_language {
1484 background-color:#003367;
1484 background-color:#003367;
1485 color:#FFF;
1485 color:#FFF;
1486 display:block;
1486 display:block;
1487 min-width:20px;
1487 min-width:20px;
1488 text-decoration:none;
1488 text-decoration:none;
1489 height:12px;
1489 height:12px;
1490 margin-bottom:4px;
1490 margin-bottom:4px;
1491 margin-left:5px;
1491 margin-left:5px;
1492 white-space:pre;
1492 white-space:pre;
1493 padding:3px;
1493 padding:3px;
1494 }
1494 }
1495
1495
1496 h3.files_location {
1496 h3.files_location {
1497 font-size:1.8em;
1497 font-size:1.8em;
1498 font-weight:700;
1498 font-weight:700;
1499 border-bottom:none !important;
1499 border-bottom:none !important;
1500 margin:10px 0 !important;
1500 margin:10px 0 !important;
1501 }
1501 }
1502
1502
1503 #files_data dl dt {
1503 #files_data dl dt {
1504 float:left;
1504 float:left;
1505 width:115px;
1505 width:115px;
1506 margin:0 !important;
1506 margin:0 !important;
1507 padding:5px;
1507 padding:5px;
1508 }
1508 }
1509
1509
1510 #files_data dl dd {
1510 #files_data dl dd {
1511 margin:0 !important;
1511 margin:0 !important;
1512 padding:5px !important;
1512 padding:5px !important;
1513 }
1513 }
1514
1514
1515 #changeset_content {
1515 #changeset_content {
1516 border:1px solid #CCC;
1516 border:1px solid #CCC;
1517 padding:5px;
1517 padding:5px;
1518 }
1518 }
1519 #changeset_compare_view_content{
1519 #changeset_compare_view_content{
1520 border:1px solid #CCC;
1520 border:1px solid #CCC;
1521 padding:5px;
1521 padding:5px;
1522 }
1522 }
1523
1523
1524 #changeset_content .container {
1524 #changeset_content .container {
1525 min-height:120px;
1525 min-height:120px;
1526 font-size:1.2em;
1526 font-size:1.2em;
1527 overflow:hidden;
1527 overflow:hidden;
1528 }
1528 }
1529
1529
1530 #changeset_compare_view_content .compare_view_commits{
1530 #changeset_compare_view_content .compare_view_commits{
1531 width: auto !important;
1531 width: auto !important;
1532 }
1532 }
1533
1533
1534 #changeset_compare_view_content .compare_view_commits td{
1534 #changeset_compare_view_content .compare_view_commits td{
1535 padding:0px 0px 0px 12px !important;
1535 padding:0px 0px 0px 12px !important;
1536 }
1536 }
1537
1537
1538 #changeset_content .container .right {
1538 #changeset_content .container .right {
1539 float:right;
1539 float:right;
1540 width:25%;
1540 width:25%;
1541 text-align:right;
1541 text-align:right;
1542 }
1542 }
1543
1543
1544 #changeset_content .container .left .message {
1544 #changeset_content .container .left .message {
1545 font-style:italic;
1545 font-style:italic;
1546 color:#556CB5;
1546 color:#556CB5;
1547 white-space:pre-wrap;
1547 white-space:pre-wrap;
1548 }
1548 }
1549
1549
1550 .cs_files .cur_cs{
1550 .cs_files .cur_cs{
1551 margin:10px 2px;
1551 margin:10px 2px;
1552 font-weight: bold;
1552 font-weight: bold;
1553 }
1553 }
1554
1554
1555 .cs_files .node{
1555 .cs_files .node{
1556 float: left;
1556 float: left;
1557 }
1557 }
1558 .cs_files .changes{
1558 .cs_files .changes{
1559 float: right;
1559 float: right;
1560 }
1560 }
1561 .cs_files .changes .added{
1561 .cs_files .changes .added{
1562 background-color: #BBFFBB;
1562 background-color: #BBFFBB;
1563 float: left;
1563 float: left;
1564 text-align: center;
1564 text-align: center;
1565 font-size: 90%;
1565 font-size: 90%;
1566 }
1566 }
1567 .cs_files .changes .deleted{
1567 .cs_files .changes .deleted{
1568 background-color: #FF8888;
1568 background-color: #FF8888;
1569 float: left;
1569 float: left;
1570 text-align: center;
1570 text-align: center;
1571 font-size: 90%;
1571 font-size: 90%;
1572 }
1572 }
1573 .cs_files .cs_added {
1573 .cs_files .cs_added {
1574 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1574 background:url("../images/icons/page_white_add.png") no-repeat scroll 3px;
1575 height:16px;
1575 height:16px;
1576 padding-left:20px;
1576 padding-left:20px;
1577 margin-top:7px;
1577 margin-top:7px;
1578 text-align:left;
1578 text-align:left;
1579 }
1579 }
1580
1580
1581 .cs_files .cs_changed {
1581 .cs_files .cs_changed {
1582 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1582 background:url("../images/icons/page_white_edit.png") no-repeat scroll 3px;
1583 height:16px;
1583 height:16px;
1584 padding-left:20px;
1584 padding-left:20px;
1585 margin-top:7px;
1585 margin-top:7px;
1586 text-align:left;
1586 text-align:left;
1587 }
1587 }
1588
1588
1589 .cs_files .cs_removed {
1589 .cs_files .cs_removed {
1590 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1590 background:url("../images/icons/page_white_delete.png") no-repeat scroll 3px;
1591 height:16px;
1591 height:16px;
1592 padding-left:20px;
1592 padding-left:20px;
1593 margin-top:7px;
1593 margin-top:7px;
1594 text-align:left;
1594 text-align:left;
1595 }
1595 }
1596
1596
1597 #graph {
1597 #graph {
1598 overflow:hidden;
1598 overflow:hidden;
1599 }
1599 }
1600
1600
1601 #graph_nodes {
1601 #graph_nodes {
1602 width:160px;
1602 width:160px;
1603 float:left;
1603 float:left;
1604 margin-left:-50px;
1604 margin-left:-50px;
1605 margin-top:5px;
1605 margin-top:5px;
1606 }
1606 }
1607
1607
1608 #graph_content {
1608 #graph_content {
1609 width:800px;
1609 width:800px;
1610 float:left;
1610 float:left;
1611 }
1611 }
1612
1612
1613 #graph_content .container_header {
1613 #graph_content .container_header {
1614 border:1px solid #CCC;
1614 border:1px solid #CCC;
1615 padding:10px;
1615 padding:10px;
1616 }
1616 }
1617 #graph_content #rev_range_container{
1617 #graph_content #rev_range_container{
1618 padding:10px 0px;
1618 padding:10px 0px;
1619 }
1619 }
1620 #graph_content .container {
1620 #graph_content .container {
1621 border-bottom:1px solid #CCC;
1621 border-bottom:1px solid #CCC;
1622 border-left:1px solid #CCC;
1622 border-left:1px solid #CCC;
1623 border-right:1px solid #CCC;
1623 border-right:1px solid #CCC;
1624 min-height:80px;
1624 min-height:80px;
1625 overflow:hidden;
1625 overflow:hidden;
1626 font-size:1.2em;
1626 font-size:1.2em;
1627 }
1627 }
1628
1628
1629 #graph_content .container .right {
1629 #graph_content .container .right {
1630 float:right;
1630 float:right;
1631 width:28%;
1631 width:28%;
1632 text-align:right;
1632 text-align:right;
1633 padding-bottom:5px;
1633 padding-bottom:5px;
1634 }
1634 }
1635
1635
1636 #graph_content .container .left .date {
1636 #graph_content .container .left .date {
1637 font-weight:700;
1637 font-weight:700;
1638 padding-bottom:5px;
1638 padding-bottom:5px;
1639 }
1639 }
1640 #graph_content .container .left .date span{
1640 #graph_content .container .left .date span{
1641 vertical-align: text-top;
1641 vertical-align: text-top;
1642 }
1642 }
1643
1643
1644 #graph_content .container .left .message {
1644 #graph_content .container .left .message {
1645 font-size:100%;
1645 font-size:100%;
1646 padding-top:3px;
1646 padding-top:3px;
1647 white-space:pre-wrap;
1647 white-space:pre-wrap;
1648 }
1648 }
1649
1649
1650 .right div {
1650 .right div {
1651 clear:both;
1651 clear:both;
1652 }
1652 }
1653
1653
1654 .right .changes .added,.changed,.removed {
1654 .right .changes .added,.changed,.removed {
1655 border:1px solid #DDD;
1655 border:1px solid #DDD;
1656 display:block;
1656 display:block;
1657 float:right;
1657 float:right;
1658 text-align:center;
1658 text-align:center;
1659 min-width:15px;
1659 min-width:15px;
1660 cursor: help;
1660 cursor: help;
1661 }
1661 }
1662 .right .changes .large {
1662 .right .changes .large {
1663 border:1px solid #DDD;
1663 border:1px solid #DDD;
1664 display:block;
1664 display:block;
1665 float:right;
1665 float:right;
1666 text-align:center;
1666 text-align:center;
1667 min-width:45px;
1667 min-width:45px;
1668 cursor: help;
1668 cursor: help;
1669 background: #54A9F7;
1669 background: #54A9F7;
1670 }
1670 }
1671
1671
1672 .right .changes .added {
1672 .right .changes .added {
1673 background:#BFB;
1673 background:#BFB;
1674 }
1674 }
1675
1675
1676 .right .changes .changed {
1676 .right .changes .changed {
1677 background:#FD8;
1677 background:#FD8;
1678 }
1678 }
1679
1679
1680 .right .changes .removed {
1680 .right .changes .removed {
1681 background:#F88;
1681 background:#F88;
1682 }
1682 }
1683
1683
1684 .right .merge {
1684 .right .merge {
1685 vertical-align:top;
1685 vertical-align:top;
1686 font-size:0.75em;
1686 font-size:0.75em;
1687 font-weight:700;
1687 font-weight:700;
1688 }
1688 }
1689
1689
1690 .right .parent {
1690 .right .parent {
1691 font-size:90%;
1691 font-size:90%;
1692 font-family:monospace;
1692 font-family:monospace;
1693 }
1693 }
1694
1694
1695 .right .logtags .branchtag {
1695 .right .logtags .branchtag {
1696 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1696 background:#FFF url("../images/icons/arrow_branch.png") no-repeat right 6px;
1697 display:block;
1697 display:block;
1698 font-size:0.8em;
1698 font-size:0.8em;
1699 padding:11px 16px 0 0;
1699 padding:11px 16px 0 0;
1700 }
1700 }
1701
1701
1702 .right .logtags .tagtag {
1702 .right .logtags .tagtag {
1703 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1703 background:#FFF url("../images/icons/tag_blue.png") no-repeat right 6px;
1704 display:block;
1704 display:block;
1705 font-size:0.8em;
1705 font-size:0.8em;
1706 padding:11px 16px 0 0;
1706 padding:11px 16px 0 0;
1707 }
1707 }
1708
1708
1709 div.browserblock {
1709 div.browserblock {
1710 overflow:hidden;
1710 overflow:hidden;
1711 border:1px solid #ccc;
1711 border:1px solid #ccc;
1712 background:#f8f8f8;
1712 background:#f8f8f8;
1713 font-size:100%;
1713 font-size:100%;
1714 line-height:125%;
1714 line-height:125%;
1715 padding:0;
1715 padding:0;
1716 }
1716 }
1717
1717
1718 div.browserblock .browser-header {
1718 div.browserblock .browser-header {
1719 background:#FFF;
1719 background:#FFF;
1720 padding:10px 0px 25px 0px;
1720 padding:10px 0px 25px 0px;
1721 width: 100%;
1721 width: 100%;
1722 }
1722 }
1723 div.browserblock .browser-nav {
1723 div.browserblock .browser-nav {
1724 float:left
1724 float:left
1725 }
1725 }
1726
1726
1727 div.browserblock .browser-branch {
1727 div.browserblock .browser-branch {
1728 float:left;
1728 float:left;
1729 }
1729 }
1730
1730
1731 div.browserblock .browser-branch label {
1731 div.browserblock .browser-branch label {
1732 color:#4A4A4A;
1732 color:#4A4A4A;
1733 vertical-align:text-top;
1733 vertical-align:text-top;
1734 }
1734 }
1735
1735
1736 div.browserblock .browser-header span {
1736 div.browserblock .browser-header span {
1737 margin-left:5px;
1737 margin-left:5px;
1738 font-weight:700;
1738 font-weight:700;
1739 }
1739 }
1740
1740
1741 div.browserblock .browser-body {
1741 div.browserblock .browser-body {
1742 background:#EEE;
1742 background:#EEE;
1743 border-top:1px solid #CCC;
1743 border-top:1px solid #CCC;
1744 }
1744 }
1745
1745
1746 table.code-browser {
1746 table.code-browser {
1747 border-collapse:collapse;
1747 border-collapse:collapse;
1748 width:100%;
1748 width:100%;
1749 }
1749 }
1750
1750
1751 table.code-browser tr {
1751 table.code-browser tr {
1752 margin:3px;
1752 margin:3px;
1753 }
1753 }
1754
1754
1755 table.code-browser thead th {
1755 table.code-browser thead th {
1756 background-color:#EEE;
1756 background-color:#EEE;
1757 height:20px;
1757 height:20px;
1758 font-size:1.1em;
1758 font-size:1.1em;
1759 font-weight:700;
1759 font-weight:700;
1760 text-align:left;
1760 text-align:left;
1761 padding-left:10px;
1761 padding-left:10px;
1762 }
1762 }
1763
1763
1764 table.code-browser tbody td {
1764 table.code-browser tbody td {
1765 padding-left:10px;
1765 padding-left:10px;
1766 height:20px;
1766 height:20px;
1767 }
1767 }
1768
1768
1769 table.code-browser .browser-file {
1769 table.code-browser .browser-file {
1770 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1770 background:url("../images/icons/document_16.png") no-repeat scroll 3px;
1771 height:16px;
1771 height:16px;
1772 padding-left:20px;
1772 padding-left:20px;
1773 text-align:left;
1773 text-align:left;
1774 }
1774 }
1775 .diffblock .changeset_file{
1775 .diffblock .changeset_file{
1776 background:url("../images/icons/file.png") no-repeat scroll 3px;
1776 background:url("../images/icons/file.png") no-repeat scroll 3px;
1777 height:16px;
1777 height:16px;
1778 padding-left:22px;
1778 padding-left:22px;
1779 text-align:left;
1779 text-align:left;
1780 font-size: 14px;
1780 font-size: 14px;
1781 }
1781 }
1782
1782
1783 .diffblock .changeset_header{
1783 .diffblock .changeset_header{
1784 margin-left: 6px !important;
1784 margin-left: 6px !important;
1785 }
1785 }
1786
1786
1787 table.code-browser .browser-dir {
1787 table.code-browser .browser-dir {
1788 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1788 background:url("../images/icons/folder_16.png") no-repeat scroll 3px;
1789 height:16px;
1789 height:16px;
1790 padding-left:20px;
1790 padding-left:20px;
1791 text-align:left;
1791 text-align:left;
1792 }
1792 }
1793
1793
1794 .box .search {
1794 .box .search {
1795 clear:both;
1795 clear:both;
1796 overflow:hidden;
1796 overflow:hidden;
1797 margin:0;
1797 margin:0;
1798 padding:0 20px 10px;
1798 padding:0 20px 10px;
1799 }
1799 }
1800
1800
1801 .box .search div.search_path {
1801 .box .search div.search_path {
1802 background:none repeat scroll 0 0 #EEE;
1802 background:none repeat scroll 0 0 #EEE;
1803 border:1px solid #CCC;
1803 border:1px solid #CCC;
1804 color:blue;
1804 color:blue;
1805 margin-bottom:10px;
1805 margin-bottom:10px;
1806 padding:10px 0;
1806 padding:10px 0;
1807 }
1807 }
1808
1808
1809 .box .search div.search_path div.link {
1809 .box .search div.search_path div.link {
1810 font-weight:700;
1810 font-weight:700;
1811 margin-left:25px;
1811 margin-left:25px;
1812 }
1812 }
1813
1813
1814 .box .search div.search_path div.link a {
1814 .box .search div.search_path div.link a {
1815 color:#003367;
1815 color:#003367;
1816 cursor:pointer;
1816 cursor:pointer;
1817 text-decoration:none;
1817 text-decoration:none;
1818 }
1818 }
1819
1819
1820 #path_unlock {
1820 #path_unlock {
1821 color:red;
1821 color:red;
1822 font-size:1.2em;
1822 font-size:1.2em;
1823 padding-left:4px;
1823 padding-left:4px;
1824 }
1824 }
1825
1825
1826 .info_box span {
1826 .info_box span {
1827 margin-left:3px;
1827 margin-left:3px;
1828 margin-right:3px;
1828 margin-right:3px;
1829 }
1829 }
1830
1830
1831 .info_box .rev {
1831 .info_box .rev {
1832 color: #003367;
1832 color: #003367;
1833 font-size: 1.6em;
1833 font-size: 1.6em;
1834 font-weight: bold;
1834 font-weight: bold;
1835 vertical-align: sub;
1835 vertical-align: sub;
1836 }
1836 }
1837
1837
1838
1838
1839 .info_box input#at_rev,.info_box input#size {
1839 .info_box input#at_rev,.info_box input#size {
1840 background:#FFF;
1840 background:#FFF;
1841 border-top:1px solid #b3b3b3;
1841 border-top:1px solid #b3b3b3;
1842 border-left:1px solid #b3b3b3;
1842 border-left:1px solid #b3b3b3;
1843 border-right:1px solid #eaeaea;
1843 border-right:1px solid #eaeaea;
1844 border-bottom:1px solid #eaeaea;
1844 border-bottom:1px solid #eaeaea;
1845 color:#000;
1845 color:#000;
1846 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1846 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
1847 font-size:12px;
1847 font-size:12px;
1848 margin:0;
1848 margin:0;
1849 padding:1px 5px 1px;
1849 padding:1px 5px 1px;
1850 }
1850 }
1851
1851
1852
1852
1853
1853
1854 .info_box input#view {
1854 .info_box input#view {
1855 text-align:center;
1855 text-align:center;
1856 padding:4px 3px 2px 2px;
1856 padding:4px 3px 2px 2px;
1857 }
1857 }
1858
1858
1859 .yui-overlay,.yui-panel-container {
1859 .yui-overlay,.yui-panel-container {
1860 visibility:hidden;
1860 visibility:hidden;
1861 position:absolute;
1861 position:absolute;
1862 z-index:2;
1862 z-index:2;
1863 }
1863 }
1864
1864
1865 .yui-tt {
1865 .yui-tt {
1866 visibility:hidden;
1866 visibility:hidden;
1867 position:absolute;
1867 position:absolute;
1868 color:#666;
1868 color:#666;
1869 background-color:#FFF;
1869 background-color:#FFF;
1870 font-family:arial, helvetica, verdana, sans-serif;
1870 font-family:arial, helvetica, verdana, sans-serif;
1871 border:2px solid #003367;
1871 border:2px solid #003367;
1872 font:100% sans-serif;
1872 font:100% sans-serif;
1873 width:auto;
1873 width:auto;
1874 opacity:1px;
1874 opacity:1px;
1875 padding:8px;
1875 padding:8px;
1876 white-space: pre;
1876 white-space: pre;
1877 -webkit-border-radius: 8px 8px 8px 8px;
1877 -webkit-border-radius: 8px 8px 8px 8px;
1878 -khtml-border-radius: 8px 8px 8px 8px;
1878 -khtml-border-radius: 8px 8px 8px 8px;
1879 -moz-border-radius: 8px 8px 8px 8px;
1879 -moz-border-radius: 8px 8px 8px 8px;
1880 border-radius: 8px 8px 8px 8px;
1880 border-radius: 8px 8px 8px 8px;
1881 }
1881 }
1882
1882
1883 .ac {
1883 .ac {
1884 vertical-align:top;
1884 vertical-align:top;
1885 }
1885 }
1886
1886
1887 .ac .yui-ac {
1887 .ac .yui-ac {
1888 position:relative;
1888 position:relative;
1889 font-family:arial;
1889 font-family:arial;
1890 font-size:100%;
1890 font-size:100%;
1891 }
1891 }
1892
1892
1893 .ac .perm_ac {
1893 .ac .perm_ac {
1894 width:15em;
1894 width:15em;
1895 }
1895 }
1896
1896
1897 .ac .yui-ac-input {
1897 .ac .yui-ac-input {
1898 width:100%;
1898 width:100%;
1899 }
1899 }
1900
1900
1901 .ac .yui-ac-container {
1901 .ac .yui-ac-container {
1902 position:absolute;
1902 position:absolute;
1903 top:1.6em;
1903 top:1.6em;
1904 width:100%;
1904 width:100%;
1905 }
1905 }
1906
1906
1907 .ac .yui-ac-content {
1907 .ac .yui-ac-content {
1908 position:absolute;
1908 position:absolute;
1909 width:100%;
1909 width:100%;
1910 border:1px solid gray;
1910 border:1px solid gray;
1911 background:#fff;
1911 background:#fff;
1912 overflow:hidden;
1912 overflow:hidden;
1913 z-index:9050;
1913 z-index:9050;
1914 }
1914 }
1915
1915
1916 .ac .yui-ac-shadow {
1916 .ac .yui-ac-shadow {
1917 position:absolute;
1917 position:absolute;
1918 width:100%;
1918 width:100%;
1919 background:#000;
1919 background:#000;
1920 -moz-opacity:0.1px;
1920 -moz-opacity:0.1px;
1921 opacity:.10;
1921 opacity:.10;
1922 filter:alpha(opacity = 10);
1922 filter:alpha(opacity = 10);
1923 z-index:9049;
1923 z-index:9049;
1924 margin:.3em;
1924 margin:.3em;
1925 }
1925 }
1926
1926
1927 .ac .yui-ac-content ul {
1927 .ac .yui-ac-content ul {
1928 width:100%;
1928 width:100%;
1929 margin:0;
1929 margin:0;
1930 padding:0;
1930 padding:0;
1931 }
1931 }
1932
1932
1933 .ac .yui-ac-content li {
1933 .ac .yui-ac-content li {
1934 cursor:default;
1934 cursor:default;
1935 white-space:nowrap;
1935 white-space:nowrap;
1936 margin:0;
1936 margin:0;
1937 padding:2px 5px;
1937 padding:2px 5px;
1938 }
1938 }
1939
1939
1940 .ac .yui-ac-content li.yui-ac-prehighlight {
1940 .ac .yui-ac-content li.yui-ac-prehighlight {
1941 background:#B3D4FF;
1941 background:#B3D4FF;
1942 }
1942 }
1943
1943
1944 .ac .yui-ac-content li.yui-ac-highlight {
1944 .ac .yui-ac-content li.yui-ac-highlight {
1945 background:#556CB5;
1945 background:#556CB5;
1946 color:#FFF;
1946 color:#FFF;
1947 }
1947 }
1948
1948
1949
1949
1950 .follow{
1950 .follow{
1951 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
1951 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
1952 height: 16px;
1952 height: 16px;
1953 width: 20px;
1953 width: 20px;
1954 cursor: pointer;
1954 cursor: pointer;
1955 display: block;
1955 display: block;
1956 float: right;
1956 float: right;
1957 margin-top: 2px;
1957 margin-top: 2px;
1958 }
1958 }
1959
1959
1960 .following{
1960 .following{
1961 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
1961 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
1962 height: 16px;
1962 height: 16px;
1963 width: 20px;
1963 width: 20px;
1964 cursor: pointer;
1964 cursor: pointer;
1965 display: block;
1965 display: block;
1966 float: right;
1966 float: right;
1967 margin-top: 2px;
1967 margin-top: 2px;
1968 }
1968 }
1969
1969
1970 .currently_following{
1970 .currently_following{
1971 padding-left: 10px;
1971 padding-left: 10px;
1972 padding-bottom:5px;
1972 padding-bottom:5px;
1973 }
1973 }
1974
1974
1975 .add_icon {
1975 .add_icon {
1976 background:url("../images/icons/add.png") no-repeat scroll 3px;
1976 background:url("../images/icons/add.png") no-repeat scroll 3px;
1977 padding-left:20px;
1977 padding-left:20px;
1978 padding-top:0px;
1978 padding-top:0px;
1979 text-align:left;
1979 text-align:left;
1980 }
1980 }
1981
1981
1982 .edit_icon {
1982 .edit_icon {
1983 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1983 background:url("../images/icons/folder_edit.png") no-repeat scroll 3px;
1984 padding-left:20px;
1984 padding-left:20px;
1985 padding-top:0px;
1985 padding-top:0px;
1986 text-align:left;
1986 text-align:left;
1987 }
1987 }
1988
1988
1989 .delete_icon {
1989 .delete_icon {
1990 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1990 background:url("../images/icons/delete.png") no-repeat scroll 3px;
1991 padding-left:20px;
1991 padding-left:20px;
1992 padding-top:0px;
1992 padding-top:0px;
1993 text-align:left;
1993 text-align:left;
1994 }
1994 }
1995
1995
1996 .refresh_icon {
1996 .refresh_icon {
1997 background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
1997 background:url("../images/icons/arrow_refresh.png") no-repeat scroll 3px;
1998 padding-left:20px;
1998 padding-left:20px;
1999 padding-top:0px;
1999 padding-top:0px;
2000 text-align:left;
2000 text-align:left;
2001 }
2001 }
2002
2002
2003 .pull_icon {
2003 .pull_icon {
2004 background:url("../images/icons/connect.png") no-repeat scroll 3px;
2004 background:url("../images/icons/connect.png") no-repeat scroll 3px;
2005 padding-left:20px;
2005 padding-left:20px;
2006 padding-top:0px;
2006 padding-top:0px;
2007 text-align:left;
2007 text-align:left;
2008 }
2008 }
2009
2009
2010 .rss_icon {
2010 .rss_icon {
2011 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
2011 background:url("../images/icons/rss_16.png") no-repeat scroll 3px;
2012 padding-left:20px;
2012 padding-left:20px;
2013 padding-top:0px;
2013 padding-top:0px;
2014 text-align:left;
2014 text-align:left;
2015 }
2015 }
2016
2016
2017 .atom_icon {
2017 .atom_icon {
2018 background:url("../images/icons/atom.png") no-repeat scroll 3px;
2018 background:url("../images/icons/atom.png") no-repeat scroll 3px;
2019 padding-left:20px;
2019 padding-left:20px;
2020 padding-top:0px;
2020 padding-top:0px;
2021 text-align:left;
2021 text-align:left;
2022 }
2022 }
2023
2023
2024 .archive_icon {
2024 .archive_icon {
2025 background:url("../images/icons/compress.png") no-repeat scroll 3px;
2025 background:url("../images/icons/compress.png") no-repeat scroll 3px;
2026 padding-left:20px;
2026 padding-left:20px;
2027 text-align:left;
2027 text-align:left;
2028 padding-top:1px;
2028 padding-top:1px;
2029 }
2029 }
2030
2030
2031 .start_following_icon {
2031 .start_following_icon {
2032 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2032 background:url("../images/icons/heart_add.png") no-repeat scroll 3px;
2033 padding-left:20px;
2033 padding-left:20px;
2034 text-align:left;
2034 text-align:left;
2035 padding-top:0px;
2035 padding-top:0px;
2036 }
2036 }
2037
2037
2038 .stop_following_icon {
2038 .stop_following_icon {
2039 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2039 background:url("../images/icons/heart_delete.png") no-repeat scroll 3px;
2040 padding-left:20px;
2040 padding-left:20px;
2041 text-align:left;
2041 text-align:left;
2042 padding-top:0px;
2042 padding-top:0px;
2043 }
2043 }
2044
2044
2045 .action_button {
2045 .action_button {
2046 border:0;
2046 border:0;
2047 display:block;
2047 display:block;
2048 }
2048 }
2049
2049
2050 .action_button:hover {
2050 .action_button:hover {
2051 border:0;
2051 border:0;
2052 text-decoration:underline;
2052 text-decoration:underline;
2053 cursor:pointer;
2053 cursor:pointer;
2054 }
2054 }
2055
2055
2056 #switch_repos {
2056 #switch_repos {
2057 position:absolute;
2057 position:absolute;
2058 height:25px;
2058 height:25px;
2059 z-index:1;
2059 z-index:1;
2060 }
2060 }
2061
2061
2062 #switch_repos select {
2062 #switch_repos select {
2063 min-width:150px;
2063 min-width:150px;
2064 max-height:250px;
2064 max-height:250px;
2065 z-index:1;
2065 z-index:1;
2066 }
2066 }
2067
2067
2068 .breadcrumbs {
2068 .breadcrumbs {
2069 border:medium none;
2069 border:medium none;
2070 color:#FFF;
2070 color:#FFF;
2071 float:left;
2071 float:left;
2072 text-transform:uppercase;
2072 text-transform:uppercase;
2073 font-weight:700;
2073 font-weight:700;
2074 font-size:14px;
2074 font-size:14px;
2075 margin:0;
2075 margin:0;
2076 padding:11px 0 11px 10px;
2076 padding:11px 0 11px 10px;
2077 }
2077 }
2078
2078
2079 .breadcrumbs a {
2079 .breadcrumbs a {
2080 color:#FFF;
2080 color:#FFF;
2081 }
2081 }
2082
2082
2083 .flash_msg ul {
2083 .flash_msg ul {
2084 margin:0;
2084 margin:0;
2085 padding:0 0 10px;
2085 padding:0 0 10px;
2086 }
2086 }
2087
2087
2088 .error_msg {
2088 .error_msg {
2089 background-color:#FFCFCF;
2089 background-color:#FFCFCF;
2090 background-image:url("../images/icons/error_msg.png");
2090 background-image:url("../images/icons/error_msg.png");
2091 border:1px solid #FF9595;
2091 border:1px solid #FF9595;
2092 color:#C30;
2092 color:#C30;
2093 }
2093 }
2094
2094
2095 .warning_msg {
2095 .warning_msg {
2096 background-color:#FFFBCC;
2096 background-color:#FFFBCC;
2097 background-image:url("../images/icons/warning_msg.png");
2097 background-image:url("../images/icons/warning_msg.png");
2098 border:1px solid #FFF35E;
2098 border:1px solid #FFF35E;
2099 color:#C69E00;
2099 color:#C69E00;
2100 }
2100 }
2101
2101
2102 .success_msg {
2102 .success_msg {
2103 background-color:#D5FFCF;
2103 background-color:#D5FFCF;
2104 background-image:url("../images/icons/success_msg.png");
2104 background-image:url("../images/icons/success_msg.png");
2105 border:1px solid #97FF88;
2105 border:1px solid #97FF88;
2106 color:#090;
2106 color:#090;
2107 }
2107 }
2108
2108
2109 .notice_msg {
2109 .notice_msg {
2110 background-color:#DCE3FF;
2110 background-color:#DCE3FF;
2111 background-image:url("../images/icons/notice_msg.png");
2111 background-image:url("../images/icons/notice_msg.png");
2112 border:1px solid #93A8FF;
2112 border:1px solid #93A8FF;
2113 color:#556CB5;
2113 color:#556CB5;
2114 }
2114 }
2115
2115
2116 .success_msg,.error_msg,.notice_msg,.warning_msg {
2116 .success_msg,.error_msg,.notice_msg,.warning_msg {
2117 background-position:10px center;
2117 background-position:10px center;
2118 background-repeat:no-repeat;
2118 background-repeat:no-repeat;
2119 font-size:12px;
2119 font-size:12px;
2120 font-weight:700;
2120 font-weight:700;
2121 min-height:14px;
2121 min-height:14px;
2122 line-height:14px;
2122 line-height:14px;
2123 margin-bottom:0;
2123 margin-bottom:0;
2124 margin-top:0;
2124 margin-top:0;
2125 display:block;
2125 display:block;
2126 overflow:auto;
2126 overflow:auto;
2127 padding:6px 10px 6px 40px;
2127 padding:6px 10px 6px 40px;
2128 }
2128 }
2129
2129
2130 #msg_close {
2130 #msg_close {
2131 background:transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
2131 background:transparent url("../icons/cross_grey_small.png") no-repeat scroll 0 0;
2132 cursor:pointer;
2132 cursor:pointer;
2133 height:16px;
2133 height:16px;
2134 position:absolute;
2134 position:absolute;
2135 right:5px;
2135 right:5px;
2136 top:5px;
2136 top:5px;
2137 width:16px;
2137 width:16px;
2138 }
2138 }
2139
2139
2140 div#legend_container table,div#legend_choices table {
2140 div#legend_container table,div#legend_choices table {
2141 width:auto !important;
2141 width:auto !important;
2142 }
2142 }
2143
2143
2144 table#permissions_manage {
2144 table#permissions_manage {
2145 width:0 !important;
2145 width:0 !important;
2146 }
2146 }
2147
2147
2148 table#permissions_manage span.private_repo_msg {
2148 table#permissions_manage span.private_repo_msg {
2149 font-size:0.8em;
2149 font-size:0.8em;
2150 opacity:0.6px;
2150 opacity:0.6px;
2151 }
2151 }
2152
2152
2153 table#permissions_manage td.private_repo_msg {
2153 table#permissions_manage td.private_repo_msg {
2154 font-size:0.8em;
2154 font-size:0.8em;
2155 }
2155 }
2156
2156
2157 table#permissions_manage tr#add_perm_input td {
2157 table#permissions_manage tr#add_perm_input td {
2158 vertical-align:middle;
2158 vertical-align:middle;
2159 }
2159 }
2160
2160
2161 div.gravatar {
2161 div.gravatar {
2162 background-color:#FFF;
2162 background-color:#FFF;
2163 border:1px solid #D0D0D0;
2163 border:1px solid #D0D0D0;
2164 float:left;
2164 float:left;
2165 margin-right:0.7em;
2165 margin-right:0.7em;
2166 padding:2px 2px 0;
2166 padding:2px 2px 0;
2167 }
2167 }
2168
2168
2169 #header,#content,#footer {
2169 #header,#content,#footer {
2170 min-width:978px;
2170 min-width:978px;
2171 }
2171 }
2172
2172
2173 #content {
2173 #content {
2174 min-height:100%;
2174 min-height:100%;
2175 clear:both;
2175 clear:both;
2176 overflow:hidden;
2176 overflow:hidden;
2177 padding:14px 10px;
2177 padding:14px 10px;
2178 }
2178 }
2179
2179
2180 #content div.box div.title div.search {
2180 #content div.box div.title div.search {
2181 background:url("../images/title_link.png") no-repeat top left;
2181 background:url("../images/title_link.png") no-repeat top left;
2182 border-left:1px solid #316293;
2182 border-left:1px solid #316293;
2183 }
2183 }
2184
2184
2185 #content div.box div.title div.search div.input input {
2185 #content div.box div.title div.search div.input input {
2186 border:1px solid #316293;
2186 border:1px solid #316293;
2187 }
2187 }
2188
2188
2189 #content div.box div.title div.search div.button input.ui-button {
2189 #content div.box div.title div.search div.button input.ui-button {
2190 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2190 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2191 border:1px solid #316293;
2191 border:1px solid #316293;
2192 border-left:none;
2192 border-left:none;
2193 color:#FFF;
2193 color:#FFF;
2194 }
2194 }
2195
2195
2196 #content div.box input.ui-button-small {
2196 #content div.box input.ui-button-small {
2197 background:#e5e3e3 url("../images/button.png") repeat-x;
2197 background:#e5e3e3 url("../images/button.png") repeat-x;
2198 border-top:1px solid #DDD;
2198 border-top:1px solid #DDD;
2199 border-left:1px solid #c6c6c6;
2199 border-left:1px solid #c6c6c6;
2200 border-right:1px solid #DDD;
2200 border-right:1px solid #DDD;
2201 border-bottom:1px solid #c6c6c6;
2201 border-bottom:1px solid #c6c6c6;
2202 color:#515151;
2202 color:#515151;
2203 outline:none;
2203 outline:none;
2204 margin:0;
2204 margin:0;
2205 }
2205 }
2206
2206
2207 #content div.box input.ui-button-small-blue {
2208 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2209 border-top:1px solid #5c91a4;
2210 border-left:1px solid #2a6f89;
2211 border-right:1px solid #2b7089;
2212 border-bottom:1px solid #1a6480;
2213 color:#fff;
2214 }
2215
2207 #content div.box input.ui-button-small submit,button{
2216 #content div.box input.ui-button-small submit,button{
2208 cursor: pointer;
2217 cursor: pointer;
2209 }
2218 }
2210
2219
2211 #content div.box div.title div.search div.button input.ui-state-hover {
2220 #content div.box div.title div.search div.button input.ui-state-hover {
2212 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2221 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2213 border:1px solid #316293;
2222 border:1px solid #316293;
2214 border-left:none;
2223 border-left:none;
2215 color:#FFF;
2224 color:#FFF;
2216 }
2225 }
2217
2226
2218 #content div.box div.form div.fields div.field div.highlight .ui-button {
2227 #content div.box div.form div.fields div.field div.highlight .ui-button {
2219 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2228 background:#4e85bb url("../images/button_highlight.png") repeat-x;
2220 border-top:1px solid #5c91a4;
2229 border-top:1px solid #5c91a4;
2221 border-left:1px solid #2a6f89;
2230 border-left:1px solid #2a6f89;
2222 border-right:1px solid #2b7089;
2231 border-right:1px solid #2b7089;
2223 border-bottom:1px solid #1a6480;
2232 border-bottom:1px solid #1a6480;
2224 color:#fff;
2233 color:#fff;
2225 }
2234 }
2226
2235
2227 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
2236 #content div.box div.form div.fields div.field div.highlight .ui-state-hover {
2228 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2237 background:#46a0c1 url("../images/button_highlight_selected.png") repeat-x;
2229 border-top:1px solid #78acbf;
2238 border-top:1px solid #78acbf;
2230 border-left:1px solid #34819e;
2239 border-left:1px solid #34819e;
2231 border-right:1px solid #35829f;
2240 border-right:1px solid #35829f;
2232 border-bottom:1px solid #257897;
2241 border-bottom:1px solid #257897;
2233 color:#fff;
2242 color:#fff;
2234 }
2243 }
2235
2244
2236 ins,div.options a:hover {
2245 ins,div.options a:hover {
2237 text-decoration:none;
2246 text-decoration:none;
2238 }
2247 }
2239
2248
2240 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2249 img,#header #header-inner #quick li a:hover span.normal,#header #header-inner #quick li ul li.last,#content div.box div.form div.fields div.field div.textarea table td table td a,#clone_url {
2241 border:none;
2250 border:none;
2242 }
2251 }
2243
2252
2244 img.icon,.right .merge img {
2253 img.icon,.right .merge img {
2245 vertical-align:bottom;
2254 vertical-align:bottom;
2246 }
2255 }
2247
2256
2248 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2257 #header ul#logged-user,#content div.box div.title ul.links,#content div.box div.message div.dismiss,#content div.box div.traffic div.legend ul {
2249 float:right;
2258 float:right;
2250 margin:0;
2259 margin:0;
2251 padding:0;
2260 padding:0;
2252 }
2261 }
2253
2262
2254 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2263 #header #header-inner #home,#header #header-inner #logo,#content div.box ul.left,#content div.box ol.left,#content div.box div.pagination-left,div#commit_history,div#legend_data,div#legend_container,div#legend_choices {
2255 float:left;
2264 float:left;
2256 }
2265 }
2257
2266
2258 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2267 #header #header-inner #quick li:hover ul ul,#header #header-inner #quick li:hover ul ul ul,#header #header-inner #quick li:hover ul ul ul ul,#content #left #menu ul.closed,#content #left #menu li ul.collapsed,.yui-tt-shadow {
2259 display:none;
2268 display:none;
2260 }
2269 }
2261
2270
2262 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded {
2271 #header #header-inner #quick li:hover ul,#header #header-inner #quick li li:hover ul,#header #header-inner #quick li li li:hover ul,#header #header-inner #quick li li li li:hover ul,#content #left #menu ul.opened,#content #left #menu li ul.expanded {
2263 display:block;
2272 display:block;
2264 }
2273 }
2265
2274
2266 #content div.graph{
2275 #content div.graph{
2267 padding:0 10px 10px;
2276 padding:0 10px 10px;
2268 }
2277 }
2269
2278
2270 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2279 #content div.box div.title ul.links li a:hover,#content div.box div.title ul.links li.ui-tabs-selected a {
2271 color:#bfe3ff;
2280 color:#bfe3ff;
2272 }
2281 }
2273
2282
2274 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal {
2283 #content div.box ol.lower-roman,#content div.box ol.upper-roman,#content div.box ol.lower-alpha,#content div.box ol.upper-alpha,#content div.box ol.decimal {
2275 margin:10px 24px 10px 44px;
2284 margin:10px 24px 10px 44px;
2276 }
2285 }
2277
2286
2278 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2287 #content div.box div.form,#content div.box div.table,#content div.box div.traffic {
2279 clear:both;
2288 clear:both;
2280 overflow:hidden;
2289 overflow:hidden;
2281 margin:0;
2290 margin:0;
2282 padding:0 20px 10px;
2291 padding:0 20px 10px;
2283 }
2292 }
2284
2293
2285 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2294 #content div.box div.form div.fields,#login div.form,#login div.form div.fields,#register div.form,#register div.form div.fields {
2286 clear:both;
2295 clear:both;
2287 overflow:hidden;
2296 overflow:hidden;
2288 margin:0;
2297 margin:0;
2289 padding:0;
2298 padding:0;
2290 }
2299 }
2291
2300
2292 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span {
2301 #content div.box div.form div.fields div.field div.label span,#login div.form div.fields div.field div.label span,#register div.form div.fields div.field div.label span {
2293 height:1%;
2302 height:1%;
2294 display:block;
2303 display:block;
2295 color:#363636;
2304 color:#363636;
2296 margin:0;
2305 margin:0;
2297 padding:2px 0 0;
2306 padding:2px 0 0;
2298 }
2307 }
2299
2308
2300 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error {
2309 #content div.box div.form div.fields div.field div.input input.error,#login div.form div.fields div.field div.input input.error,#register div.form div.fields div.field div.input input.error {
2301 background:#FBE3E4;
2310 background:#FBE3E4;
2302 border-top:1px solid #e1b2b3;
2311 border-top:1px solid #e1b2b3;
2303 border-left:1px solid #e1b2b3;
2312 border-left:1px solid #e1b2b3;
2304 border-right:1px solid #FBC2C4;
2313 border-right:1px solid #FBC2C4;
2305 border-bottom:1px solid #FBC2C4;
2314 border-bottom:1px solid #FBC2C4;
2306 }
2315 }
2307
2316
2308 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success {
2317 #content div.box div.form div.fields div.field div.input input.success,#login div.form div.fields div.field div.input input.success,#register div.form div.fields div.field div.input input.success {
2309 background:#E6EFC2;
2318 background:#E6EFC2;
2310 border-top:1px solid #cebb98;
2319 border-top:1px solid #cebb98;
2311 border-left:1px solid #cebb98;
2320 border-left:1px solid #cebb98;
2312 border-right:1px solid #c6d880;
2321 border-right:1px solid #c6d880;
2313 border-bottom:1px solid #c6d880;
2322 border-bottom:1px solid #c6d880;
2314 }
2323 }
2315
2324
2316 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input {
2325 #content div.box-left div.form div.fields div.field div.textarea,#content div.box-right div.form div.fields div.field div.textarea,#content div.box div.form div.fields div.field div.select select,#content div.box table th.selected input,#content div.box table td.selected input {
2317 margin:0;
2326 margin:0;
2318 }
2327 }
2319
2328
2320 #content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios{
2329 #content div.box-left div.form div.fields div.field div.select,#content div.box-left div.form div.fields div.field div.checkboxes,#content div.box-left div.form div.fields div.field div.radios,#content div.box-right div.form div.fields div.field div.select,#content div.box-right div.form div.fields div.field div.checkboxes,#content div.box-right div.form div.fields div.field div.radios{
2321 margin:0 0 0 0px !important;
2330 margin:0 0 0 0px !important;
2322 padding:0;
2331 padding:0;
2323 }
2332 }
2324
2333
2325 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios {
2334 #content div.box div.form div.fields div.field div.select,#content div.box div.form div.fields div.field div.checkboxes,#content div.box div.form div.fields div.field div.radios {
2326 margin:0 0 0 200px;
2335 margin:0 0 0 200px;
2327 padding:0;
2336 padding:0;
2328 }
2337 }
2329
2338
2330
2339
2331 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover {
2340 #content div.box div.form div.fields div.field div.select a:hover,#content div.box div.form div.fields div.field div.select a.ui-selectmenu:hover,#content div.box div.action a:hover {
2332 color:#000;
2341 color:#000;
2333 text-decoration:none;
2342 text-decoration:none;
2334 }
2343 }
2335
2344
2336 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2345 #content div.box div.form div.fields div.field div.select a.ui-selectmenu-focus,#content div.box div.action a.ui-selectmenu-focus {
2337 border:1px solid #666;
2346 border:1px solid #666;
2338 }
2347 }
2339
2348
2340 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio {
2349 #content div.box div.form div.fields div.field div.checkboxes div.checkbox,#content div.box div.form div.fields div.field div.radios div.radio {
2341 clear:both;
2350 clear:both;
2342 overflow:hidden;
2351 overflow:hidden;
2343 margin:0;
2352 margin:0;
2344 padding:8px 0 2px;
2353 padding:8px 0 2px;
2345 }
2354 }
2346
2355
2347 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input {
2356 #content div.box div.form div.fields div.field div.checkboxes div.checkbox input,#content div.box div.form div.fields div.field div.radios div.radio input {
2348 float:left;
2357 float:left;
2349 margin:0;
2358 margin:0;
2350 }
2359 }
2351
2360
2352 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label {
2361 #content div.box div.form div.fields div.field div.checkboxes div.checkbox label,#content div.box div.form div.fields div.field div.radios div.radio label {
2353 height:1%;
2362 height:1%;
2354 display:block;
2363 display:block;
2355 float:left;
2364 float:left;
2356 margin:2px 0 0 4px;
2365 margin:2px 0 0 4px;
2357 }
2366 }
2358
2367
2359 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2368 div.form div.fields div.field div.button input,#content div.box div.form div.fields div.buttons input,div.form div.fields div.buttons input,#content div.box div.action div.button input {
2360 color:#000;
2369 color:#000;
2361 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2370 font-family:Lucida Grande, Verdana, Lucida Sans Regular, Lucida Sans Unicode, Arial, sans-serif;
2362 font-size:11px;
2371 font-size:11px;
2363 font-weight:700;
2372 font-weight:700;
2364 margin:0;
2373 margin:0;
2365 }
2374 }
2366
2375
2367 div.form div.fields div.field div.button .ui-button,#content div.box div.form div.fields div.buttons input.ui-button {
2376 div.form div.fields div.field div.button .ui-button,#content div.box div.form div.fields div.buttons input.ui-button {
2368 background:#e5e3e3 url("../images/button.png") repeat-x;
2377 background:#e5e3e3 url("../images/button.png") repeat-x;
2369 border-top:1px solid #DDD;
2378 border-top:1px solid #DDD;
2370 border-left:1px solid #c6c6c6;
2379 border-left:1px solid #c6c6c6;
2371 border-right:1px solid #DDD;
2380 border-right:1px solid #DDD;
2372 border-bottom:1px solid #c6c6c6;
2381 border-bottom:1px solid #c6c6c6;
2373 color:#515151;
2382 color:#515151;
2374 outline:none;
2383 outline:none;
2375 margin:0;
2384 margin:0;
2376 padding:6px 12px;
2385 padding:6px 12px;
2377 }
2386 }
2378
2387
2379 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2388 div.form div.fields div.field div.button .ui-state-hover,#content div.box div.form div.fields div.buttons input.ui-state-hover {
2380 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2389 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2381 border-top:1px solid #ccc;
2390 border-top:1px solid #ccc;
2382 border-left:1px solid #bebebe;
2391 border-left:1px solid #bebebe;
2383 border-right:1px solid #b1b1b1;
2392 border-right:1px solid #b1b1b1;
2384 border-bottom:1px solid #afafaf;
2393 border-bottom:1px solid #afafaf;
2385 color:#515151;
2394 color:#515151;
2386 outline:none;
2395 outline:none;
2387 margin:0;
2396 margin:0;
2388 padding:6px 12px;
2397 padding:6px 12px;
2389 }
2398 }
2390
2399
2391 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2400 div.form div.fields div.field div.highlight,#content div.box div.form div.fields div.buttons div.highlight {
2392 display:inline;
2401 display:inline;
2393 }
2402 }
2394
2403
2395 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2404 #content div.box div.form div.fields div.buttons,div.form div.fields div.buttons {
2396 margin:10px 0 0 200px;
2405 margin:10px 0 0 200px;
2397 padding:0;
2406 padding:0;
2398 }
2407 }
2399
2408
2400 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons {
2409 #content div.box-left div.form div.fields div.buttons,#content div.box-right div.form div.fields div.buttons,div.box-left div.form div.fields div.buttons,div.box-right div.form div.fields div.buttons {
2401 margin:10px 0 0;
2410 margin:10px 0 0;
2402 }
2411 }
2403
2412
2404 #content div.box table td.user,#content div.box table td.address {
2413 #content div.box table td.user,#content div.box table td.address {
2405 width:10%;
2414 width:10%;
2406 text-align:center;
2415 text-align:center;
2407 }
2416 }
2408
2417
2409 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link {
2418 #content div.box div.action div.button,#login div.form div.fields div.field div.input div.link,#register div.form div.fields div.field div.input div.link {
2410 text-align:right;
2419 text-align:right;
2411 margin:6px 0 0;
2420 margin:6px 0 0;
2412 padding:0;
2421 padding:0;
2413 }
2422 }
2414
2423
2415 #content div.box div.action div.button input.ui-button,#login div.form div.fields div.buttons input.ui-button,#register div.form div.fields div.buttons input.ui-button {
2424 #content div.box div.action div.button input.ui-button,#login div.form div.fields div.buttons input.ui-button,#register div.form div.fields div.buttons input.ui-button {
2416 background:#e5e3e3 url("../images/button.png") repeat-x;
2425 background:#e5e3e3 url("../images/button.png") repeat-x;
2417 border-top:1px solid #DDD;
2426 border-top:1px solid #DDD;
2418 border-left:1px solid #c6c6c6;
2427 border-left:1px solid #c6c6c6;
2419 border-right:1px solid #DDD;
2428 border-right:1px solid #DDD;
2420 border-bottom:1px solid #c6c6c6;
2429 border-bottom:1px solid #c6c6c6;
2421 color:#515151;
2430 color:#515151;
2422 margin:0;
2431 margin:0;
2423 padding:6px 12px;
2432 padding:6px 12px;
2424 }
2433 }
2425
2434
2426 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover {
2435 #content div.box div.action div.button input.ui-state-hover,#login div.form div.fields div.buttons input.ui-state-hover,#register div.form div.fields div.buttons input.ui-state-hover {
2427 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2436 background:#b4b4b4 url("../images/button_selected.png") repeat-x;
2428 border-top:1px solid #ccc;
2437 border-top:1px solid #ccc;
2429 border-left:1px solid #bebebe;
2438 border-left:1px solid #bebebe;
2430 border-right:1px solid #b1b1b1;
2439 border-right:1px solid #b1b1b1;
2431 border-bottom:1px solid #afafaf;
2440 border-bottom:1px solid #afafaf;
2432 color:#515151;
2441 color:#515151;
2433 margin:0;
2442 margin:0;
2434 padding:6px 12px;
2443 padding:6px 12px;
2435 }
2444 }
2436
2445
2437 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2446 #content div.box div.pagination div.results,#content div.box div.pagination-wh div.results {
2438 text-align:left;
2447 text-align:left;
2439 float:left;
2448 float:left;
2440 margin:0;
2449 margin:0;
2441 padding:0;
2450 padding:0;
2442 }
2451 }
2443
2452
2444 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2453 #content div.box div.pagination div.results span,#content div.box div.pagination-wh div.results span {
2445 height:1%;
2454 height:1%;
2446 display:block;
2455 display:block;
2447 float:left;
2456 float:left;
2448 background:#ebebeb url("../images/pager.png") repeat-x;
2457 background:#ebebeb url("../images/pager.png") repeat-x;
2449 border-top:1px solid #dedede;
2458 border-top:1px solid #dedede;
2450 border-left:1px solid #cfcfcf;
2459 border-left:1px solid #cfcfcf;
2451 border-right:1px solid #c4c4c4;
2460 border-right:1px solid #c4c4c4;
2452 border-bottom:1px solid #c4c4c4;
2461 border-bottom:1px solid #c4c4c4;
2453 color:#4A4A4A;
2462 color:#4A4A4A;
2454 font-weight:700;
2463 font-weight:700;
2455 margin:0;
2464 margin:0;
2456 padding:6px 8px;
2465 padding:6px 8px;
2457 }
2466 }
2458
2467
2459 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2468 #content div.box div.pagination ul.pager li.disabled,#content div.box div.pagination-wh a.disabled {
2460 color:#B4B4B4;
2469 color:#B4B4B4;
2461 padding:6px;
2470 padding:6px;
2462 }
2471 }
2463
2472
2464 #login,#register {
2473 #login,#register {
2465 width:520px;
2474 width:520px;
2466 margin:10% auto 0;
2475 margin:10% auto 0;
2467 padding:0;
2476 padding:0;
2468 }
2477 }
2469
2478
2470 #login div.color,#register div.color {
2479 #login div.color,#register div.color {
2471 clear:both;
2480 clear:both;
2472 overflow:hidden;
2481 overflow:hidden;
2473 background:#FFF;
2482 background:#FFF;
2474 margin:10px auto 0;
2483 margin:10px auto 0;
2475 padding:3px 3px 3px 0;
2484 padding:3px 3px 3px 0;
2476 }
2485 }
2477
2486
2478 #login div.color a,#register div.color a {
2487 #login div.color a,#register div.color a {
2479 width:20px;
2488 width:20px;
2480 height:20px;
2489 height:20px;
2481 display:block;
2490 display:block;
2482 float:left;
2491 float:left;
2483 margin:0 0 0 3px;
2492 margin:0 0 0 3px;
2484 padding:0;
2493 padding:0;
2485 }
2494 }
2486
2495
2487 #login div.title h5,#register div.title h5 {
2496 #login div.title h5,#register div.title h5 {
2488 color:#fff;
2497 color:#fff;
2489 margin:10px;
2498 margin:10px;
2490 padding:0;
2499 padding:0;
2491 }
2500 }
2492
2501
2493 #login div.form div.fields div.field,#register div.form div.fields div.field {
2502 #login div.form div.fields div.field,#register div.form div.fields div.field {
2494 clear:both;
2503 clear:both;
2495 overflow:hidden;
2504 overflow:hidden;
2496 margin:0;
2505 margin:0;
2497 padding:0 0 10px;
2506 padding:0 0 10px;
2498 }
2507 }
2499
2508
2500 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2509 #login div.form div.fields div.field span.error-message,#register div.form div.fields div.field span.error-message {
2501 height:1%;
2510 height:1%;
2502 display:block;
2511 display:block;
2503 color:red;
2512 color:red;
2504 margin:8px 0 0;
2513 margin:8px 0 0;
2505 padding:0;
2514 padding:0;
2506 max-width: 320px;
2515 max-width: 320px;
2507 }
2516 }
2508
2517
2509 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2518 #login div.form div.fields div.field div.label label,#register div.form div.fields div.field div.label label {
2510 color:#000;
2519 color:#000;
2511 font-weight:700;
2520 font-weight:700;
2512 }
2521 }
2513
2522
2514 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2523 #login div.form div.fields div.field div.input,#register div.form div.fields div.field div.input {
2515 float:left;
2524 float:left;
2516 margin:0;
2525 margin:0;
2517 padding:0;
2526 padding:0;
2518 }
2527 }
2519
2528
2520 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2529 #login div.form div.fields div.field div.checkbox,#register div.form div.fields div.field div.checkbox {
2521 margin:0 0 0 184px;
2530 margin:0 0 0 184px;
2522 padding:0;
2531 padding:0;
2523 }
2532 }
2524
2533
2525 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2534 #login div.form div.fields div.field div.checkbox label,#register div.form div.fields div.field div.checkbox label {
2526 color:#565656;
2535 color:#565656;
2527 font-weight:700;
2536 font-weight:700;
2528 }
2537 }
2529
2538
2530 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2539 #login div.form div.fields div.buttons input,#register div.form div.fields div.buttons input {
2531 color:#000;
2540 color:#000;
2532 font-size:1em;
2541 font-size:1em;
2533 font-weight:700;
2542 font-weight:700;
2534 font-family:Verdana, Helvetica, Sans-Serif;
2543 font-family:Verdana, Helvetica, Sans-Serif;
2535 margin:0;
2544 margin:0;
2536 }
2545 }
2537
2546
2538 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2547 #changeset_content .container .wrapper,#graph_content .container .wrapper {
2539 width:600px;
2548 width:600px;
2540 }
2549 }
2541
2550
2542 #changeset_content .container .left,#graph_content .container .left {
2551 #changeset_content .container .left,#graph_content .container .left {
2543 float:left;
2552 float:left;
2544 width:70%;
2553 width:70%;
2545 padding-left:5px;
2554 padding-left:5px;
2546 }
2555 }
2547
2556
2548 #changeset_content .container .left .date,.ac .match {
2557 #changeset_content .container .left .date,.ac .match {
2549 font-weight:700;
2558 font-weight:700;
2550 padding-top: 5px;
2559 padding-top: 5px;
2551 padding-bottom:5px;
2560 padding-bottom:5px;
2552 }
2561 }
2553
2562
2554 div#legend_container table td,div#legend_choices table td {
2563 div#legend_container table td,div#legend_choices table td {
2555 border:none !important;
2564 border:none !important;
2556 height:20px !important;
2565 height:20px !important;
2557 padding:0 !important;
2566 padding:0 !important;
2558 }
2567 }
2559
2568
2560 #q_filter{
2569 #q_filter{
2561 border:0 none;
2570 border:0 none;
2562 color:#AAAAAA;
2571 color:#AAAAAA;
2563 margin-bottom:-4px;
2572 margin-bottom:-4px;
2564 margin-top:-4px;
2573 margin-top:-4px;
2565 padding-left:3px;
2574 padding-left:3px;
2566 }
2575 }
2567
2576
@@ -1,355 +1,352 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <!-- HEADER -->
4 <!-- HEADER -->
5 <div id="header">
5 <div id="header">
6 <!-- user -->
6 <!-- user -->
7 <ul id="logged-user">
7 <ul id="logged-user">
8 <li class="first">
8 <li class="first">
9 <div class="gravatar">
9 <div class="gravatar">
10 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
10 <img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,20)}" />
11 </div>
11 </div>
12 <div class="account">
12 <div class="account">
13 %if c.rhodecode_user.username == 'default':
13 %if c.rhodecode_user.username == 'default':
14 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
14 <a href="${h.url('public_journal')}">${_('Public journal')}</a>
15 %else:
15 %else:
16 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
16 ${h.link_to(c.rhodecode_user.username,h.url('admin_settings_my_account'),title='%s %s'%(c.rhodecode_user.name,c.rhodecode_user.lastname))}
17 %endif
17 %endif
18 </div>
18 </div>
19 </li>
19 </li>
20 <li>
20 <li>
21 <a href="${h.url('home')}">${_('Home')}</a>
21 <a href="${h.url('home')}">${_('Home')}</a>
22 </li>
22 </li>
23 %if c.rhodecode_user.username != 'default':
23 %if c.rhodecode_user.username != 'default':
24 <li>
24 <li>
25 <a href="${h.url('journal')}">${_('Journal')}</a>
25 <a href="${h.url('journal')}">${_('Journal')}</a>
26 ##(${c.unread_journal}
26 ##(${c.unread_journal}
27 </li>
27 </li>
28 %endif
28 %endif
29 %if c.rhodecode_user.username == 'default':
29 %if c.rhodecode_user.username == 'default':
30 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
30 <li class="last highlight">${h.link_to(u'Login',h.url('login_home'))}</li>
31 %else:
31 %else:
32 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
32 <li class="last highlight">${h.link_to(u'Log Out',h.url('logout_home'))}</li>
33 %endif
33 %endif
34 </ul>
34 </ul>
35 <!-- end user -->
35 <!-- end user -->
36 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
36 <div id="header-inner" class="title top-left-rounded-corner top-right-rounded-corner">
37 <div id="logo">
37 <div id="logo">
38 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
38 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
39 </div>
39 </div>
40 <!-- MENU -->
40 <!-- MENU -->
41 ${self.page_nav()}
41 ${self.page_nav()}
42 <!-- END MENU -->
42 <!-- END MENU -->
43 ${self.body()}
43 ${self.body()}
44 </div>
44 </div>
45 </div>
45 </div>
46 <!-- END HEADER -->
46 <!-- END HEADER -->
47
47
48 <!-- CONTENT -->
48 <!-- CONTENT -->
49 <div id="content">
49 <div id="content">
50 <div class="flash_msg">
50 <div class="flash_msg">
51 <% messages = h.flash.pop_messages() %>
51 <% messages = h.flash.pop_messages() %>
52 % if messages:
52 % if messages:
53 <ul id="flash-messages">
53 <ul id="flash-messages">
54 % for message in messages:
54 % for message in messages:
55 <li class="${message.category}_msg">${message}</li>
55 <li class="${message.category}_msg">${message}</li>
56 % endfor
56 % endfor
57 </ul>
57 </ul>
58 % endif
58 % endif
59 </div>
59 </div>
60 <div id="main">
60 <div id="main">
61 ${next.main()}
61 ${next.main()}
62 </div>
62 </div>
63 </div>
63 </div>
64 <!-- END CONTENT -->
64 <!-- END CONTENT -->
65
65
66 <!-- FOOTER -->
66 <!-- FOOTER -->
67 <div id="footer">
67 <div id="footer">
68 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
68 <div id="footer-inner" class="title bottom-left-rounded-corner bottom-right-rounded-corner">
69 <div>
69 <div>
70 <p class="footer-link">
70 <p class="footer-link">
71 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
71 <a href="${h.url('bugtracker')}">${_('Submit a bug')}</a>
72 </p>
72 </p>
73 <p class="footer-link-right">
73 <p class="footer-link-right">
74 <a href="${h.url('rhodecode_official')}">RhodeCode</a>
74 <a href="${h.url('rhodecode_official')}">RhodeCode</a>
75 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
75 ${c.rhodecode_version} &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski
76 </p>
76 </p>
77 </div>
77 </div>
78 </div>
78 </div>
79 <script type="text/javascript">
79 <script type="text/javascript">
80 function tooltip_activate(){
80 function tooltip_activate(){
81 ${h.tooltip.activate()}
81 ${h.tooltip.activate()}
82 }
82 }
83 tooltip_activate();
83 tooltip_activate();
84 </script>
84 </script>
85 </div>
85 </div>
86 <!-- END FOOTER -->
86 <!-- END FOOTER -->
87
87
88 ### MAKO DEFS ###
88 ### MAKO DEFS ###
89 <%def name="page_nav()">
89 <%def name="page_nav()">
90 ${self.menu()}
90 ${self.menu()}
91 </%def>
91 </%def>
92
92
93 <%def name="breadcrumbs()">
93 <%def name="breadcrumbs()">
94 <div class="breadcrumbs">
94 <div class="breadcrumbs">
95 ${self.breadcrumbs_links()}
95 ${self.breadcrumbs_links()}
96 </div>
96 </div>
97 </%def>
97 </%def>
98
98
99
99
100 <%def name="menu(current=None)">
100 <%def name="menu(current=None)">
101 <%
101 <%
102 def is_current(selected):
102 def is_current(selected):
103 if selected == current:
103 if selected == current:
104 return h.literal('class="current"')
104 return h.literal('class="current"')
105 %>
105 %>
106 %if current not in ['home','admin']:
106 %if current not in ['home','admin']:
107 ##REGULAR MENU
107 ##REGULAR MENU
108 <ul id="quick">
108 <ul id="quick">
109 <!-- repo switcher -->
109 <!-- repo switcher -->
110 <li>
110 <li>
111 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
111 <a id="repo_switcher" title="${_('Switch repository')}" href="#">
112 <span class="icon">
112 <span class="icon">
113 <img src="${h.url("/images/icons/database.png")}" alt="${_('Products')}" />
113 <img src="${h.url("/images/icons/database.png")}" alt="${_('Products')}" />
114 </span>
114 </span>
115 <span>&darr;</span>
115 <span>&darr;</span>
116 </a>
116 </a>
117 <ul id="repo_switcher_list" class="repo_switcher">
117 <ul id="repo_switcher_list" class="repo_switcher">
118 <li>
118 <li>
119 <a href="#">${_('loading...')}</a>
119 <a href="#">${_('loading...')}</a>
120 </li>
120 </li>
121 </ul>
121 </ul>
122 <script type="text/javascript">
122 <script type="text/javascript">
123 YUE.on('repo_switcher','mouseover',function(){
123 YUE.on('repo_switcher','mouseover',function(){
124 function qfilter(){
124 function qfilter(){
125 var S = YAHOO.util.Selector;
125 var S = YAHOO.util.Selector;
126
126
127 var q_filter = YUD.get('q_filter_rs');
127 var q_filter = YUD.get('q_filter_rs');
128 var F = YAHOO.namespace('q_filter_rs');
128 var F = YAHOO.namespace('q_filter_rs');
129
129
130 YUE.on(q_filter,'click',function(){
130 YUE.on(q_filter,'click',function(){
131 q_filter.value = '';
131 q_filter.value = '';
132 });
132 });
133
133
134 F.filterTimeout = null;
134 F.filterTimeout = null;
135
135
136 F.updateFilter = function() {
136 F.updateFilter = function() {
137 // Reset timeout
137 // Reset timeout
138 F.filterTimeout = null;
138 F.filterTimeout = null;
139
139
140 var obsolete = [];
140 var obsolete = [];
141 var nodes = S.query('ul#repo_switcher_list li a.repo_name');
141 var nodes = S.query('ul#repo_switcher_list li a.repo_name');
142 var req = YUD.get('q_filter_rs').value;
142 var req = YUD.get('q_filter_rs').value;
143 for (n in nodes){
143 for (n in nodes){
144 YUD.setStyle(nodes[n].parentNode,'display','')
144 YUD.setStyle(nodes[n].parentNode,'display','')
145 }
145 }
146 if (req){
146 if (req){
147 for (n in nodes){
147 for (n in nodes){
148 console.log(n);
148 console.log(n);
149 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
149 if (nodes[n].innerHTML.toLowerCase().indexOf(req) == -1) {
150 obsolete.push(nodes[n]);
150 obsolete.push(nodes[n]);
151 }
151 }
152 }
152 }
153 if(obsolete){
153 if(obsolete){
154 for (n in obsolete){
154 for (n in obsolete){
155 YUD.setStyle(obsolete[n].parentNode,'display','none');
155 YUD.setStyle(obsolete[n].parentNode,'display','none');
156 }
156 }
157 }
157 }
158 }
158 }
159 }
159 }
160
160
161 YUE.on(q_filter,'keyup',function(e){
161 YUE.on(q_filter,'keyup',function(e){
162 clearTimeout(F.filterTimeout);
162 clearTimeout(F.filterTimeout);
163 setTimeout(F.updateFilter,600);
163 setTimeout(F.updateFilter,600);
164 });
164 });
165 }
165 }
166 var loaded = YUD.hasClass('repo_switcher','loaded');
166 var loaded = YUD.hasClass('repo_switcher','loaded');
167 if(!loaded){
167 if(!loaded){
168 YUD.addClass('repo_switcher','loaded');
168 YUD.addClass('repo_switcher','loaded');
169 YAHOO.util.Connect.asyncRequest('GET',"${h.url('repo_switcher')}",{
169 YAHOO.util.Connect.asyncRequest('GET',"${h.url('repo_switcher')}",{
170 success:function(o){
170 success:function(o){
171 YUD.get('repo_switcher_list').innerHTML = o.responseText;
171 YUD.get('repo_switcher_list').innerHTML = o.responseText;
172 qfilter();
172 qfilter();
173 },
173 },
174 failure:function(o){
174 failure:function(o){
175 YUD.removeClass('repo_switcher','loaded');
175 YUD.removeClass('repo_switcher','loaded');
176 }
176 }
177 },null);
177 },null);
178 }
178 }
179 return false;
179 return false;
180 });
180 });
181 </script>
181 </script>
182 </li>
182 </li>
183
183
184 <li ${is_current('summary')}>
184 <li ${is_current('summary')}>
185 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
185 <a title="${_('Summary')}" href="${h.url('summary_home',repo_name=c.repo_name)}">
186 <span class="icon">
186 <span class="icon">
187 <img src="${h.url("/images/icons/clipboard_16.png")}" alt="${_('Summary')}" />
187 <img src="${h.url("/images/icons/clipboard_16.png")}" alt="${_('Summary')}" />
188 </span>
188 </span>
189 <span>${_('Summary')}</span>
189 <span>${_('Summary')}</span>
190 </a>
190 </a>
191 </li>
191 </li>
192 ##<li ${is_current('shortlog')}>
192 ##<li ${is_current('shortlog')}>
193 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
193 ## <a title="${_('Shortlog')}" href="${h.url('shortlog_home',repo_name=c.repo_name)}">
194 ## <span class="icon">
194 ## <span class="icon">
195 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
195 ## <img src="${h.url("/images/icons/application_view_list.png")}" alt="${_('Shortlog')}" />
196 ## </span>
196 ## </span>
197 ## <span>${_('Shortlog')}</span>
197 ## <span>${_('Shortlog')}</span>
198 ## </a>
198 ## </a>
199 ##</li>
199 ##</li>
200 <li ${is_current('changelog')}>
200 <li ${is_current('changelog')}>
201 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
201 <a title="${_('Changelog')}" href="${h.url('changelog_home',repo_name=c.repo_name)}">
202 <span class="icon">
202 <span class="icon">
203 <img src="${h.url("/images/icons/time.png")}" alt="${_('Changelog')}" />
203 <img src="${h.url("/images/icons/time.png")}" alt="${_('Changelog')}" />
204 </span>
204 </span>
205 <span>${_('Changelog')}</span>
205 <span>${_('Changelog')}</span>
206 </a>
206 </a>
207 </li>
207 </li>
208
208
209 <li ${is_current('switch_to')}>
209 <li ${is_current('switch_to')}>
210 <a title="${_('Switch to')}" href="#">
210 <a title="${_('Switch to')}" href="#">
211 <span class="icon">
211 <span class="icon">
212 <img src="${h.url("/images/icons/arrow_switch.png")}" alt="${_('Switch to')}" />
212 <img src="${h.url("/images/icons/arrow_switch.png")}" alt="${_('Switch to')}" />
213 </span>
213 </span>
214 <span>${_('Switch to')}</span>
214 <span>${_('Switch to')}</span>
215 </a>
215 </a>
216 <ul>
216 <ul>
217 <li>
217 <li>
218 ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
218 ${h.link_to('%s (%s)' % (_('branches'),len(c.rhodecode_repo.branches.values()),),h.url('branches_home',repo_name=c.repo_name),class_='branches childs')}
219 <ul>
219 <ul>
220 %if c.rhodecode_repo.branches.values():
220 %if c.rhodecode_repo.branches.values():
221 %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
221 %for cnt,branch in enumerate(c.rhodecode_repo.branches.items()):
222 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
222 <li>${h.link_to('%s - %s' % (branch[0],h.short_id(branch[1])),h.url('files_home',repo_name=c.repo_name,revision=branch[1]))}</li>
223 %endfor
223 %endfor
224 %else:
224 %else:
225 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
225 <li>${h.link_to(_('There are no branches yet'),'#')}</li>
226 %endif
226 %endif
227 </ul>
227 </ul>
228 </li>
228 </li>
229 <li>
229 <li>
230 ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
230 ${h.link_to('%s (%s)' % (_('tags'),len(c.rhodecode_repo.tags.values()),),h.url('tags_home',repo_name=c.repo_name),class_='tags childs')}
231 <ul>
231 <ul>
232 %if c.rhodecode_repo.tags.values():
232 %if c.rhodecode_repo.tags.values():
233 %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
233 %for cnt,tag in enumerate(c.rhodecode_repo.tags.items()):
234 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
234 <li>${h.link_to('%s - %s' % (tag[0],h.short_id(tag[1])),h.url('files_home',repo_name=c.repo_name,revision=tag[1]))}</li>
235 %endfor
235 %endfor
236 %else:
236 %else:
237 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
237 <li>${h.link_to(_('There are no tags yet'),'#')}</li>
238 %endif
238 %endif
239 </ul>
239 </ul>
240 </li>
240 </li>
241 </ul>
241 </ul>
242 </li>
242 </li>
243 <li ${is_current('files')}>
243 <li ${is_current('files')}>
244 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
244 <a title="${_('Files')}" href="${h.url('files_home',repo_name=c.repo_name)}">
245 <span class="icon">
245 <span class="icon">
246 <img src="${h.url("/images/icons/file.png")}" alt="${_('Files')}" />
246 <img src="${h.url("/images/icons/file.png")}" alt="${_('Files')}" />
247 </span>
247 </span>
248 <span>${_('Files')}</span>
248 <span>${_('Files')}</span>
249 </a>
249 </a>
250 </li>
250 </li>
251
251
252 <li ${is_current('options')}>
252 <li ${is_current('options')}>
253 <a title="${_('Options')}" href="#">
253 <a title="${_('Options')}" href="#">
254 <span class="icon">
254 <span class="icon">
255 <img src="${h.url("/images/icons/table_gear.png")}" alt="${_('Admin')}" />
255 <img src="${h.url("/images/icons/table_gear.png")}" alt="${_('Admin')}" />
256 </span>
256 </span>
257 <span>${_('Options')}</span>
257 <span>${_('Options')}</span>
258 </a>
258 </a>
259 <ul>
259 <ul>
260 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
260 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
261 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
261 %if h.HasPermissionAll('hg.admin')('access settings on repository'):
262 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
262 <li>${h.link_to(_('settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
263 %else:
263 %else:
264 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
264 <li>${h.link_to(_('settings'),h.url('repo_settings_home',repo_name=c.repo_name),class_='settings')}</li>
265 %endif
265 %endif
266 %endif
266 %endif
267 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
267 <li>${h.link_to(_('fork'),h.url('repo_fork_home',repo_name=c.repo_name),class_='fork')}</li>
268 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
268 <li>${h.link_to(_('search'),h.url('search_repo',search_repo=c.repo_name),class_='search')}</li>
269
269
270 %if h.HasPermissionAll('hg.admin')('access admin main page'):
270 % if h.HasPermissionAll('hg.admin')('access admin main page'):
271 <li>
271 <li>
272 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
272 ${h.link_to(_('admin'),h.url('admin_home'),class_='admin')}
273 <%def name="admin_menu()">
273 <%def name="admin_menu()">
274 <ul>
274 <ul>
275 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
275 <li>${h.link_to(_('journal'),h.url('admin_home'),class_='journal')}</li>
276 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
276 <li>${h.link_to(_('repositories'),h.url('repos'),class_='repos')}</li>
277 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
277 <li>${h.link_to(_('users'),h.url('users'),class_='users')}</li>
278 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
278 <li>${h.link_to(_('users groups'),h.url('users_groups'),class_='groups')}</li>
279 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
279 <li>${h.link_to(_('permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
280 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
280 <li>${h.link_to(_('ldap'),h.url('ldap_home'),class_='ldap')}</li>
281 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
281 <li class="last">${h.link_to(_('settings'),h.url('admin_settings'),class_='settings')}</li>
282 </ul>
282 </ul>
283 </%def>
283 </%def>
284
284
285 ${admin_menu()}
285 ${admin_menu()}
286 </li>
286 </li>
287 %endif
287 % endif
288
289 </ul>
288 </ul>
290 </li>
289 </li>
291
290
292 <li>
291 <li>
293 <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
292 <a title="${_('Followers')}" href="${h.url('repo_followers_home',repo_name=c.repo_name)}">
294 <span class="icon_short">
293 <span class="icon_short">
295 <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
294 <img src="${h.url("/images/icons/heart.png")}" alt="${_('Followers')}" />
296 </span>
295 </span>
297 <span id="current_followers_count" class="short">${c.repository_followers}</span>
296 <span id="current_followers_count" class="short">${c.repository_followers}</span>
298 </a>
297 </a>
299 </li>
298 </li>
300 <li>
299 <li>
301 <a title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
300 <a title="${_('Forks')}" href="${h.url('repo_forks_home',repo_name=c.repo_name)}">
302 <span class="icon_short">
301 <span class="icon_short">
303 <img src="${h.url("/images/icons/arrow_divide.png")}" alt="${_('Forks')}" />
302 <img src="${h.url("/images/icons/arrow_divide.png")}" alt="${_('Forks')}" />
304 </span>
303 </span>
305 <span class="short">${c.repository_forks}</span>
304 <span class="short">${c.repository_forks}</span>
306 </a>
305 </a>
307 </li>
306 </li>
308
307
309
310
311 </ul>
308 </ul>
312 %else:
309 %else:
313 ##ROOT MENU
310 ##ROOT MENU
314 <ul id="quick">
311 <ul id="quick">
315 <li>
312 <li>
316 <a title="${_('Home')}" href="${h.url('home')}">
313 <a title="${_('Home')}" href="${h.url('home')}">
317 <span class="icon">
314 <span class="icon">
318 <img src="${h.url("/images/icons/home_16.png")}" alt="${_('Home')}" />
315 <img src="${h.url("/images/icons/home_16.png")}" alt="${_('Home')}" />
319 </span>
316 </span>
320 <span>${_('Home')}</span>
317 <span>${_('Home')}</span>
321 </a>
318 </a>
322 </li>
319 </li>
323 %if c.rhodecode_user.username != 'default':
320 % if c.rhodecode_user.username != 'default':
324 <li>
321 <li>
325 <a title="${_('Journal')}" href="${h.url('journal')}">
322 <a title="${_('Journal')}" href="${h.url('journal')}">
326 <span class="icon">
323 <span class="icon">
327 <img src="${h.url("/images/icons/book.png")}" alt="${_('Journal')}" />
324 <img src="${h.url("/images/icons/book.png")}" alt="${_('Journal')}" />
328 </span>
325 </span>
329 <span>${_('Journal')}</span>
326 <span>${_('Journal')}</span>
330 </a>
327 </a>
331 </li>
328 </li>
332 %endif
329 % endif
333 <li>
330 <li>
334 <a title="${_('Search')}" href="${h.url('search')}">
331 <a title="${_('Search')}" href="${h.url('search')}">
335 <span class="icon">
332 <span class="icon">
336 <img src="${h.url("/images/icons/search_16.png")}" alt="${_('Search')}" />
333 <img src="${h.url("/images/icons/search_16.png")}" alt="${_('Search')}" />
337 </span>
334 </span>
338 <span>${_('Search')}</span>
335 <span>${_('Search')}</span>
339 </a>
336 </a>
340 </li>
337 </li>
341
338
342 %if h.HasPermissionAll('hg.admin')('access admin main page'):
339 %if h.HasPermissionAll('hg.admin')('access admin main page'):
343 <li ${is_current('admin')}>
340 <li ${is_current('admin')}>
344 <a title="${_('Admin')}" href="${h.url('admin_home')}">
341 <a title="${_('Admin')}" href="${h.url('admin_home')}">
345 <span class="icon">
342 <span class="icon">
346 <img src="${h.url("/images/icons/cog_edit.png")}" alt="${_('Admin')}" />
343 <img src="${h.url("/images/icons/cog_edit.png")}" alt="${_('Admin')}" />
347 </span>
344 </span>
348 <span>${_('Admin')}</span>
345 <span>${_('Admin')}</span>
349 </a>
346 </a>
350 ${admin_menu()}
347 ${admin_menu()}
351 </li>
348 </li>
352 %endif
349 %endif
353 </ul>
350 </ul>
354 %endif
351 %endif
355 </%def> No newline at end of file
352 </%def>
@@ -1,126 +1,130 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml">
3 <html xmlns="http://www.w3.org/1999/xhtml">
4 <head>
4 <head>
5 <title>${self.title()}</title>
5 <title>${self.title()}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <meta name="robots" content="index, nofollow"/>
7 <meta name="robots" content="index, nofollow"/>
8 <link rel="icon" href="${h.url("/images/icons/database_gear.png")}" type="image/png" />
8 <link rel="icon" href="${h.url("/images/icons/database_gear.png")}" type="image/png" />
9
9
10 <!-- stylesheets -->
10 <!-- stylesheets -->
11 ${self.css()}
11 ${self.css()}
12
12
13 %if c.ga_code:
13 %if c.ga_code:
14 <!-- Analytics -->
14 <!-- Analytics -->
15 <script type="text/javascript">
15 <script type="text/javascript">
16 var _gaq = _gaq || [];
16 var _gaq = _gaq || [];
17 _gaq.push(['_setAccount', '${c.ga_code}']);
17 _gaq.push(['_setAccount', '${c.ga_code}']);
18 _gaq.push(['_trackPageview']);
18 _gaq.push(['_trackPageview']);
19
19
20 (function() {
20 (function() {
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
21 var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
22 ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
23 var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
24 })();
24 })();
25 </script>
25 </script>
26 %endif
26 %endif
27
27
28 <!-- scripts -->
28 <!-- scripts -->
29 ${self.js()}
29 ${self.js()}
30
30
31 </head>
31 </head>
32
32
33 <body id="body">
33 <body id="body">
34 ${next.body()}
34 ${next.body()}
35 </body>
35 </body>
36
36
37 </html>
37 </html>
38
38
39 <%def name="css()">
39 <%def name="css()">
40 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen" />
40 <link rel="stylesheet" type="text/css" href="${h.url('/css/style.css')}" media="screen"/>
41 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css')}" />
41 <link rel="stylesheet" type="text/css" href="${h.url('/css/pygments.css')}"/>
42 <link rel="stylesheet" type="text/css" href="${h.url('/css/diff.css')}" />
42 <link rel="stylesheet" type="text/css" href="${h.url('/css/diff.css')}"/>
43 ${self.css_extra()}
43 </%def>
44 </%def>
44
45 <%def name="css_extra()">
46 </%def>
45 <%def name="js()">
47 <%def name="js()">
46 <script type="text/javascript">
48 <script type="text/javascript">
47 if (typeof console == "undefined" || typeof console.log == "undefined")
49 if (typeof console == "undefined" || typeof console.log == "undefined")
48 console = { log: function() {} }
50 console = { log: function() {} }
49 </script>
51 </script>
50
52
51 % if False:
53 % if False:
52 <script type="text/javascript" src="${h.url('/js/yui/utilities/utilities.js')}"></script>
54 <script type="text/javascript" src="${h.url('/js/yui/utilities/utilities.js')}"></script>
53 <script type="text/javascript" src="${h.url('/js/yui/container/container.js')}"></script>
55 <script type="text/javascript" src="${h.url('/js/yui/container/container.js')}"></script>
54 <script type="text/javascript" src="${h.url('/js/yui/datasource/datasource.js')}"></script>
56 <script type="text/javascript" src="${h.url('/js/yui/datasource/datasource.js')}"></script>
55 <script type="text/javascript" src="${h.url('/js/yui/autocomplete/autocomplete.js')}"></script>
57 <script type="text/javascript" src="${h.url('/js/yui/autocomplete/autocomplete.js')}"></script>
56 <script type="text/javascript" src="${h.url('/js/yui/selector/selector-min.js')}"></script>
58 <script type="text/javascript" src="${h.url('/js/yui/selector/selector-min.js')}"></script>
57 % else:
59 % else:
58 <script type="text/javascript" src="${h.url('/js/yui2a.js')}"></script>
60 <script type="text/javascript" src="${h.url('/js/yui2a.js')}"></script>
59 <!--[if IE]>
61 <!--[if IE]>
60 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
62 <script language="javascript" type="text/javascript" src="${h.url('/js/excanvas.min.js')}"></script>
61 <![endif]-->
63 <![endif]-->
62 <script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
64 <script type="text/javascript" src="${h.url('/js/yui.flot.js')}"></script>
63 % endif
65 % endif
64
66 ${self.js_extra()}
65 <script type="text/javascript">
67 <script type="text/javascript">
66 var YUC = YAHOO.util.Connect;
68 var YUC = YAHOO.util.Connect;
67 var YUD = YAHOO.util.Dom;
69 var YUD = YAHOO.util.Dom;
68 var YUE = YAHOO.util.Event;
70 var YUE = YAHOO.util.Event;
69 </script>
71 </script>
70
72
71 <script type="text/javascript">
73 <script type="text/javascript">
72 var base_url = "${h.url('toggle_following')}";
74 var base_url = "${h.url('toggle_following')}";
73 function onSuccess(target){
75 function onSuccess(target){
74
76
75 var f = YUD.get(target.id);
77 var f = YUD.get(target.id);
76 var f_cnt = YUD.get('current_followers_count');
78 var f_cnt = YUD.get('current_followers_count');
77
79
78 if(f.getAttribute('class')=='follow'){
80 if(f.getAttribute('class')=='follow'){
79 f.setAttribute('class','following');
81 f.setAttribute('class','following');
80 f.setAttribute('title',"${_('Stop following this repository')}");
82 f.setAttribute('title',"${_('Stop following this repository')}");
81
83
82 if(f_cnt){
84 if(f_cnt){
83 var cnt = Number(f_cnt.innerHTML)+1;
85 var cnt = Number(f_cnt.innerHTML)+1;
84 f_cnt.innerHTML = cnt;
86 f_cnt.innerHTML = cnt;
85 }
87 }
86
88
87 }
89 }
88 else{
90 else{
89 f.setAttribute('class','follow');
91 f.setAttribute('class','follow');
90 f.setAttribute('title',"${_('Start following this repository')}");
92 f.setAttribute('title',"${_('Start following this repository')}");
91 if(f_cnt){
93 if(f_cnt){
92 var cnt = Number(f_cnt.innerHTML)+1;
94 var cnt = Number(f_cnt.innerHTML)+1;
93 f_cnt.innerHTML = cnt;
95 f_cnt.innerHTML = cnt;
94 }
96 }
95 }
97 }
96 }
98 }
97
99
98 function toggleFollowingUser(target,fallows_user_id,token,user_id){
100 function toggleFollowingUser(target,fallows_user_id,token,user_id){
99 args = 'follows_user_id='+fallows_user_id;
101 args = 'follows_user_id='+fallows_user_id;
100 args+= '&amp;auth_token='+token;
102 args+= '&amp;auth_token='+token;
101 if(user_id != undefined){
103 if(user_id != undefined){
102 args+="&amp;user_id="+user_id;
104 args+="&amp;user_id="+user_id;
103 }
105 }
104 YUC.asyncRequest('POST',base_url,{
106 YUC.asyncRequest('POST',base_url,{
105 success:function(o){
107 success:function(o){
106 onSuccess(target);
108 onSuccess(target);
107 }
109 }
108 },args); return false;
110 },args); return false;
109 }
111 }
110
112
111 function toggleFollowingRepo(target,fallows_repo_id,token,user_id){
113 function toggleFollowingRepo(target,fallows_repo_id,token,user_id){
112
114
113 args = 'follows_repo_id='+fallows_repo_id;
115 args = 'follows_repo_id='+fallows_repo_id;
114 args+= '&amp;auth_token='+token;
116 args+= '&amp;auth_token='+token;
115 if(user_id != undefined){
117 if(user_id != undefined){
116 args+="&amp;user_id="+user_id;
118 args+="&amp;user_id="+user_id;
117 }
119 }
118 YUC.asyncRequest('POST',base_url,{
120 YUC.asyncRequest('POST',base_url,{
119 success:function(o){
121 success:function(o){
120 onSuccess(target);
122 onSuccess(target);
121 }
123 }
122 },args); return false;
124 },args); return false;
123 }
125 }
124 </script>
126 </script>
125
127
128 </%def>
129 <%def name="js_extra()">
126 </%def> No newline at end of file
130 </%def>
@@ -1,91 +1,95 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${c.repo_name} ${_('File annotate')} - ${c.rhodecode_name}
4 ${c.repo_name} ${_('File annotate')} - ${c.rhodecode_name}
5 </%def>
5 </%def>
6
6
7 <%def name="breadcrumbs_links()">
7 <%def name="breadcrumbs_links()">
8 ${h.link_to(u'Home',h.url('/'))}
8 ${h.link_to(u'Home',h.url('/'))}
9 &raquo;
9 &raquo;
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
10 ${h.link_to(c.repo_name,h.url('summary_home',repo_name=c.repo_name))}
11 &raquo;
11 &raquo;
12 ${_('annotate')} @ R${c.cs.revision}:${h.short_id(c.cs.raw_id)}
12 ${_('annotate')} @ R${c.cs.revision}:${h.short_id(c.cs.raw_id)}
13 </%def>
13 </%def>
14
14
15 <%def name="page_nav()">
15 <%def name="page_nav()">
16 ${self.menu('files')}
16 ${self.menu('files')}
17 </%def>
17 </%def>
18 <%def name="main()">
18 <%def name="main()">
19 <div class="box">
19 <div class="box">
20 <!-- box / title -->
20 <!-- box / title -->
21 <div class="title">
21 <div class="title">
22 ${self.breadcrumbs()}
22 ${self.breadcrumbs()}
23 <ul class="links">
23 <ul class="links">
24 <li>
24 <li>
25 <span style="text-transform: uppercase;"><a href="#">${_('branch')}: ${c.cs.branch}</a></span>
25 <span style="text-transform: uppercase;"><a href="#">${_('branch')}: ${c.cs.branch}</a></span>
26 </li>
26 </li>
27 </ul>
27 </ul>
28 </div>
28 </div>
29 <div class="table">
29 <div class="table">
30 <div id="files_data">
30 <div id="files_data">
31 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cs.revision,c.file.path)}</h3>
31 <h3 class="files_location">${_('Location')}: ${h.files_breadcrumbs(c.repo_name,c.cs.revision,c.file.path)}</h3>
32 <dl class="overview">
32 <dl class="overview">
33 <dt>${_('Revision')}</dt>
33 <dt>${_('Revision')}</dt>
34 <dd>${h.link_to("r%s:%s" % (c.file.last_changeset.revision,h.short_id(c.file.last_changeset.raw_id)),
34 <dd>${h.link_to("r%s:%s" % (c.file.last_changeset.revision,h.short_id(c.file.last_changeset.raw_id)),
35 h.url('changeset_home',repo_name=c.repo_name,revision=c.file.last_changeset.raw_id))} </dd>
35 h.url('changeset_home',repo_name=c.repo_name,revision=c.file.last_changeset.raw_id))} </dd>
36 <dt>${_('Size')}</dt>
36 <dt>${_('Size')}</dt>
37 <dd>${h.format_byte_size(c.file.size,binary=True)}</dd>
37 <dd>${h.format_byte_size(c.file.size,binary=True)}</dd>
38 <dt>${_('Mimetype')}</dt>
38 <dt>${_('Mimetype')}</dt>
39 <dd>${c.file.mimetype}</dd>
39 <dd>${c.file.mimetype}</dd>
40 <dt>${_('Options')}</dt>
40 <dt>${_('Options')}</dt>
41 <dd>${h.link_to(_('show source'),
41 <dd>${h.link_to(_('show source'),
42 h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
42 h.url('files_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
43 / ${h.link_to(_('show as raw'),
43 / ${h.link_to(_('show as raw'),
44 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
44 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
45 / ${h.link_to(_('download as raw'),
45 / ${h.link_to(_('download as raw'),
46 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
46 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
47 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
48 / ${h.link_to(_('edit'),
49 h.url('files_edit_home',repo_name=c.repo_name,revision=c.cs.raw_id,f_path=c.f_path))}
50 % endif
47 </dd>
51 </dd>
48 <dt>${_('History')}</dt>
52 <dt>${_('History')}</dt>
49 <dd>
53 <dd>
50 <div>
54 <div>
51 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
55 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
52 ${h.hidden('diff2',c.file.last_changeset.raw_id)}
56 ${h.hidden('diff2',c.file.last_changeset.raw_id)}
53 ${h.select('diff1',c.file.last_changeset.raw_id,c.file_history)}
57 ${h.select('diff1',c.file.last_changeset.raw_id,c.file_history)}
54 ${h.submit('diff','diff to revision',class_="ui-button-small")}
58 ${h.submit('diff','diff to revision',class_="ui-button-small")}
55 ${h.submit('show_rev','show at revision',class_="ui-button-small")}
59 ${h.submit('show_rev','show at revision',class_="ui-button-small")}
56 ${h.end_form()}
60 ${h.end_form()}
57 </div>
61 </div>
58 </dd>
62 </dd>
59 </dl>
63 </dl>
60 <div id="body" class="codeblock">
64 <div id="body" class="codeblock">
61 <div class="code-header">
65 <div class="code-header">
62 <div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${h.short_id(c.file.last_changeset.raw_id)}</div>
66 <div class="revision">${c.file.name}@r${c.file.last_changeset.revision}:${h.short_id(c.file.last_changeset.raw_id)}</div>
63 <div class="commit">"${c.file.message}"</div>
67 <div class="commit">"${c.file.message}"</div>
64 </div>
68 </div>
65 <div class="code-body">
69 <div class="code-body">
66 %if c.file.is_binary:
70 %if c.file.is_binary:
67 ${_('Binary file (%s)') % c.file.mimetype}
71 ${_('Binary file (%s)') % c.file.mimetype}
68 %else:
72 %else:
69 % if c.file.size < c.cut_off_limit:
73 % if c.file.size < c.cut_off_limit:
70 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
74 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='S',cssclass="code-highlight")}
71 %else:
75 %else:
72 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
76 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
73 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.f_path))}
77 h.url('files_raw_home',repo_name=c.repo_name,revision=c.cs.revision,f_path=c.f_path))}
74 %endif
78 %endif
75 <script type="text/javascript">
79 <script type="text/javascript">
76 YAHOO.util.Event.onDOMReady(function(){
80 YAHOO.util.Event.onDOMReady(function(){
77 YAHOO.util.Event.addListener('show_rev','click',function(e){
81 YAHOO.util.Event.addListener('show_rev','click',function(e){
78 YAHOO.util.Event.preventDefault(e);
82 YAHOO.util.Event.preventDefault(e);
79 var cs = YAHOO.util.Dom.get('diff1').value;
83 var cs = YAHOO.util.Dom.get('diff1').value;
80 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
84 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
81 window.location = url;
85 window.location = url;
82 });
86 });
83 });
87 });
84 </script>
88 </script>
85 %endif
89 %endif
86 </div>
90 </div>
87 </div>
91 </div>
88 </div>
92 </div>
89 </div>
93 </div>
90 </div>
94 </div>
91 </%def> No newline at end of file
95 </%def>
@@ -1,91 +1,95 b''
1 <dl>
1 <dl>
2 <dt>${_('Revision')}</dt>
2 <dt>${_('Revision')}</dt>
3 <dd>
3 <dd>
4 ${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
4 ${h.link_to("r%s:%s" % (c.files_list.last_changeset.revision,h.short_id(c.files_list.last_changeset.raw_id)),
5 h.url('changeset_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id))}
5 h.url('changeset_home',repo_name=c.repo_name,revision=c.files_list.last_changeset.raw_id))}
6 </dd>
6 </dd>
7 <dt>${_('Size')}</dt>
7 <dt>${_('Size')}</dt>
8 <dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
8 <dd>${h.format_byte_size(c.files_list.size,binary=True)}</dd>
9 <dt>${_('Mimetype')}</dt>
9 <dt>${_('Mimetype')}</dt>
10 <dd>${c.files_list.mimetype}</dd>
10 <dd>${c.files_list.mimetype}</dd>
11 <dt>${_('Options')}</dt>
11 <dt>${_('Options')}</dt>
12 <dd>${h.link_to(_('show annotation'),
12 <dd>${h.link_to(_('show annotation'),
13 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
13 h.url('files_annotate_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
14 / ${h.link_to(_('show as raw'),
14 / ${h.link_to(_('show as raw'),
15 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
15 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
16 / ${h.link_to(_('download as raw'),
16 / ${h.link_to(_('download as raw'),
17 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
17 h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
18 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
19 / ${h.link_to(_('edit'),
20 h.url('files_edit_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
21 % endif
18 </dd>
22 </dd>
19 <dt>${_('History')}</dt>
23 <dt>${_('History')}</dt>
20 <dd>
24 <dd>
21 <div>
25 <div>
22 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
26 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
23 ${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
27 ${h.hidden('diff2',c.files_list.last_changeset.raw_id)}
24 ${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
28 ${h.select('diff1',c.files_list.last_changeset.raw_id,c.file_history)}
25 ${h.submit('diff','diff to revision',class_="ui-button-small")}
29 ${h.submit('diff','diff to revision',class_="ui-button-small")}
26 ${h.submit('show_rev','show at revision',class_="ui-button-small")}
30 ${h.submit('show_rev','show at revision',class_="ui-button-small")}
27 ${h.end_form()}
31 ${h.end_form()}
28 </div>
32 </div>
29 </dd>
33 </dd>
30 </dl>
34 </dl>
31
35
32
36
33 <div id="body" class="codeblock">
37 <div id="body" class="codeblock">
34 <div class="code-header">
38 <div class="code-header">
35 <div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
39 <div class="revision">${c.files_list.name}@r${c.files_list.last_changeset.revision}:${h.short_id(c.files_list.last_changeset.raw_id)}</div>
36 <div class="commit">"${c.files_list.last_changeset.message}"</div>
40 <div class="commit">"${c.files_list.last_changeset.message}"</div>
37 </div>
41 </div>
38 <div class="code-body">
42 <div class="code-body">
39 %if c.files_list.is_binary:
43 %if c.files_list.is_binary:
40 ${_('Binary file (%s)') % c.files_list.mimetype}
44 ${_('Binary file (%s)') % c.files_list.mimetype}
41 %else:
45 %else:
42 % if c.files_list.size < c.cut_off_limit:
46 % if c.files_list.size < c.cut_off_limit:
43 ${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
47 ${h.pygmentize(c.files_list,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
44 %else:
48 %else:
45 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
49 ${_('File is to big to display')} ${h.link_to(_('show as raw'),
46 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
50 h.url('files_raw_home',repo_name=c.repo_name,revision=c.changeset.raw_id,f_path=c.f_path))}
47 %endif
51 %endif
48
52
49 <script type="text/javascript">
53 <script type="text/javascript">
50 function highlight_lines(lines){
54 function highlight_lines(lines){
51 for(pos in lines){
55 for(pos in lines){
52 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
56 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
53 }
57 }
54 }
58 }
55 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
59 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
56 if (page_highlights.length == 2){
60 if (page_highlights.length == 2){
57 highlight_ranges = page_highlights[1].split(",");
61 highlight_ranges = page_highlights[1].split(",");
58
62
59 var h_lines = [];
63 var h_lines = [];
60 for (pos in highlight_ranges){
64 for (pos in highlight_ranges){
61 var _range = highlight_ranges[pos].split('-');
65 var _range = highlight_ranges[pos].split('-');
62 if(_range.length == 2){
66 if(_range.length == 2){
63 var start = parseInt(_range[0]);
67 var start = parseInt(_range[0]);
64 var end = parseInt(_range[1]);
68 var end = parseInt(_range[1]);
65 if (start < end){
69 if (start < end){
66 for(var i=start;i<=end;i++){
70 for(var i=start;i<=end;i++){
67 h_lines.push(i);
71 h_lines.push(i);
68 }
72 }
69 }
73 }
70 }
74 }
71 else{
75 else{
72 h_lines.push(parseInt(highlight_ranges[pos]));
76 h_lines.push(parseInt(highlight_ranges[pos]));
73 }
77 }
74 }
78 }
75 highlight_lines(h_lines);
79 highlight_lines(h_lines);
76 }
80 }
77 </script>
81 </script>
78 %endif
82 %endif
79 </div>
83 </div>
80 </div>
84 </div>
81
85
82 <script type="text/javascript">
86 <script type="text/javascript">
83 YAHOO.util.Event.onDOMReady(function(){
87 YAHOO.util.Event.onDOMReady(function(){
84 YAHOO.util.Event.addListener('show_rev','click',function(e){
88 YAHOO.util.Event.addListener('show_rev','click',function(e){
85 YAHOO.util.Event.preventDefault(e);
89 YAHOO.util.Event.preventDefault(e);
86 var cs = YAHOO.util.Dom.get('diff1').value;
90 var cs = YAHOO.util.Dom.get('diff1').value;
87 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
91 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
88 window.location = url;
92 window.location = url;
89 });
93 });
90 });
94 });
91 </script> No newline at end of file
95 </script>
General Comments 0
You need to be logged in to leave comments. Login now