Merge branch 'master' into move_settings
Conflicts: static/simplewiki
@@ -169,7 +169,7 @@ def grade_summary_6002x(totaled_scores):
|
||||
homework_percentages = []
|
||||
for i in range(12):
|
||||
if i < len(homework_scores):
|
||||
percentage = homework_scores[1].earned / float(homework_scores[i].possible)
|
||||
percentage = homework_scores[i].earned / float(homework_scores[i].possible)
|
||||
summary = "Homework {0} - {1} - {2:.0%} ({3:g}/{4:g})".format( i + 1, homework_scores[i].section , percentage, homework_scores[i].earned, homework_scores[i].possible )
|
||||
else:
|
||||
percentage = 0
|
||||
|
||||
@@ -73,7 +73,9 @@ class Module(XModule):
|
||||
content={'name':self.name,
|
||||
'html':html}
|
||||
|
||||
check_button = True
|
||||
# We using strings as truthy values, because the terminology of the check button
|
||||
# is context-specific.
|
||||
check_button = "Grade" if self.max_attempts else "Check"
|
||||
reset_button = True
|
||||
save_button = True
|
||||
|
||||
@@ -96,10 +98,6 @@ class Module(XModule):
|
||||
if not self.lcp.done:
|
||||
reset_button = False
|
||||
|
||||
attempts_str = ""
|
||||
if self.max_attempts != None:
|
||||
attempts_str = " ({a}/{m})".format(a=self.attempts, m=self.max_attempts)
|
||||
|
||||
# We don't need a "save" button if infinite number of attempts and non-randomized
|
||||
if self.max_attempts == None and self.rerandomize != "always":
|
||||
save_button = False
|
||||
@@ -122,7 +120,8 @@ class Module(XModule):
|
||||
'save_button' : save_button,
|
||||
'answer_available' : self.answer_available(),
|
||||
'ajax_url' : self.ajax_url,
|
||||
'attempts': attempts_str,
|
||||
'attempts_used': self.attempts,
|
||||
'attempts_allowed': self.max_attempts,
|
||||
'explain': explain
|
||||
})
|
||||
if encapsulate:
|
||||
|
||||
@@ -3,14 +3,24 @@
|
||||
Image Circuit Extension for Python-Markdown
|
||||
======================================
|
||||
|
||||
circuit:name becomes the circuit.
|
||||
|
||||
Any single line beginning with circuit-schematic: and followed by data (which should be json data, but this
|
||||
is not enforced at this level) will be displayed as a circuit schematic. This is simply an input element with
|
||||
the value set to the data. It is left to javascript on the page to render that input as a circuit schematic.
|
||||
|
||||
ex:
|
||||
circuit-schematic:[["r",[128,48,0],{"r":"1","_json_":0},["2","1"]],["view",0,0,2,null,null,null,null,null,null,null],["dc",{"0":0,"1":1,"I(_3)":-1}]]
|
||||
|
||||
(This is a schematic with a single one-ohm resistor. Note that this data is not meant to be user-editable.)
|
||||
|
||||
'''
|
||||
import markdown
|
||||
import re
|
||||
|
||||
import simplewiki.settings as settings
|
||||
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from django.utils.html import escape
|
||||
|
||||
import markdown
|
||||
try:
|
||||
# Markdown 2.1.0 changed from 2.0.3. We try importing the new version first,
|
||||
# but import the 2.0.3 version if it fails
|
||||
@@ -22,23 +32,40 @@ class CircuitExtension(markdown.Extension):
|
||||
def __init__(self, configs):
|
||||
for key, value in configs :
|
||||
self.setConfig(key, value)
|
||||
|
||||
def add_inline(self, md, name, klass, re):
|
||||
pattern = klass(re)
|
||||
pattern.md = md
|
||||
pattern.ext = self
|
||||
md.inlinePatterns.add(name, pattern, "<reference")
|
||||
|
||||
|
||||
def extendMarkdown(self, md, md_globals):
|
||||
self.add_inline(md, 'circuit', CircuitLink, r'^circuit:(?P<name>[a-zA-Z0-9]*)$')
|
||||
## Because Markdown treats contigous lines as one block of text, it is hard to match
|
||||
## a regex that must occupy the whole line (like the circuit regex). This is why we have
|
||||
## a preprocessor that inspects the lines and replaces the matched lines with text that is
|
||||
## easier to match
|
||||
md.preprocessors.add('circuit', CircuitPreprocessor(md), "_begin")
|
||||
|
||||
pattern = CircuitLink(r'processed-schematic:(?P<data>.*?)processed-schematic-end')
|
||||
pattern.md = md
|
||||
pattern.ext = self
|
||||
md.inlinePatterns.add('circuit', pattern, "<reference")
|
||||
|
||||
|
||||
class CircuitPreprocessor(markdown.preprocessors.Preprocessor):
|
||||
preRegex = re.compile(r'^circuit-schematic:(?P<data>.*)$')
|
||||
|
||||
def run(self, lines):
|
||||
def convertLine(line):
|
||||
m = self.preRegex.match(line)
|
||||
if m:
|
||||
return 'processed-schematic:{0}processed-schematic-end'.format( m.group('data') )
|
||||
else:
|
||||
return line
|
||||
|
||||
return [ convertLine(line) for line in lines ]
|
||||
|
||||
|
||||
class CircuitLink(markdown.inlinepatterns.Pattern):
|
||||
def handleMatch(self, m):
|
||||
name = m.group('name')
|
||||
if not name.isalnum():
|
||||
return etree.fromstring("<div>Circuit name must be alphanumeric</div>")
|
||||
|
||||
return etree.fromstring(render_to_string('show_circuit.html', {'name':name}))
|
||||
data = m.group('data')
|
||||
data = escape(data)
|
||||
return etree.fromstring("<div align='center'><input type='hidden' parts='' value='" + data + "' analyses='' class='schematic ctrls' width='500' height='300'/></div>")
|
||||
|
||||
|
||||
def makeExtension(configs=None) :
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
================================================
|
||||
autosuggest, inquisitor style
|
||||
================================================
|
||||
*/
|
||||
|
||||
body
|
||||
{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
div.autosuggest
|
||||
{
|
||||
position: absolute;
|
||||
background-image: url(img_inquisitor/as_pointer.gif);
|
||||
background-position: top;
|
||||
background-repeat: no-repeat;
|
||||
padding: 10px 0 0 0;
|
||||
}
|
||||
|
||||
div.autosuggest div.as_header,
|
||||
div.autosuggest div.as_footer
|
||||
{
|
||||
position: relative;
|
||||
height: 6px;
|
||||
padding: 0 6px;
|
||||
background-image: url(img_inquisitor/ul_corner_tr.gif);
|
||||
background-position: top right;
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden;
|
||||
}
|
||||
div.autosuggest div.as_footer
|
||||
{
|
||||
background-image: url(img_inquisitor/ul_corner_br.gif);
|
||||
}
|
||||
|
||||
div.autosuggest div.as_header div.as_corner,
|
||||
div.autosuggest div.as_footer div.as_corner
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
background-image: url(img_inquisitor/ul_corner_tl.gif);
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
div.autosuggest div.as_footer div.as_corner
|
||||
{
|
||||
background-image: url(img_inquisitor/ul_corner_bl.gif);
|
||||
}
|
||||
div.autosuggest div.as_header div.as_bar,
|
||||
div.autosuggest div.as_footer div.as_bar
|
||||
{
|
||||
height: 6px;
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
|
||||
div.autosuggest ul
|
||||
{
|
||||
list-style: none;
|
||||
margin: 0 0 -4px 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
div.autosuggest ul li
|
||||
{
|
||||
color: #ccc;
|
||||
padding: 0;
|
||||
margin: 0 4px 4px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div.autosuggest ul li a
|
||||
{
|
||||
color: #ccc;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
text-shadow: #000 0px 0px 5px;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
div.autosuggest ul li a:hover
|
||||
{
|
||||
background-color: #444;
|
||||
}
|
||||
div.autosuggest ul li.as_highlight a:hover
|
||||
{
|
||||
background-color: #1B5CCD;
|
||||
}
|
||||
|
||||
div.autosuggest ul li a span
|
||||
{
|
||||
display: block;
|
||||
padding: 3px 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.autosuggest ul li a span small
|
||||
{
|
||||
font-weight: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
div.autosuggest ul li.as_highlight a span small
|
||||
{
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
div.autosuggest ul li.as_highlight a
|
||||
{
|
||||
color: #fff;
|
||||
background-color: #1B5CCD;
|
||||
background-image: url(img_inquisitor/hl_corner_br.gif);
|
||||
background-position: bottom right;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
div.autosuggest ul li.as_highlight a span
|
||||
{
|
||||
background-image: url(img_inquisitor/hl_corner_bl.gif);
|
||||
background-position: bottom left;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
div.autosuggest ul li a .tl,
|
||||
div.autosuggest ul li a .tr
|
||||
{
|
||||
background-image: transparent;
|
||||
background-repeat: no-repeat;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
div.autosuggest ul li a .tr
|
||||
{
|
||||
right: 0;
|
||||
}
|
||||
|
||||
div.autosuggest ul li.as_highlight a .tl
|
||||
{
|
||||
left: 0;
|
||||
background-image: url(img_inquisitor/hl_corner_tl.gif);
|
||||
background-position: bottom left;
|
||||
}
|
||||
|
||||
div.autosuggest ul li.as_highlight a .tr
|
||||
{
|
||||
right: 0;
|
||||
background-image: url(img_inquisitor/hl_corner_tr.gif);
|
||||
background-position: bottom right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.autosuggest ul li.as_warning
|
||||
{
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.autosuggest ul em
|
||||
{
|
||||
font-style: normal;
|
||||
color: #6EADE7;
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
body
|
||||
{
|
||||
font-family: 'Lucida Sans', 'Sans';
|
||||
}
|
||||
|
||||
a img
|
||||
{
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div#wiki_article a {
|
||||
color: #06d;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div#wiki_article a:hover {
|
||||
color: #f82;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
background-color: #def;
|
||||
height: 2px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div#wiki_article .toc a
|
||||
{
|
||||
color: #025
|
||||
}
|
||||
|
||||
div#wiki_article p
|
||||
{
|
||||
/* font-size: 90%; looks funny when combined with lists/tables */
|
||||
line-height: 140%;
|
||||
}
|
||||
div#wiki_article h1
|
||||
{
|
||||
font-size: 200%;
|
||||
font-weight: normal;
|
||||
color: #048;
|
||||
}
|
||||
|
||||
div#wiki_article h2
|
||||
{
|
||||
font-size: 150%;
|
||||
font-weight: normal;
|
||||
color: #025;
|
||||
}
|
||||
|
||||
div#wiki_article h3
|
||||
{
|
||||
font-size: 120%;
|
||||
font-weight: bold;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
table
|
||||
{
|
||||
border: 1px solid black;
|
||||
border-collapse: collapse;
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
table tr.dark
|
||||
{
|
||||
background-color: #F3F3F3;
|
||||
}
|
||||
|
||||
table thead tr
|
||||
{
|
||||
background-color: #def;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
|
||||
table td, th
|
||||
{
|
||||
padding: 6px 10px 6px 10px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
table thead th
|
||||
{
|
||||
padding-bottom: 8px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
div#wiki_panel
|
||||
{
|
||||
float: right;
|
||||
}
|
||||
|
||||
div.wiki_box
|
||||
{
|
||||
width: 230px;
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
div.wiki_box div.wiki_box_contents
|
||||
{ background-color: #222;
|
||||
padding: 5px 10px;}
|
||||
|
||||
div.wiki_box div.wiki_box_header,
|
||||
div.wiki_box div.wiki_box_footer
|
||||
{
|
||||
position: relative;
|
||||
height: 6px;
|
||||
padding: 0 6px;
|
||||
background-image: url(../img/box_corner_tr.gif);
|
||||
background-position: top right;
|
||||
background-repeat: no-repeat;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.wiki_box div.wiki_box_footer
|
||||
{
|
||||
background-image: url(../img/box_corner_br.gif);
|
||||
}
|
||||
|
||||
div.wiki_box div.wiki_box_header div.wiki_box_corner,
|
||||
div.wiki_box div.wiki_box_footer div.wiki_box_corner
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
background-image: url(../img/box_corner_tl.gif);
|
||||
background-position: top left;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
div.wiki_box div.wiki_box_footer div.wiki_box_corner
|
||||
{
|
||||
background-image: url(../img/box_corner_bl.gif);
|
||||
}
|
||||
|
||||
div.wiki_box div.wiki_box_header div.wiki_box_bar,
|
||||
div.wiki_box div.wiki_box_footer div.wiki_box_bar
|
||||
{
|
||||
height: 6px;
|
||||
overflow: hidden;
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
|
||||
div.wiki_box a
|
||||
{
|
||||
color: #acf;
|
||||
}
|
||||
|
||||
div.wiki_box p
|
||||
{
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
div.wiki_box ul
|
||||
{
|
||||
padding-left: 20px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
div.wiki_box div.wiki_box_title
|
||||
{
|
||||
margin-bottom: 5px;
|
||||
font-size: 140%;
|
||||
}
|
||||
|
||||
form#wiki_revision #id_contents
|
||||
{
|
||||
width:500px;
|
||||
height: 400px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
form#wiki_revision #id_title
|
||||
{
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
form#wiki_revision #id_revision_text
|
||||
{
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
table#wiki_revision_table
|
||||
{
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
padding-right: 250px;
|
||||
}
|
||||
|
||||
table#wiki_revision_table th
|
||||
{
|
||||
border: none;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table#wiki_revision_table td
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
table#wiki_history_table
|
||||
{
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
padding-right: 250px;
|
||||
}
|
||||
|
||||
table#wiki_history_table th#modified
|
||||
{
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
table#wiki_history_table td
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
table#wiki_history_table tbody tr
|
||||
{
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
table#wiki_history_table tbody td
|
||||
{
|
||||
vertical-align: top;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
table#wiki_history_table tfoot td
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
table#wiki_history_table tbody td.diff
|
||||
{
|
||||
font-family: monospace;
|
||||
overflow: hidden;
|
||||
border-left: 1px dotted black;
|
||||
border-right: 1px dotted black;
|
||||
}
|
||||
|
||||
table#wiki_history_table th
|
||||
{
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
div#wiki_attach_progress_container
|
||||
{
|
||||
background-color: #333;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#wiki_attach_progress
|
||||
{
|
||||
width: 25%;
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
margin-left: 50px;
|
||||
padding-left: 15px;
|
||||
border-left: 3px solid #666;
|
||||
color: #999;
|
||||
max-width: 400px ;
|
||||
}
|
||||
|
||||
blockquote p {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
div#wiki_panel
|
||||
{
|
||||
display:none;
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 66 B |
|
Before Width: | Height: | Size: 73 B |
|
Before Width: | Height: | Size: 73 B |
|
Before Width: | Height: | Size: 73 B |
|
Before Width: | Height: | Size: 73 B |
|
Before Width: | Height: | Size: 49 B |
|
Before Width: | Height: | Size: 49 B |
|
Before Width: | Height: | Size: 50 B |
|
Before Width: | Height: | Size: 50 B |
|
Before Width: | Height: | Size: 49 B |
|
Before Width: | Height: | Size: 49 B |
|
Before Width: | Height: | Size: 50 B |
|
Before Width: | Height: | Size: 50 B |
|
Before Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 130 B |
@@ -1,961 +0,0 @@
|
||||
/**
|
||||
* author: Timothy Groves - http://www.brandspankingnew.net
|
||||
* version: 1.2 - 2006-11-17
|
||||
* 1.3 - 2006-12-04
|
||||
* 2.0 - 2007-02-07
|
||||
*
|
||||
*/
|
||||
|
||||
var useBSNns;
|
||||
|
||||
if (useBSNns)
|
||||
{
|
||||
if (typeof(bsn) == "undefined")
|
||||
bsn = {}
|
||||
_bsn = bsn;
|
||||
}
|
||||
else
|
||||
{
|
||||
_bsn = this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (typeof(_bsn.Autosuggest) == "undefined")
|
||||
_bsn.Autosuggest = {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest = function (fldID, param)
|
||||
{
|
||||
// no DOM - give up!
|
||||
//
|
||||
if (!document.getElementById)
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
|
||||
// get field via DOM
|
||||
//
|
||||
this.fld = _bsn.DOM.getElement(fldID);
|
||||
|
||||
if (!this.fld)
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
|
||||
// init variables
|
||||
//
|
||||
this.sInput = "";
|
||||
this.nInputChars = 0;
|
||||
this.aSuggestions = [];
|
||||
this.iHighlighted = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
// parameters object
|
||||
//
|
||||
this.oP = (param) ? param : {};
|
||||
|
||||
// defaults
|
||||
//
|
||||
if (!this.oP.minchars) this.oP.minchars = 1;
|
||||
if (!this.oP.method) this.oP.meth = "get";
|
||||
if (!this.oP.varname) this.oP.varname = "input";
|
||||
if (!this.oP.className) this.oP.className = "autosuggest";
|
||||
if (!this.oP.timeout) this.oP.timeout = 2500;
|
||||
if (!this.oP.delay) this.oP.delay = 500;
|
||||
if (!this.oP.offsety) this.oP.offsety = -5;
|
||||
if (!this.oP.shownoresults) this.oP.shownoresults = true;
|
||||
if (!this.oP.noresults) this.oP.noresults = "No results!";
|
||||
if (!this.oP.maxheight && this.oP.maxheight !== 0) this.oP.maxheight = 250;
|
||||
if (!this.oP.cache && this.oP.cache != false) this.oP.cache = true;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// set keyup handler for field
|
||||
// and prevent autocomplete from client
|
||||
//
|
||||
var pointer = this;
|
||||
|
||||
// NOTE: not using addEventListener because UpArrow fired twice in Safari
|
||||
//_bsn.DOM.addEvent( this.fld, 'keyup', function(ev){ return pointer.onKeyPress(ev); } );
|
||||
|
||||
this.fld.onkeypress = function(ev){ return pointer.onKeyPress(ev); }
|
||||
this.fld.onkeyup = function(ev){ return pointer.onKeyUp(ev); }
|
||||
|
||||
this.fld.setAttribute("autocomplete","off");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.onKeyPress = function(ev)
|
||||
{
|
||||
|
||||
var key = (window.event) ? window.event.keyCode : ev.keyCode;
|
||||
|
||||
|
||||
|
||||
// set responses to keydown events in the field
|
||||
// this allows the user to use the arrow keys to scroll through the results
|
||||
// ESCAPE clears the list
|
||||
// TAB sets the current highlighted value
|
||||
//
|
||||
var RETURN = 13;
|
||||
var TAB = 9;
|
||||
var ESC = 27;
|
||||
|
||||
var bubble = true;
|
||||
|
||||
switch(key)
|
||||
{
|
||||
|
||||
case RETURN:
|
||||
this.setHighlightedValue();
|
||||
bubble = false;
|
||||
break;
|
||||
|
||||
|
||||
case ESC:
|
||||
this.clearSuggestions();
|
||||
break;
|
||||
}
|
||||
|
||||
return bubble;
|
||||
}
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.onKeyUp = function(ev)
|
||||
{
|
||||
var key = (window.event) ? window.event.keyCode : ev.keyCode;
|
||||
|
||||
|
||||
|
||||
// set responses to keydown events in the field
|
||||
// this allows the user to use the arrow keys to scroll through the results
|
||||
// ESCAPE clears the list
|
||||
// TAB sets the current highlighted value
|
||||
//
|
||||
|
||||
var ARRUP = 38;
|
||||
var ARRDN = 40;
|
||||
|
||||
var bubble = true;
|
||||
|
||||
switch(key)
|
||||
{
|
||||
|
||||
|
||||
case ARRUP:
|
||||
this.changeHighlight(key);
|
||||
bubble = false;
|
||||
break;
|
||||
|
||||
|
||||
case ARRDN:
|
||||
this.changeHighlight(key);
|
||||
bubble = false;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
this.getSuggestions(this.fld.value);
|
||||
}
|
||||
|
||||
return bubble;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.getSuggestions = function (val)
|
||||
{
|
||||
|
||||
// if input stays the same, do nothing
|
||||
//
|
||||
if (val == this.sInput)
|
||||
return false;
|
||||
|
||||
|
||||
// input length is less than the min required to trigger a request
|
||||
// reset input string
|
||||
// do nothing
|
||||
//
|
||||
if (val.length < this.oP.minchars)
|
||||
{
|
||||
this.sInput = "";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// if caching enabled, and user is typing (ie. length of input is increasing)
|
||||
// filter results out of aSuggestions from last request
|
||||
//
|
||||
if (val.length>this.nInputChars && this.aSuggestions.length && this.oP.cache)
|
||||
{
|
||||
var arr = [];
|
||||
for (var i=0;i<this.aSuggestions.length;i++)
|
||||
{
|
||||
if (this.aSuggestions[i].value.substr(0,val.length).toLowerCase() == val.toLowerCase())
|
||||
arr.push( this.aSuggestions[i] );
|
||||
}
|
||||
|
||||
this.sInput = val;
|
||||
this.nInputChars = val.length;
|
||||
this.aSuggestions = arr;
|
||||
|
||||
this.createList(this.aSuggestions);
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
// do new request
|
||||
//
|
||||
{
|
||||
this.sInput = val;
|
||||
this.nInputChars = val.length;
|
||||
|
||||
|
||||
var pointer = this;
|
||||
clearTimeout(this.ajID);
|
||||
this.ajID = setTimeout( function() { pointer.doAjaxRequest() }, this.oP.delay );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.doAjaxRequest = function ()
|
||||
{
|
||||
|
||||
var pointer = this;
|
||||
|
||||
// create ajax request
|
||||
var url = this.oP.script+this.oP.varname+"="+escape(this.fld.value);
|
||||
var meth = this.oP.meth;
|
||||
|
||||
var onSuccessFunc = function (req) { pointer.setSuggestions(req) };
|
||||
var onErrorFunc = function (status) { alert("AJAX error: "+status); };
|
||||
|
||||
var myAjax = new _bsn.Ajax();
|
||||
myAjax.makeRequest( url, meth, onSuccessFunc, onErrorFunc );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.setSuggestions = function (req)
|
||||
{
|
||||
this.aSuggestions = [];
|
||||
|
||||
if (this.oP.json)
|
||||
{
|
||||
var jsondata = eval('(' + req.responseText + ')');
|
||||
|
||||
for (var i=0;i<jsondata.results.length;i++)
|
||||
{
|
||||
this.aSuggestions.push( { 'id':jsondata.results[i].id, 'value':jsondata.results[i].value, 'info':jsondata.results[i].info } );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var xml = req.responseXML;
|
||||
|
||||
// traverse xml
|
||||
//
|
||||
var results = xml.getElementsByTagName('results')[0].childNodes;
|
||||
|
||||
for (var i=0;i<results.length;i++)
|
||||
{
|
||||
if (results[i].hasChildNodes())
|
||||
this.aSuggestions.push( { 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') } );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.idAs = "as_"+this.fld.id;
|
||||
|
||||
|
||||
this.createList(this.aSuggestions);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.createList = function(arr)
|
||||
{
|
||||
var pointer = this;
|
||||
|
||||
|
||||
// get rid of old list
|
||||
// and clear the list removal timeout
|
||||
//
|
||||
_bsn.DOM.removeElement(this.idAs);
|
||||
this.killTimeout();
|
||||
|
||||
|
||||
// create holding div
|
||||
//
|
||||
var div = _bsn.DOM.createElement("div", {id:this.idAs, className:this.oP.className});
|
||||
|
||||
var hcorner = _bsn.DOM.createElement("div", {className:"as_corner"});
|
||||
var hbar = _bsn.DOM.createElement("div", {className:"as_bar"});
|
||||
var header = _bsn.DOM.createElement("div", {className:"as_header"});
|
||||
header.appendChild(hcorner);
|
||||
header.appendChild(hbar);
|
||||
div.appendChild(header);
|
||||
|
||||
|
||||
|
||||
|
||||
// create and populate ul
|
||||
//
|
||||
var ul = _bsn.DOM.createElement("ul", {id:"as_ul"});
|
||||
|
||||
|
||||
|
||||
|
||||
// loop throught arr of suggestions
|
||||
// creating an LI element for each suggestion
|
||||
//
|
||||
for (var i=0;i<arr.length;i++)
|
||||
{
|
||||
// format output with the input enclosed in a EM element
|
||||
// (as HTML, not DOM)
|
||||
//
|
||||
var val = arr[i].value;
|
||||
var st = val.toLowerCase().indexOf( this.sInput.toLowerCase() );
|
||||
var output = val.substring(0,st) + "<em>" + val.substring(st, st+this.sInput.length) + "</em>" + val.substring(st+this.sInput.length);
|
||||
|
||||
|
||||
var span = _bsn.DOM.createElement("span", {}, output, true);
|
||||
if (arr[i].info != "")
|
||||
{
|
||||
var br = _bsn.DOM.createElement("br", {});
|
||||
span.appendChild(br);
|
||||
var small = _bsn.DOM.createElement("small", {}, arr[i].info);
|
||||
span.appendChild(small);
|
||||
}
|
||||
|
||||
var a = _bsn.DOM.createElement("a", { href:"#" });
|
||||
|
||||
var tl = _bsn.DOM.createElement("span", {className:"tl"}, " ");
|
||||
var tr = _bsn.DOM.createElement("span", {className:"tr"}, " ");
|
||||
a.appendChild(tl);
|
||||
a.appendChild(tr);
|
||||
|
||||
a.appendChild(span);
|
||||
|
||||
a.name = i+1;
|
||||
a.onclick = function () { pointer.setHighlightedValue(); return false; }
|
||||
a.onmouseover = function () { pointer.setHighlight(this.name); }
|
||||
|
||||
var li = _bsn.DOM.createElement( "li", {}, a );
|
||||
|
||||
ul.appendChild( li );
|
||||
}
|
||||
|
||||
|
||||
// no results
|
||||
//
|
||||
if (arr.length == 0)
|
||||
{
|
||||
var li = _bsn.DOM.createElement( "li", {className:"as_warning"}, this.oP.noresults );
|
||||
|
||||
ul.appendChild( li );
|
||||
}
|
||||
|
||||
|
||||
div.appendChild( ul );
|
||||
|
||||
|
||||
var fcorner = _bsn.DOM.createElement("div", {className:"as_corner"});
|
||||
var fbar = _bsn.DOM.createElement("div", {className:"as_bar"});
|
||||
var footer = _bsn.DOM.createElement("div", {className:"as_footer"});
|
||||
footer.appendChild(fcorner);
|
||||
footer.appendChild(fbar);
|
||||
div.appendChild(footer);
|
||||
|
||||
|
||||
|
||||
// get position of target textfield
|
||||
// position holding div below it
|
||||
// set width of holding div to width of field
|
||||
//
|
||||
var pos = _bsn.DOM.getPos(this.fld);
|
||||
|
||||
div.style.left = pos.x + "px";
|
||||
div.style.top = ( pos.y + this.fld.offsetHeight + this.oP.offsety ) + "px";
|
||||
div.style.width = this.fld.offsetWidth + "px";
|
||||
|
||||
|
||||
|
||||
// set mouseover functions for div
|
||||
// when mouse pointer leaves div, set a timeout to remove the list after an interval
|
||||
// when mouse enters div, kill the timeout so the list won't be removed
|
||||
//
|
||||
div.onmouseover = function(){ pointer.killTimeout() }
|
||||
div.onmouseout = function(){ pointer.resetTimeout() }
|
||||
|
||||
|
||||
// add DIV to document
|
||||
//
|
||||
document.getElementsByTagName("body")[0].appendChild(div);
|
||||
|
||||
|
||||
|
||||
// currently no item is highlighted
|
||||
//
|
||||
this.iHighlighted = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// remove list after an interval
|
||||
//
|
||||
var pointer = this;
|
||||
this.toID = setTimeout(function () { pointer.clearSuggestions() }, this.oP.timeout);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.changeHighlight = function(key)
|
||||
{
|
||||
var list = _bsn.DOM.getElement("as_ul");
|
||||
if (!list)
|
||||
return false;
|
||||
|
||||
var n;
|
||||
|
||||
if (key == 40)
|
||||
n = this.iHighlighted + 1;
|
||||
else if (key == 38)
|
||||
n = this.iHighlighted - 1;
|
||||
|
||||
|
||||
if (n > list.childNodes.length)
|
||||
n = list.childNodes.length;
|
||||
if (n < 1)
|
||||
n = 1;
|
||||
|
||||
|
||||
this.setHighlight(n);
|
||||
}
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.setHighlight = function(n)
|
||||
{
|
||||
var list = _bsn.DOM.getElement("as_ul");
|
||||
if (!list)
|
||||
return false;
|
||||
|
||||
if (this.iHighlighted > 0)
|
||||
this.clearHighlight();
|
||||
|
||||
this.iHighlighted = Number(n);
|
||||
|
||||
list.childNodes[this.iHighlighted-1].className = "as_highlight";
|
||||
|
||||
|
||||
this.killTimeout();
|
||||
}
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.clearHighlight = function()
|
||||
{
|
||||
var list = _bsn.DOM.getElement("as_ul");
|
||||
if (!list)
|
||||
return false;
|
||||
|
||||
if (this.iHighlighted > 0)
|
||||
{
|
||||
list.childNodes[this.iHighlighted-1].className = "";
|
||||
this.iHighlighted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.setHighlightedValue = function ()
|
||||
{
|
||||
if (this.iHighlighted)
|
||||
{
|
||||
this.sInput = this.fld.value = this.aSuggestions[ this.iHighlighted-1 ].value;
|
||||
|
||||
// move cursor to end of input (safari)
|
||||
//
|
||||
this.fld.focus();
|
||||
if (this.fld.selectionStart)
|
||||
this.fld.setSelectionRange(this.sInput.length, this.sInput.length);
|
||||
|
||||
|
||||
this.clearSuggestions();
|
||||
|
||||
// pass selected object to callback function, if exists
|
||||
//
|
||||
if (typeof(this.oP.callback) == "function")
|
||||
this.oP.callback( this.aSuggestions[this.iHighlighted-1] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.killTimeout = function()
|
||||
{
|
||||
clearTimeout(this.toID);
|
||||
}
|
||||
|
||||
_bsn.AutoSuggest.prototype.resetTimeout = function()
|
||||
{
|
||||
clearTimeout(this.toID);
|
||||
var pointer = this;
|
||||
this.toID = setTimeout(function () { pointer.clearSuggestions() }, 1000);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.AutoSuggest.prototype.clearSuggestions = function ()
|
||||
{
|
||||
|
||||
this.killTimeout();
|
||||
|
||||
var ele = _bsn.DOM.getElement(this.idAs);
|
||||
var pointer = this;
|
||||
if (ele)
|
||||
{
|
||||
var fade = new _bsn.Fader(ele,1,0,250,function () { _bsn.DOM.removeElement(pointer.idAs) });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// AJAX PROTOTYPE _____________________________________________
|
||||
|
||||
|
||||
if (typeof(_bsn.Ajax) == "undefined")
|
||||
_bsn.Ajax = {}
|
||||
|
||||
|
||||
|
||||
_bsn.Ajax = function ()
|
||||
{
|
||||
this.req = {};
|
||||
this.isIE = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
_bsn.Ajax.prototype.makeRequest = function (url, meth, onComp, onErr)
|
||||
{
|
||||
|
||||
if (meth != "POST")
|
||||
meth = "GET";
|
||||
|
||||
this.onComplete = onComp;
|
||||
this.onError = onErr;
|
||||
|
||||
var pointer = this;
|
||||
|
||||
// branch for native XMLHttpRequest object
|
||||
if (window.XMLHttpRequest)
|
||||
{
|
||||
this.req = new XMLHttpRequest();
|
||||
this.req.onreadystatechange = function () { pointer.processReqChange() };
|
||||
this.req.open("GET", url, true); //
|
||||
this.req.send(null);
|
||||
// branch for IE/Windows ActiveX version
|
||||
}
|
||||
else if (window.ActiveXObject)
|
||||
{
|
||||
this.req = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
if (this.req)
|
||||
{
|
||||
this.req.onreadystatechange = function () { pointer.processReqChange() };
|
||||
this.req.open(meth, url, true);
|
||||
this.req.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_bsn.Ajax.prototype.processReqChange = function()
|
||||
{
|
||||
|
||||
// only if req shows "loaded"
|
||||
if (this.req.readyState == 4) {
|
||||
// only if "OK"
|
||||
if (this.req.status == 200)
|
||||
{
|
||||
this.onComplete( this.req );
|
||||
} else {
|
||||
this.onError( this.req.status );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// DOM PROTOTYPE _____________________________________________
|
||||
|
||||
|
||||
if (typeof(_bsn.DOM) == "undefined")
|
||||
_bsn.DOM = {}
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.createElement = function ( type, attr, cont, html )
|
||||
{
|
||||
var ne = document.createElement( type );
|
||||
if (!ne)
|
||||
return false;
|
||||
|
||||
for (var a in attr)
|
||||
ne[a] = attr[a];
|
||||
|
||||
if (typeof(cont) == "string" && !html)
|
||||
ne.appendChild( document.createTextNode(cont) );
|
||||
else if (typeof(cont) == "string" && html)
|
||||
ne.innerHTML = cont;
|
||||
else if (typeof(cont) == "object")
|
||||
ne.appendChild( cont );
|
||||
|
||||
return ne;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.clearElement = function ( id )
|
||||
{
|
||||
var ele = this.getElement( id );
|
||||
|
||||
if (!ele)
|
||||
return false;
|
||||
|
||||
while (ele.childNodes.length)
|
||||
ele.removeChild( ele.childNodes[0] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.removeElement = function ( ele )
|
||||
{
|
||||
var e = this.getElement(ele);
|
||||
|
||||
if (!e)
|
||||
return false;
|
||||
else if (e.parentNode.removeChild(e))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.replaceContent = function ( id, cont, html )
|
||||
{
|
||||
var ele = this.getElement( id );
|
||||
|
||||
if (!ele)
|
||||
return false;
|
||||
|
||||
this.clearElement( ele );
|
||||
|
||||
if (typeof(cont) == "string" && !html)
|
||||
ele.appendChild( document.createTextNode(cont) );
|
||||
else if (typeof(cont) == "string" && html)
|
||||
ele.innerHTML = cont;
|
||||
else if (typeof(cont) == "object")
|
||||
ele.appendChild( cont );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.getElement = function ( ele )
|
||||
{
|
||||
if (typeof(ele) == "undefined")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (typeof(ele) == "string")
|
||||
{
|
||||
var re = document.getElementById( ele );
|
||||
if (!re)
|
||||
return false;
|
||||
else if (typeof(re.appendChild) != "undefined" ) {
|
||||
return re;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (typeof(ele.appendChild) != "undefined")
|
||||
return ele;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.appendChildren = function ( id, arr )
|
||||
{
|
||||
var ele = this.getElement( id );
|
||||
|
||||
if (!ele)
|
||||
return false;
|
||||
|
||||
|
||||
if (typeof(arr) != "object")
|
||||
return false;
|
||||
|
||||
for (var i=0;i<arr.length;i++)
|
||||
{
|
||||
var cont = arr[i];
|
||||
if (typeof(cont) == "string")
|
||||
ele.appendChild( document.createTextNode(cont) );
|
||||
else if (typeof(cont) == "object")
|
||||
ele.appendChild( cont );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.DOM.getPos = function ( ele )
|
||||
{
|
||||
var ele = this.getElement(ele);
|
||||
|
||||
var obj = ele;
|
||||
|
||||
var curleft = 0;
|
||||
if (obj.offsetParent)
|
||||
{
|
||||
while (obj.offsetParent)
|
||||
{
|
||||
curleft += obj.offsetLeft
|
||||
obj = obj.offsetParent;
|
||||
}
|
||||
}
|
||||
else if (obj.x)
|
||||
curleft += obj.x;
|
||||
|
||||
|
||||
var obj = ele;
|
||||
|
||||
var curtop = 0;
|
||||
if (obj.offsetParent)
|
||||
{
|
||||
while (obj.offsetParent)
|
||||
{
|
||||
curtop += obj.offsetTop
|
||||
obj = obj.offsetParent;
|
||||
}
|
||||
}
|
||||
else if (obj.y)
|
||||
curtop += obj.y;
|
||||
|
||||
return {x:curleft, y:curtop}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// FADER PROTOTYPE _____________________________________________
|
||||
|
||||
|
||||
|
||||
if (typeof(_bsn.Fader) == "undefined")
|
||||
_bsn.Fader = {}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.Fader = function (ele, from, to, fadetime, callback)
|
||||
{
|
||||
if (!ele)
|
||||
return false;
|
||||
|
||||
this.ele = ele;
|
||||
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
|
||||
this.callback = callback;
|
||||
|
||||
this.nDur = fadetime;
|
||||
|
||||
this.nInt = 50;
|
||||
this.nTime = 0;
|
||||
|
||||
var p = this;
|
||||
this.nID = setInterval(function() { p._fade() }, this.nInt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
_bsn.Fader.prototype._fade = function()
|
||||
{
|
||||
this.nTime += this.nInt;
|
||||
|
||||
var ieop = Math.round( this._tween(this.nTime, this.from, this.to, this.nDur) * 100 );
|
||||
var op = ieop / 100;
|
||||
|
||||
if (this.ele.filters) // internet explorer
|
||||
{
|
||||
try
|
||||
{
|
||||
this.ele.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;
|
||||
} catch (e) {
|
||||
// If it is not set initially, the browser will throw an error. This will set it if it is not set yet.
|
||||
this.ele.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';
|
||||
}
|
||||
}
|
||||
else // other browsers
|
||||
{
|
||||
this.ele.style.opacity = op;
|
||||
}
|
||||
|
||||
|
||||
if (this.nTime == this.nDur)
|
||||
{
|
||||
clearInterval( this.nID );
|
||||
if (this.callback != undefined)
|
||||
this.callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
_bsn.Fader.prototype._tween = function(t,b,c,d)
|
||||
{
|
||||
return b + ( (c-b) * (t/d) );
|
||||
}
|
||||
@@ -276,7 +276,6 @@ class Revision(models.Model):
|
||||
# Create pre-parsed contents - no need to parse on-the-fly
|
||||
ext = WIKI_MARKDOWN_EXTENSIONS
|
||||
ext += ["wikipath(base_url=%s)" % reverse('wiki_view', args=('/',))]
|
||||
print ext
|
||||
self.contents_parsed = markdown(self.contents,
|
||||
extensions=ext,
|
||||
safe_mode='escape',)
|
||||
|
||||
@@ -154,10 +154,11 @@ def create(request, wiki_url):
|
||||
|
||||
d = {'wiki_form': f,
|
||||
'wiki_write': True,
|
||||
'create_article' : True,
|
||||
}
|
||||
d.update(csrf(request))
|
||||
|
||||
return render_to_response('simplewiki_create.html', d)
|
||||
return render_to_response('simplewiki_edit.html', d)
|
||||
|
||||
def edit(request, wiki_url):
|
||||
if not request.user.is_authenticated():
|
||||
@@ -207,6 +208,7 @@ def edit(request, wiki_url):
|
||||
'wiki_article': article,
|
||||
'wiki_title' : article.title,
|
||||
'wiki_attachments_write': article.can_attach(request.user),
|
||||
'create_article' : False,
|
||||
}
|
||||
d.update(csrf(request))
|
||||
|
||||
|
||||