Commit 3edd2867 by benjaoming

Adding possibility for Plugins to add media to rendering pages.

Adding advanced markdown extension for images.
Adding colorbox for images plugin to enlarge photos.
parent df4fd062
......@@ -22,9 +22,7 @@ def send_file(request, filepath, last_modified=None, filename=None):
response["Last-Modified"] = http_date(statobj.st_mtime)
else:
if isinstance(last_modified, datetime):
print last_modified
last_modified = float(dateformat.format(last_modified, 'U'))
print last_modified
response["Last-Modified"] = http_date(epoch_seconds=last_modified)
response["Content-Length"] = statobj.st_size
......
......@@ -31,7 +31,9 @@ class BasePlugin(object):
markdown_extensions = []
pass
class RenderMedia:
js = []
css = {}
class PluginSidebarFormMixin(object):
......
......@@ -69,7 +69,7 @@ class EditForm(forms.Form):
def clean(self):
cd = self.cleaned_data
if self.no_clean:
if self.no_clean or self.preview:
return cd
if not str(self.initial_revision.id) == str(self.presumed_revision):
raise forms.ValidationError(_(u'While you were editing, someone else changed the revision. Your contents have been automatically merged with the new contents. Please review the text below.'))
......@@ -245,7 +245,6 @@ class PermissionsForm(PluginSettingsFormMixin, forms.ModelForm):
self.user = user
kwargs['instance'] = article
super(PermissionsForm, self).__init__(*args, **kwargs)
print self.data
if user.has_perm("wiki.admin"):
self.fields['group'].queryset = models.Group.objects.all()
else:
......
......@@ -25,7 +25,7 @@ class AttachmentPreprocessor(markdown.preprocessors.Preprocessor):
if m:
attachment_id = m.group('id').strip()
try:
attachment = models.Attachment.objects.get(article=self.markdown.article,
attachment = models.Attachment.objects.get(articles=self.markdown.article,
id=attachment_id)
url = reverse('wiki:attachments_download', kwargs={'article_id': self.markdown.article.id,
'attachment_id':attachment.id,})
......
import markdown
import re
from django.template.loader import render_to_string
from django.template import Context
from wiki.core import article_markdown
IMAGE_RE = re.compile(r'.*(\[image\:(?P<id>\d+)\s+align\:(?P<align>right|left|center)\s*\]).*',
re.IGNORECASE)
from wiki.plugins.images import models
class ImageExtension(markdown.Extension):
""" Images plugin markdown extension for django-wiki. """
def extendMarkdown(self, md, md_globals):
""" Insert ImagePreprocessor before ReferencePreprocessor. """
md.preprocessors.add('dw-images', ImagePreprocessor(md), '>html_block')
class ImagePreprocessor(markdown.preprocessors.Preprocessor):
"""django-wiki image preprocessor - parse text for [image:id align:left|right|center] references. """
def run(self, lines):
new_text = []
previous_line_was_image = False
image = None
image_id = None
alignment = None
caption = ""
for line in lines:
m = IMAGE_RE.match(line)
if m:
previous_line_was_image = True
image_id = m.group('id').strip()
alignment = m.group('align').strip()
try:
image = models.Image.objects.get(article=self.markdown.article,
id=image_id)
except models.Image.DoesNotExist:
pass
line = line.replace(m.group(1), "")
elif previous_line_was_image:
print line
if line.startswith(" "):
caption += line[4:]
line = ""
else:
html = render_to_string("wiki/plugins/images/render.html",
Context({'image': image,
'caption': article_markdown(caption, self.markdown.article,
extensions=self.markdown.registeredExtensions),
'align': alignment}))
line = html + line
previous_line_was_image = False
new_text.append(line)
return new_text
// ColorBox v1.3.20 - jQuery lightbox plugin
// (c) 2012 Jack Moore - jacklmoore.com
// License: http://www.opensource.org/licenses/mit-license.php
(function(e,t,n){function G(n,r,i){var o=t.createElement(n);return r&&(o.id=s+r),i&&(o.style.cssText=i),e(o)}function Y(e){var t=T.length,n=(U+e)%t;return n<0?t+n:n}function Z(e,t){return Math.round((/%/.test(e)?(t==="x"?N.width():N.height())/100:1)*parseInt(e,10))}function et(e){return B.photo||/\.(gif|png|jp(e|g|eg)|bmp|ico)((#|\?).*)?$/i.test(e)}function tt(){var t,n=e.data(R,i);n==null?(B=e.extend({},r),console&&console.log&&console.log("Error: cboxElement missing settings object")):B=e.extend({},n);for(t in B)e.isFunction(B[t])&&t.slice(0,2)!=="on"&&(B[t]=B[t].call(R));B.rel=B.rel||R.rel||"nofollow",B.href=B.href||e(R).attr("href"),B.title=B.title||R.title,typeof B.href=="string"&&(B.href=e.trim(B.href))}function nt(t,n){e.event.trigger(t),n&&n.call(R)}function rt(){var e,t=s+"Slideshow_",n="click."+s,r,i,o;B.slideshow&&T[1]?(r=function(){M.text(B.slideshowStop).unbind(n).bind(f,function(){if(B.loop||T[U+1])e=setTimeout(J.next,B.slideshowSpeed)}).bind(a,function(){clearTimeout(e)}).one(n+" "+l,i),g.removeClass(t+"off").addClass(t+"on"),e=setTimeout(J.next,B.slideshowSpeed)},i=function(){clearTimeout(e),M.text(B.slideshowStart).unbind([f,a,l,n].join(" ")).one(n,function(){J.next(),r()}),g.removeClass(t+"on").addClass(t+"off")},B.slideshowAuto?r():i()):g.removeClass(t+"off "+t+"on")}function it(t){V||(R=t,tt(),T=e(R),U=0,B.rel!=="nofollow"&&(T=e("."+o).filter(function(){var t=e.data(this,i),n;return t&&(n=t.rel||this.rel),n===B.rel}),U=T.index(R),U===-1&&(T=T.add(R),U=T.length-1)),W||(W=X=!0,g.show(),B.returnFocus&&e(R).blur().one(c,function(){e(this).focus()}),m.css({opacity:+B.opacity,cursor:B.overlayClose?"pointer":"auto"}).show(),B.w=Z(B.initialWidth,"x"),B.h=Z(B.initialHeight,"y"),J.position(),d&&N.bind("resize."+v+" scroll."+v,function(){m.css({width:N.width(),height:N.height(),top:N.scrollTop(),left:N.scrollLeft()})}).trigger("resize."+v),nt(u,B.onOpen),H.add(A).hide(),P.html(B.close).show()),J.load(!0))}function st(){!g&&t.body&&(Q=!1,N=e(n),g=G(K).attr({id:i,"class":p?s+(d?"IE6":"IE"):""}).hide(),m=G(K,"Overlay",d?"position:absolute":"").hide(),y=G(K,"Wrapper"),b=G(K,"Content").append(C=G(K,"LoadedContent","width:0; height:0; overflow:hidden"),L=G(K,"LoadingOverlay").add(G(K,"LoadingGraphic")),A=G(K,"Title"),O=G(K,"Current"),_=G(K,"Next"),D=G(K,"Previous"),M=G(K,"Slideshow").bind(u,rt),P=G(K,"Close")),y.append(G(K).append(G(K,"TopLeft"),w=G(K,"TopCenter"),G(K,"TopRight")),G(K,!1,"clear:left").append(E=G(K,"MiddleLeft"),b,S=G(K,"MiddleRight")),G(K,!1,"clear:left").append(G(K,"BottomLeft"),x=G(K,"BottomCenter"),G(K,"BottomRight"))).find("div div").css({"float":"left"}),k=G(K,!1,"position:absolute; width:9999px; visibility:hidden; display:none"),H=_.add(D).add(O).add(M),e(t.body).append(m,g.append(y,k)))}function ot(){return g?(Q||(Q=!0,j=w.height()+x.height()+b.outerHeight(!0)-b.height(),F=E.width()+S.width()+b.outerWidth(!0)-b.width(),I=C.outerHeight(!0),q=C.outerWidth(!0),g.css({"padding-bottom":j,"padding-right":F}),_.click(function(){J.next()}),D.click(function(){J.prev()}),P.click(function(){J.close()}),m.click(function(){B.overlayClose&&J.close()}),e(t).bind("keydown."+s,function(e){var t=e.keyCode;W&&B.escKey&&t===27&&(e.preventDefault(),J.close()),W&&B.arrowKey&&T[1]&&(t===37?(e.preventDefault(),D.click()):t===39&&(e.preventDefault(),_.click()))}),e("."+o,t).live("click",function(e){e.which>1||e.shiftKey||e.altKey||e.metaKey||(e.preventDefault(),it(this))})),!0):!1}var r={transition:"elastic",speed:300,width:!1,initialWidth:"600",innerWidth:!1,maxWidth:!1,height:!1,initialHeight:"450",innerHeight:!1,maxHeight:!1,scalePhotos:!0,scrolling:!0,inline:!1,html:!1,iframe:!1,fastIframe:!0,photo:!1,href:!1,title:!1,rel:!1,opacity:.9,preloading:!0,current:"image {current} of {total}",previous:"previous",next:"next",close:"close",xhrError:"This content failed to load.",imgError:"This image failed to load.",open:!1,returnFocus:!0,reposition:!0,loop:!0,slideshow:!1,slideshowAuto:!0,slideshowSpeed:2500,slideshowStart:"start slideshow",slideshowStop:"stop slideshow",onOpen:!1,onLoad:!1,onComplete:!1,onCleanup:!1,onClosed:!1,overlayClose:!0,escKey:!0,arrowKey:!0,top:!1,bottom:!1,left:!1,right:!1,fixed:!1,data:undefined},i="colorbox",s="cbox",o=s+"Element",u=s+"_open",a=s+"_load",f=s+"_complete",l=s+"_cleanup",c=s+"_closed",h=s+"_purge",p=!e.support.opacity&&!e.support.style,d=p&&!n.XMLHttpRequest,v=s+"_IE6",m,g,y,b,w,E,S,x,T,N,C,k,L,A,O,M,_,D,P,H,B,j,F,I,q,R,U,z,W,X,V,$,J,K="div",Q;if(e.colorbox)return;e(st),J=e.fn[i]=e[i]=function(t,n){var s=this;t=t||{},st();if(ot()){if(!s[0]){if(s.selector)return s;s=e("<a/>"),t.open=!0}n&&(t.onComplete=n),s.each(function(){e.data(this,i,e.extend({},e.data(this,i)||r,t))}).addClass(o),(e.isFunction(t.open)&&t.open.call(s)||t.open)&&it(s[0])}return s},J.position=function(e,t){function f(e){w[0].style.width=x[0].style.width=b[0].style.width=e.style.width,b[0].style.height=E[0].style.height=S[0].style.height=e.style.height}var n,r=0,i=0,o=g.offset(),u,a;N.unbind("resize."+s),g.css({top:-9e4,left:-9e4}),u=N.scrollTop(),a=N.scrollLeft(),B.fixed&&!d?(o.top-=u,o.left-=a,g.css({position:"fixed"})):(r=u,i=a,g.css({position:"absolute"})),B.right!==!1?i+=Math.max(N.width()-B.w-q-F-Z(B.right,"x"),0):B.left!==!1?i+=Z(B.left,"x"):i+=Math.round(Math.max(N.width()-B.w-q-F,0)/2),B.bottom!==!1?r+=Math.max(N.height()-B.h-I-j-Z(B.bottom,"y"),0):B.top!==!1?r+=Z(B.top,"y"):r+=Math.round(Math.max(N.height()-B.h-I-j,0)/2),g.css({top:o.top,left:o.left}),e=g.width()===B.w+q&&g.height()===B.h+I?0:e||0,y[0].style.width=y[0].style.height="9999px",n={width:B.w+q,height:B.h+I,top:r,left:i},e===0&&g.css(n),g.dequeue().animate(n,{duration:e,complete:function(){f(this),X=!1,y[0].style.width=B.w+q+F+"px",y[0].style.height=B.h+I+j+"px",B.reposition&&setTimeout(function(){N.bind("resize."+s,J.position)},1),t&&t()},step:function(){f(this)}})},J.resize=function(e){W&&(e=e||{},e.width&&(B.w=Z(e.width,"x")-q-F),e.innerWidth&&(B.w=Z(e.innerWidth,"x")),C.css({width:B.w}),e.height&&(B.h=Z(e.height,"y")-I-j),e.innerHeight&&(B.h=Z(e.innerHeight,"y")),!e.innerHeight&&!e.height&&(C.css({height:"auto"}),B.h=C.height()),C.css({height:B.h}),J.position(B.transition==="none"?0:B.speed))},J.prep=function(t){function o(){return B.w=B.w||C.width(),B.w=B.mw&&B.mw<B.w?B.mw:B.w,B.w}function u(){return B.h=B.h||C.height(),B.h=B.mh&&B.mh<B.h?B.mh:B.h,B.h}if(!W)return;var n,r=B.transition==="none"?0:B.speed;C.remove(),C=G(K,"LoadedContent").append(t),C.hide().appendTo(k.show()).css({width:o(),overflow:B.scrolling?"auto":"hidden"}).css({height:u()}).prependTo(b),k.hide(),e(z).css({"float":"none"}),d&&e("select").not(g.find("select")).filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one(l,function(){this.style.visibility="inherit"}),n=function(){function y(){p&&g[0].style.removeAttribute("filter")}var t,n,o=T.length,u,a="frameBorder",l="allowTransparency",c,d,v,m;if(!W)return;c=function(){clearTimeout($),L.hide(),nt(f,B.onComplete)},p&&z&&C.fadeIn(100),A.html(B.title).add(C).show();if(o>1){typeof B.current=="string"&&O.html(B.current.replace("{current}",U+1).replace("{total}",o)).show(),_[B.loop||U<o-1?"show":"hide"]().html(B.next),D[B.loop||U?"show":"hide"]().html(B.previous),B.slideshow&&M.show();if(B.preloading){t=[Y(-1),Y(1)];while(n=T[t.pop()])m=e.data(n,i),m&&m.href?(d=m.href,e.isFunction(d)&&(d=d.call(n))):d=n.href,et(d)&&(v=new Image,v.src=d)}}else H.hide();B.iframe?(u=G("iframe")[0],a in u&&(u[a]=0),l in u&&(u[l]="true"),u.name=s+ +(new Date),B.fastIframe?c():e(u).one("load",c),u.src=B.href,B.scrolling||(u.scrolling="no"),e(u).addClass(s+"Iframe").appendTo(C).one(h,function(){u.src="//about:blank"})):c(),B.transition==="fade"?g.fadeTo(r,1,y):y()},B.transition==="fade"?g.fadeTo(r,0,function(){J.position(0,n)}):J.position(r,n)},J.load=function(t){var n,r,i=J.prep;X=!0,z=!1,R=T[U],t||tt(),nt(h),nt(a,B.onLoad),B.h=B.height?Z(B.height,"y")-I-j:B.innerHeight&&Z(B.innerHeight,"y"),B.w=B.width?Z(B.width,"x")-q-F:B.innerWidth&&Z(B.innerWidth,"x"),B.mw=B.w,B.mh=B.h,B.maxWidth&&(B.mw=Z(B.maxWidth,"x")-q-F,B.mw=B.w&&B.w<B.mw?B.w:B.mw),B.maxHeight&&(B.mh=Z(B.maxHeight,"y")-I-j,B.mh=B.h&&B.h<B.mh?B.h:B.mh),n=B.href,$=setTimeout(function(){L.show()},100),B.inline?(G(K).hide().insertBefore(e(n)[0]).one(h,function(){e(this).replaceWith(C.children())}),i(e(n))):B.iframe?i(" "):B.html?i(B.html):et(n)?(e(z=new Image).addClass(s+"Photo").error(function(){B.title=!1,i(G(K,"Error").html(B.imgError))}).load(function(){var e;z.onload=null,B.scalePhotos&&(r=function(){z.height-=z.height*e,z.width-=z.width*e},B.mw&&z.width>B.mw&&(e=(z.width-B.mw)/z.width,r()),B.mh&&z.height>B.mh&&(e=(z.height-B.mh)/z.height,r())),B.h&&(z.style.marginTop=Math.max(B.h-z.height,0)/2+"px"),T[1]&&(B.loop||T[U+1])&&(z.style.cursor="pointer",z.onclick=function(){J.next()}),p&&(z.style.msInterpolationMode="bicubic"),setTimeout(function(){i(z)},1)}),setTimeout(function(){z.src=n},1)):n&&k.load(n,B.data,function(t,n,r){i(n==="error"?G(K,"Error").html(B.xhrError):e(this).contents())})},J.next=function(){!X&&T[1]&&(B.loop||T[U+1])&&(U=Y(1),J.load())},J.prev=function(){!X&&T[1]&&(B.loop||U)&&(U=Y(-1),J.load())},J.close=function(){W&&!V&&(V=!0,W=!1,nt(l,B.onCleanup),N.unbind("."+s+" ."+v),m.fadeTo(200,0),g.stop().fadeTo(300,0,function(){g.add(m).css({opacity:1,cursor:"auto"}).hide(),nt(h),C.remove(),setTimeout(function(){V=!1,nt(c,B.onClosed)},1)}))},J.remove=function(){e([]).add(g).add(m).remove(),g=null,e("."+o).removeData(i).removeClass(o).die()},J.element=function(){return e(R)},J.settings=r})(jQuery,document,this);
\ No newline at end of file
<div id='homer' style="background:url(../content/homer.jpg) right center no-repeat #ececec; height:135px; width:280px; padding:30px 10px;">
<strong>Homer</strong><br/>
<em>\noun\</em><br/>
<strong>1.</strong> American bonehead<br/>
<strong>2. Pull a Homer-</strong><br/>
to succeed despite<br/>
idiocy
</div>
<script>
$('#homer strong').css({color:'red'});
</script>
\ No newline at end of file
<div style="width:504px; height:412px; overflow:hidden;">
<object>
<param name="allowfullscreen" value="true" /><param name="wmode" value="opaque" />
<param name="allowscriptaccess" value="always" />
<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=2285902&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" />
<embed src="http://vimeo.com/moogaloop.swf?clip_id=2285902&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00ADEF&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" wmode="opaque" allowscriptaccess="always" width="504" height="412"></embed>
</object>
</div>
\ No newline at end of file
/*
ColorBox Core Style:
The following CSS is consistent between example themes and should not be altered.
*/
#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
#cboxOverlay{position:fixed; width:100%; height:100%;}
#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
#cboxContent{position:relative;}
#cboxLoadedContent{overflow:auto;}
#cboxTitle{margin:0;}
#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none;}
.cboxIframe{width:100%; height:100%; display:block; border:0;}
#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box;}
/*
User Style:
Change the following styles to modify the appearance of ColorBox. They are
ordered & tabbed in a way that represents the nesting of the generated HTML.
*/
#cboxOverlay{background:url(images/overlay.png) repeat 0 0;}
#colorbox{}
#cboxTopLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px 0;}
#cboxTopRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px 0;}
#cboxBottomLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px -29px;}
#cboxBottomRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px -29px;}
#cboxMiddleLeft{width:21px; background:url(images/controls.png) left top repeat-y;}
#cboxMiddleRight{width:21px; background:url(images/controls.png) right top repeat-y;}
#cboxTopCenter{height:21px; background:url(images/border.png) 0 0 repeat-x;}
#cboxBottomCenter{height:21px; background:url(images/border.png) 0 -29px repeat-x;}
#cboxContent{background:#fff; overflow:hidden;}
.cboxIframe{background:#fff;}
#cboxError{padding:50px; border:1px solid #ccc;}
#cboxLoadedContent{margin-bottom:28px;}
#cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;}
#cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;}
#cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;}
#cboxPrevious{position:absolute; bottom:0; left:0; background:url(images/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;}
#cboxPrevious:hover{background-position:-75px -25px;}
#cboxNext{position:absolute; bottom:0; left:27px; background:url(images/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;}
#cboxNext:hover{background-position:-50px -25px;}
#cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;}
#cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
#cboxClose{position:absolute; bottom:0; right:0; background:url(images/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;}
#cboxClose:hover{background-position:-25px -25px;}
/*
The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
See: http://jacklmoore.com/notes/ie-transparency-problems/
*/
.cboxIE #cboxTopLeft,
.cboxIE #cboxTopCenter,
.cboxIE #cboxTopRight,
.cboxIE #cboxBottomLeft,
.cboxIE #cboxBottomCenter,
.cboxIE #cboxBottomRight,
.cboxIE #cboxMiddleLeft,
.cboxIE #cboxMiddleRight {
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
}
/*
The following provides PNG transparency support for IE6
Feel free to remove this and the /ie6/ directory if you have dropped IE6 support.
*/
.cboxIE6 #cboxTopLeft{background:url(images/ie6/borderTopLeft.png);}
.cboxIE6 #cboxTopCenter{background:url(images/ie6/borderTopCenter.png);}
.cboxIE6 #cboxTopRight{background:url(images/ie6/borderTopRight.png);}
.cboxIE6 #cboxBottomLeft{background:url(images/ie6/borderBottomLeft.png);}
.cboxIE6 #cboxBottomCenter{background:url(images/ie6/borderBottomCenter.png);}
.cboxIE6 #cboxBottomRight{background:url(images/ie6/borderBottomRight.png);}
.cboxIE6 #cboxMiddleLeft{background:url(images/ie6/borderMiddleLeft.png);}
.cboxIE6 #cboxMiddleRight{background:url(images/ie6/borderMiddleRight.png);}
.cboxIE6 #cboxTopLeft,
.cboxIE6 #cboxTopCenter,
.cboxIE6 #cboxTopRight,
.cboxIE6 #cboxBottomLeft,
.cboxIE6 #cboxBottomCenter,
.cboxIE6 #cboxBottomRight,
.cboxIE6 #cboxMiddleLeft,
.cboxIE6 #cboxMiddleRight {
_behavior: expression(this.src = this.src ? this.src : this.currentStyle.backgroundImage.split('"')[1], this.style.background = "none", this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + this.src + ", sizingMethod='scale')");
}
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'/>
<title>ColorBox Examples</title>
<style>
body{font:12px/1.2 Verdana, sans-serif; padding:0 10px;}
a:link, a:visited{text-decoration:none; color:#416CE5; border-bottom:1px solid #416CE5;}
h2{font-size:13px; margin:15px 0 0 0;}
</style>
<link rel="stylesheet" href="colorbox.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="../colorbox/jquery.colorbox.js"></script>
<script>
$(document).ready(function(){
//Examples of how to assign the ColorBox event to elements
$(".group1").colorbox({rel:'group1'});
$(".group2").colorbox({rel:'group2', transition:"fade"});
$(".group3").colorbox({rel:'group3', transition:"none", width:"75%", height:"75%"});
$(".group4").colorbox({rel:'group4', slideshow:true});
$(".ajax").colorbox();
$(".youtube").colorbox({iframe:true, innerWidth:425, innerHeight:344});
$(".iframe").colorbox({iframe:true, width:"80%", height:"80%"});
$(".inline").colorbox({inline:true, width:"50%"});
$(".callbacks").colorbox({
onOpen:function(){ alert('onOpen: colorbox is about to open'); },
onLoad:function(){ alert('onLoad: colorbox has started to load the targeted content'); },
onComplete:function(){ alert('onComplete: colorbox has displayed the loaded content'); },
onCleanup:function(){ alert('onCleanup: colorbox has begun the close process'); },
onClosed:function(){ alert('onClosed: colorbox has completely closed'); }
});
//Example of preserving a JavaScript event for inline calls.
$("#click").click(function(){
$('#click').css({"background-color":"#f00", "color":"#fff", "cursor":"inherit"}).text("Open this window again and this message will still be here.");
return false;
});
});
</script>
</head>
<body>
<h1>ColorBox Demonstration</h1>
<h2>Elastic Transition</h2>
<p><a class="group1" href="../content/ohoopee1.jpg" title="Me and my grandfather on the Ohoopee.">Grouped Photo 1</a></p>
<p><a class="group1" href="../content/ohoopee2.jpg" title="On the Ohoopee as a child">Grouped Photo 2</a></p>
<p><a class="group1" href="../content/ohoopee3.jpg" title="On the Ohoopee as an adult">Grouped Photo 3</a></p>
<h2>Fade Transition</h2>
<p><a class="group2" href="../content/ohoopee1.jpg" title="Me and my grandfather on the Ohoopee">Grouped Photo 1</a></p>
<p><a class="group2" href="../content/ohoopee2.jpg" title="On the Ohoopee as a child">Grouped Photo 2</a></p>
<p><a class="group2" href="../content/ohoopee3.jpg" title="On the Ohoopee as an adult">Grouped Photo 3</a></p>
<h2>No Transition + fixed width and height (75% of screen size)</h2>
<p><a class="group3" href="../content/ohoopee1.jpg" title="Me and my grandfather on the Ohoopee.">Grouped Photo 1</a></p>
<p><a class="group3" href="../content/ohoopee2.jpg" title="On the Ohoopee as a child">Grouped Photo 2</a></p>
<p><a class="group3" href="../content/ohoopee3.jpg" title="On the Ohoopee as an adult">Grouped Photo 3</a></p>
<h2>Slideshow</h2>
<p><a class="group4" href="../content/ohoopee1.jpg" title="Me and my grandfather on the Ohoopee.">Grouped Photo 1</a></p>
<p><a class="group4" href="../content/ohoopee2.jpg" title="On the Ohoopee as a child">Grouped Photo 2</a></p>
<p><a class="group4" href="../content/ohoopee3.jpg" title="On the Ohoopee as an adult">Grouped Photo 3</a></p>
<h2>Other Content Types</h2>
<p><a class='ajax' href="../content/ajax.html" title="Homer Defined">Outside HTML (Ajax)</a></p>
<p><a class='ajax' href="../content/flash.html" title="Royksopp: Remind Me">Flash / Video (Ajax/Embedded)</a></p>
<p><a class='youtube' href="http://www.youtube.com/embed/617ANIA5Rqs?rel=0&amp;wmode=transparent" title="The Knife: We Share Our Mother's Health">Flash / Video (Iframe/Direct Link To YouTube)</a></p>
<p><a class='iframe' href="http://threadless.com">Outside Webpage (Iframe)</a></p>
<p><a class='inline' href="#inline_content">Inline HTML</a></p>
<h2>Demonstration of using callbacks</h2>
<p><a class='callbacks' href="../content/marylou.jpg" title="Marylou on Cumberland Island">Example with alerts</a>. Callbacks and event-hooks allow users to extend functionality without having to rewrite parts of the plugin.</p>
<!-- This contains the hidden content for inline calls -->
<div style='display:none'>
<div id='inline_content' style='padding:10px; background:#fff;'>
<p><strong>This content comes from a hidden element on this page.</strong></p>
<p>The inline option preserves bound JavaScript events and changes, and it puts the content back where it came from when it is closed.</p>
<p><a id="click" href="#" style='padding:5px; background:#ccc;'>Click me, it will be preserved!</a></p>
<p><strong>If you try to open a new ColorBox while it is already open, it will update itself with the new content.</strong></p>
<p>Updating Content Example:<br />
<a class="ajax" href="../content/flash.html">Click here to load new content</a></p>
</div>
</div>
</body>
</html>
\ No newline at end of file
$(document).ready(function() {
$('.wiki-article .thumbnail a').colorbox();
});
{% load thumbnail %}
{% comment %}
This template is used for the markdown extension that renders images and captions
{% endcomment %}
{% with image.current_revision.imagerevision as revision %}
<div class="pull-{{ align }}" style="width: 250px; margin: 10px;">
<div class="thumbnail">
{% thumbnail revision.image "250x250" as thumb %}
<a href="{{ revision.image.url }}">
<img src="{{ thumb.url }}" alt="{{ revision.get_filename }}" />
</a>
<div class="caption">
{{ caption|safe }}
</div>
{% endthumbnail %}
</div>
</div>
{% endwith %}
{% load i18n wiki_tags wiki_images_tags humanize thumbnail %}
{% load url from future %}
<script type="text/javascript">
function insert_image(image_id) {
align=prompt('Enter an alignment. \'left\', \'right\' or \'center\':', 'right');
caption=prompt('Enter a caption text. You may use markdown. You can edit the text after...');
$('#id_content').insertAtCaret('\n[image:'+image_id+' align:'+align+']\n '+caption+'\n\n');
}
</script>
{% with article|images_for_article as images %}
<style type="text/css">
#image-list tr:first-child td {border:0;}
......@@ -12,9 +20,9 @@
{% thumbnail revision.image "50x50" crop="center" as thumb %}
<tr>
<td style="white-space: nowrap;">
<p>{{ revision.get_filename|truncatechars:30 }}</p>
<p>{% trans "Image id" %}: {{ image.id }}</code></p>
<p>
<a href=""><span class="icon-edit"></span> {% trans "Insert" %}</a><br />
<a href="javascript:void(insert_image({{ image.id }}))"><span class="icon-edit"></span> {% trans "Insert" %}</a><br />
{% if image|can_write:user %}
<a href="{% url 'wiki:images_add_revision' path=urlpath.path article_id=article.id image_id=image.id %}"><span class="icon-edit"></span> {% trans "Replace" %}</a>
{% endif %}
......@@ -99,7 +107,10 @@
{% trans "How to use images" %}
</h4>
<p>{% trans "After uploading an image, it is attached to this particular artice and can be used only here. Other users may replace the image, but older versions are kept. You probably want to show the image with a nice caption. To achieve this, press the Insert button and fill in the caption fields and possibly choose to have you image floating right or left of the content. You can use Markdown in the caption. The markdown code syntax for images looks like this:" %}<br /><code>[image:id alignment caption text]</code></p>
<p>{% trans "After uploading an image, it is attached to this particular artice and can be used only here. Other users may replace the image, but older versions are kept. You probably want to show the image with a nice caption. To achieve this, press the Insert button and fill in the caption fields and possibly choose to have you image floating right or left of the content. You can use Markdown in the caption. The markdown code syntax for images looks like this, possible values for align are left/center/right:" %}<br />
<pre>[image:id align:right]
caption indented by 4 spaces</pre>
</p>
{% endwith %}
......@@ -6,6 +6,7 @@ from wiki.core.plugins import registry
from wiki.core.plugins.base import BasePlugin
from wiki.plugins.images import views, models, settings, forms
from wiki.plugins.notifications import ARTICLE_EDIT
from wiki.plugins.images.markdown_extensions import ImageExtension
class ImagePlugin(BasePlugin):
......@@ -31,6 +32,14 @@ class ImagePlugin(BasePlugin):
'get_article': lambda obj: obj.article}
]
class RenderMedia:
js = [
'wiki/colorbox/colorbox/jquery.colorbox-min.js',
'wiki/js/images.js',
]
css = {'screen': 'wiki/colorbox/example1/colorbox.css'}
urlpatterns = patterns('',
url('^$', views.ImageView.as_view(), name='images_index'),
url('^delete/(?P<image_id>\d+)/$', views.DeleteView.as_view(), name='images_delete'),
......@@ -39,7 +48,7 @@ class ImagePlugin(BasePlugin):
url('^(?P<image_id>\d+)/revision/add/$', views.RevisionAddView.as_view(), name='images_add_revision'),
)
#markdown_extensions = [AttachmentExtension()]
markdown_extensions = [ImageExtension()]
def __init__(self):
#print "I WAS LOADED!"
......
$.fn.extend({
insertAtCaret: function(myValue){
return this.each(function(i) {
if (document.selection) {
//For browsers like Internet Explorer
this.focus();
sel = document.selection.createRange();
sel.text = myValue;
this.focus();
}
else if (this.selectionStart || this.selectionStart == '0') {
//For browsers like Firefox and Webkit based
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos)+myValue+this.value.substring(endPos,this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
} else {
this.value += myValue;
this.focus();
}
})
}
});
{% load sekizai_tags %}
{% addtoblock "js" %}
<script type="text/javascript" src="{{ STATIC_URL }}wiki/js/editor.js"></script>
{% for js in editor.Media.js %}
<script type="text/javascript" src="{{ STATIC_URL }}{{ js }}"></script>
{% endfor %}
......
{% load wiki_tags i18n cache %}
{% block wiki_contents %}
{% for plugin in plugins %}
{% if plugin.RenderMedia.css %}
{% for media, url in plugin.RenderMedia.css.items %}
<link rel="stylesheet" href="{{ STATIC_URL }}{{ url }}" />
{% endfor %}
{% endif %}
{% if plugin.RenderMedia.js %}
{% for url in plugin.RenderMedia.js %}
<script type="text/javascript" src="{{ STATIC_URL }}{{ url }}"></script>
{% endfor %}
{% endif %}
{% endfor %}
<div class="wiki-article">
{% if not preview %}
{% if article.current_revision %}
{% cache 1 article article.current_revision.id %}
{{ article.render }}
{% endcache %}
{% endif %}
{% if article.current_revision %}
{% cache 1 article article.current_revision.id %}
{{ article.render }}
{% endcache %}
{% endif %}
{% else %}
{{ content|default:"" }}
{% endif %}
</div>
{% endblock %}
from django.conf import settings as django_settings
from django import template
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model
......@@ -6,6 +7,7 @@ from django.forms import BaseForm
register = template.Library()
from wiki import models
from wiki.core.plugins import registry as plugin_registry
# Cache for looking up objects for articles... article_for_object is
# called more than once per page in multiple template blocks.
......@@ -39,6 +41,8 @@ def wiki_render(article, preview_content=None):
'article': article,
'content': content,
'preview': not preview_content is None,
'plugins': plugin_registry.get_plugins(),
'STATIC_URL': django_settings.STATIC_URL,
}
@register.inclusion_tag('wiki/includes/form.html', takes_context=True)
......
......@@ -21,7 +21,7 @@ if settings.ACCOUNT_HANDLING:
urlpatterns += patterns('',
# This one doesn't work because it don't know where to redirect after...
url('^_revision/change/(?P<article_id>\d+)/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision'),
url('^_revision/preview/(?P<article_id>\d+)/$', 'wiki.views.article.preview', name='preview_revision'),
url('^_revision/preview/(?P<article_id>\d+)/$', article.Preview.as_view(), name='preview_revision'),
url('^_revision/merge/(?P<article_id>\d+)/(?P<revision_id>\d+)/preview/$', 'wiki.views.article.merge', name='merge_revision_preview', kwargs={'preview': True}),
# Paths decided by article_ids
......@@ -29,7 +29,7 @@ urlpatterns += patterns('',
url('^(?P<article_id>\d+)/delete/$', article.Delete.as_view(), name='delete'),
url('^(?P<article_id>\d+)/deleted/$', article.Deleted.as_view(), name='deleted'),
url('^(?P<article_id>\d+)/edit/$', article.Edit.as_view(), name='edit'),
url('^(?P<article_id>\d+)/preview/$', 'wiki.views.article.preview', name='preview'),
url('^(?P<article_id>\d+)/preview/$', article.Preview.as_view(), name='preview'),
url('^(?P<article_id>\d+)/history/$', article.History.as_view(), name='history'),
url('^(?P<article_id>\d+)/settings/$', article.Settings.as_view(), name='settings'),
url('^(?P<article_id>\d+)/revision/change/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision'),
......@@ -53,7 +53,7 @@ urlpatterns += patterns('',
url('^(?P<path>.+/|)_delete/$', article.Delete.as_view(), name='delete'),
url('^(?P<path>.+/|)_deleted/$', article.Deleted.as_view(), name='deleted'),
url('^(?P<path>.+/|)_edit/$', article.Edit.as_view(), name='edit'),
url('^(?P<path>.+/|)_preview/$', 'wiki.views.article.preview', name='preview'),
url('^(?P<path>.+/|)_preview/$', article.Preview.as_view(), name='preview'),
url('^(?P<path>.+/|)_history/$', article.History.as_view(), name='history'),
url('^(?P<path>.+/|)_settings/$', article.Settings.as_view(), name='settings'),
url('^(?P<path>.+/|)_revision/change/(?P<revision_id>\d+)/$', 'wiki.views.article.change_revision', name='change_revision'),
......
......@@ -233,7 +233,7 @@ class Edit(FormView, ArticleMixin):
otherwise removes the 'data' and 'files' kwargs from form initialisation.
"""
kwargs = self.get_form_kwargs()
if self.request.POST.get('save', '') != '1':
if self.request.POST.get('save', '') != '1' and self.request.POST.get('preview') != '1':
kwargs['data'] = None
kwargs['files'] = None
kwargs['no_clean'] = True
......@@ -466,33 +466,42 @@ def change_revision(request, article, revision_id=None, urlpath=None):
else:
return redirect('wiki:history', article_id=article.id)
# TODO: Throw in a class-based view
@get_article(can_read=True)
def preview(request, article, urlpath=None, template_file="wiki/preview_inline.html"):
class Preview(ArticleMixin, TemplateView):
content = article.current_revision.content
title = article.current_revision.title
template_name="wiki/preview_inline.html"
revision_id = request.GET.get('r', None)
revision = None
@method_decorator(get_article(can_read=True))
def dispatch(self, request, article, *args, **kwargs):
revision_id = request.GET.get('r', None)
self.title = None
self.content = None
self.preview = False
if revision_id:
self.revision = get_object_or_404(models.ArticleRevision, article=article, id=revision_id)
else:
self.revision = None
return super(Preview, self).dispatch(request, article, *args, **kwargs)
if request.method == 'POST':
edit_form = forms.EditForm(article.current_revision, request.POST, preview=True)
def post(self, request, *args, **kwargs):
edit_form = forms.EditForm(self.article.current_revision, request.POST, preview=True)
if edit_form.is_valid():
title = edit_form.cleaned_data['title']
content = edit_form.cleaned_data['content']
elif revision_id:
revision = get_object_or_404(models.ArticleRevision, article=article, id=revision_id)
title = revision.title
content = revision.content
c = RequestContext(request, {'urlpath': urlpath,
'article': article,
'title': title,
'revision': revision,
'content': content})
return render_to_response(template_file, context_instance=c)
self.title = edit_form.cleaned_data['title']
self.content = edit_form.cleaned_data['content']
self.preview = True
return super(Preview, self).get(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
self.title = self.revision.title
self.content = self.revision.content
return super(Preview, self).get( request, *args, **kwargs)
def get_context_data(self, **kwargs):
kwargs['title'] = self.title
kwargs['revision'] = self.revision
kwargs['content'] = self.content
kwargs['preview'] = self.preview
return super(Preview, self).get_context_data(**kwargs)
@json_view
def diff(request, revision_id, other_revision_id=None):
......
......@@ -23,5 +23,6 @@ class ArticleMixin(TemplateResponseMixin):
kwargs['article_tabs'] = registry.get_article_tabs()
kwargs['children_slice'] = self.children_slice[:20]
kwargs['children_slice_more'] = len(self.children_slice) > 20
kwargs['plugins'] = registry.get_plugins()
return kwargs
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment