Commits

Olemis Lang committed 5def019

TracMac: Ready-to-use vertical dock menu.

Comments (0)

Files changed (10)

 
 Outstanding tasks are :
 
-- Add icon for `more` item in metanav.
 - Add icon (apple) for active item in navs.
 - Change icon for `About Trac` item in metanav.
-- Add definitive mage for first letter.
+- Add definitive image for first letter.
 - Add image for blockquotes.
 - Add image for external links.
 - Add styles for buttons.
 - Render .menu li(s) using display: block rule.
 - Do not render roadmap progress bar in yellow background.
 - Add timeline icons.
-- Add further toolbar icons.
+- Design further toolbar icons.
 - Add `more` drop-down menu in toolbar for missing mainnav items.
 - Implement toolbar search icon.
 - Hide & show main toolbar.
+- Change style of toolbar mainnav items on hover.
+- Design further docknav icons.
 

tracmacos/htdocs/dk_admin.png

Added
New image

tracmacos/htdocs/dk_default.png

Added
New image

tracmacos/htdocs/dk_milestone.png

Added
New image

tracmacos/htdocs/dk_search.png

Added
New image

tracmacos/htdocs/dk_wiki.png

Added
New image

tracmacos/htdocs/jquery.jqDock.min.js

+/*
+ jquery.jqDock.js v1.4 
+*/
+(function(h,q){if(!h.jqDock){var o=["Top","Right","Bottom","Left"],H={src:"Source",altsrc:"AltSource"},w=['<div style="position:relative;padding:0;',"margin:0;border:0 none;background-color:transparent;",'">'],t={v:{wh:"height",xy:1,tl:"top",lead:o[0],trail:o[2],act:"TransInv"},h:{wh:"width",xy:0,tl:"left",lead:o[3],trail:o[1],act:"Trans"}},m=[],A=[0,0],I=function(c){return(c=h(c).attr("alt"))&&c.match(/\.(gif|jpg|jpeg|png)$/i)?c:false},v=function(c){c=parseInt(c,10);return isNaN(c)?0:c},B=function(c){var d=
+c.Opts.vh,a=0;if(c=c.Current!==false?c.Elem[c.Current]:0){a=c.Pad[d.lead]+c.Pad[d.trail];a=Math.floor((A[d.xy]-c.Wrap.parent().offset()[d.tl])*(a+c.Initial)/(a+c.Trans))+c.Offset}return a},C=function(c,d,a){var b={},e=t[a.vh].wh;a=t[a.inv].wh;b[e]=d;b[a]=Math.round(d*c[a]/c[e]);return b},x=function(c){var d=c.Opts.labels,a=c.Opts.vh,b={},e;if(d&&c.Current!==false&&/[mc]/.test(d)){d=d.split("");c=c.Elem[c.Current];e=c.Label;if(d[0]=="m")b.top=Math.floor((c[a.inv.act]-e.height-e.heightPad)/2);if(d[1]==
+"c")b.left=Math.floor((c[a.act]-e.width-e.widthPad)/2);e.el.css(b)}},D=function(c){for(var d=c.childNodes.length,a;d;){a=c.childNodes[--d];if(a.childNodes&&a.childNodes.length)D(a);else a.nodeType==3&&c.removeChild(a)}},J=function(c,d){var a=c.Opts.labels,b=d.Label,e,g;if(b.txt){b.el.click(function(){d.Img.trigger("click")});if(/[mc]/.test(a)){e={};h.each(o,function(i,j){e[j]=v(b.el.css("padding"+j))});h.each(t,function(i,j){b[j.wh]=b.el[j.wh]();b[j.wh+"Pad"]=e[j.lead]+e[j.trail]})}g=a.split("");
+a={top:0,left:0,bottom:"auto",right:"auto"};if(g[0]=="b"){a.top="auto";a.bottom=0}if(g[1]=="r"){a.left="auto";a.right=0}b.el.css(a);e=a=g=null}},u=function(c,d){var a=m[c],b=a.Opts,e=a.Elem.length,g,i;for(d=d||B(a);e;){g=a.Elem[--e];i=Math.abs(d-g.Centre);g.Final=i<b.distance?g[b.vh.wh]-Math.floor((g[b.vh.wh]-g.Initial)*Math.pow(i,b.coefficient)/b.attenuation):g.Initial}},r=function(c,d){var a;if(c.Opts.labels&&c.Current!==false){a=c.Elem[c.Current].Label;a.el[a.txt&&d?"show":"hide"]()}},E=function(c,
+d,a,b){c=m[c];var e=c.Elem[d],g=c.Opts,i=g.vh.inv,j=e.Source!=e.AltSource,l,k,f;if(b||e.Trans!=a){l=h.boxModel||g.orient.vh=="v"?0:c.Borders[g.vh.lead]+c.Borders[g.vh.trail];if(j&&!b&&e.Trans==e.Initial)e.Img[0].src=e.AltSource;c.Spread+=a-e.Trans;k=C(e,a,g.orient);f=g.size-k[i.wh];switch(g.align){case "bottom":case "right":k["margin"+i.lead]=f;break;case "middle":case "center":k["margin"+i.lead]=(f+f%2)/2;k["margin"+i.trail]=(f-f%2)/2;break;default:k["margin"+i.trail]=f}if(a!=e.Trans||b&&!d)c.Yard[g.vh.wh](c.Spread+
+l);e.Wrap.css(k);c.Yard.css(g.vh.tl,Math.floor(Math.max(0,(c[g.vh.wh]-c.Spread)/2)));c.OnDock&&x(c);e.Trans=a;e.TransInv=k[i.wh];if(j&&!b&&e.Trans==e.Initial)e.Img[0].src=e.Source}},y=function(c,d){var a=m[c],b=a.Opts,e=b.duration+b.step,g=0,i;if(a.Timestamp){e=(new Date).getTime()-a.Timestamp;if(e>=b.duration)a.Timestamp=0}if(e>b.step){for(e=e<b.duration?e/b.duration:0;g<a.Elem.length;){i=a.Elem[g];i=d?e?Math.floor(i.Final-(i.Final-i.Initial)*e):i.Initial:e?Math.floor(i.Initial+(i.Final-i.Initial)*
+e):i.Final;E(c,g++,i)}if(a.Spread>a[b.vh.wh]){a.Yard.parent()[b.vh.wh](a.Spread+a.Borders[b.vh.lead]+a.Borders[b.vh.trail]);a[b.vh.wh]=a.Spread}}},F=function(c){var d=m[c],a=d.Elem,b=a.length;if(!d.OnDock){for(;b--&&a[b].Trans<=a[b].Initial;);B(d);if(b<0){for(b=a.length;b--;)a[b].Trans=a[b].Final=a[b].Initial;d.Current=false}else{y(c,true);q.setTimeout(function(){F(c)},d.Opts.step)}}},G=function(c){var d=m[c],a=d.Elem,b=a.length;if(d.OnDock){for(;b--&&a[b].Trans>=a[b].Final;);if(b<0){d.Expanded=true;
+r(d,true)}else{u(c);y(c);q.setTimeout(function(){G(c)},d.Opts.step)}}},s=function(c,d,a){var b=m[d],e=b.Elem;switch(c){case "mousemove":if(a!==b.Current){r(b);b.Current=a}x(b);b.Expanded&&r(b,true);if(b.OnDock&&b.Expanded){u(d);y(d)}break;case "mouseenter":b.OnDock=true;b.Current!==false&&b.Current!==a&&r(b);b.Current=a;x(b);b.Expanded&&r(b,true);b.Timestamp=(new Date).getTime();u(d);G(d);break;case "mouseleave":if(b.Inactive){q.clearTimeout(b.Inactive);b.Inactive=null}b.OnDock=b.Expanded=false;r(b);
+b.Timestamp=(new Date).getTime();for(c=e.length;c--;)e[c].Final=e[c].Trans;F(d);break;default:}},K=function(c){var d=1*(this.id.match(/^jqDock(\d+)$/)||[0,-1])[1],a=d>=0?m[d]:0,b=a?c.target.className.toString().match(/jqDockMouse(\d+)/):0,e=b?1*b[1]:false;if(a){A=[c.pageX,c.pageY];if(c.type=="mouseleave")a.OnDock&&s(c.type,d,e);else{if(a.Opts.inactivity){if(a.Inactive){q.clearTimeout(a.Inactive);a.Inactive=null}a.Inactive=q.setTimeout(function(){s("mouseleave",d,e)},a.Opts.inactivity)}if(c.type==
+"mousemove")if(e===false)a.OnDock&&a.Current!==false&&s("mouseleave",d,e);else!a.OnDock||a.Current===false?s("mouseenter",d,e):s(c.type,d,e);else e!==false&&!a.OnDock&&s(c.type,d,e)}}return false};h.jqDock=function(){return{version:1.4,defaults:{size:48,distance:72,coefficient:1.5,duration:300,align:"bottom",labels:false,source:false,loader:null,inactivity:0,fadeIn:0,fadeLayer:"",step:50},useJqLoader:h.browser.opera||h.browser.safari,initDock:function(c){var d=m[c],a=d.Opts,b=a.vh,e=a.orient,g=d.Borders,
+i=w.join(""),j=0,l=0,k,f,n;D(d.Menu);for(h(d.Menu).children().each(function(z,p){var L=d.Elem[z].Wrap=h(p).wrap(i+i+"</div></div>").parent();e.vh=="h"&&L.parent().css("float","left")}).find("img").andSelf().css({position:"relative",padding:0,margin:0,borderWidth:0,borderStyle:"none",verticalAlign:"top",display:"block",width:"100%",height:"100%"});l<d.Elem.length;){f=d.Elem[l++];n=C(f,a.size,{vh:e.inv,inv:e.vh});f.Trans=f.Final=f.Initial=n[b.wh];f.Wrap.css(n);f.Img.attr({alt:""}).parent("a").andSelf().removeAttr("title");
+d[b.inv.wh]=Math.max(d[b.inv.wh],a.size+f.Pad[b.inv.lead]+f.Pad[b.inv.trail]);f.Offset=j;f.Centre=j+f.Pad[b.lead]+f.Initial/2;j+=f.Initial+f.Pad[b.lead]+f.Pad[b.trail]}for(l=0;l<d.Elem.length;){f=d.Elem[l++];k=d.Elem.length;n=f.Pad[b.lead]+f.Pad[b.trail];d.Spread+=f.Initial+n;u(c,f.Centre);for(j=0;k;)j+=d.Elem[--k].Final+n;if(j>d[b.wh])d[b.wh]=j;u(c,f.Offset);for(j=0;k<d.Elem.length;)j+=d.Elem[k++].Final+n;if(j>d[b.wh])d[b.wh]=j}for(;l;){f=d.Elem[--l];f.Final=f.Initial}f=[w[0],w[2],'<div id="jqDock',
+c,'" class="jqDock" style="position:absolute;top:0;left:0;padding:0;margin:0;overflow:visible;height:',d.height,"px;width:",d.width,'px;"></div></div>'].join("");d.Yard=h(d.Menu).wrapInner(f).find("div.jqDock");h.each(o,function(z,p){g[p]=v(d.Yard.css("border"+p+"Width"))});for(d.Yard.parent().addClass("jqDockWrap").width(d.width+g.Left+g.Right).height(d.height+g.Top+g.Bottom);l<d.Elem.length;){f=d.Elem[l];n=f.Wrap.parent();for(k in f.Pad)f.Pad[k]&&n.css("padding"+k,f.Pad[k]);E(c,l,f.Final,true);
+n.add(f.Img).addClass("jqDockMouse"+l);f.Label.el=h('<div class="jqDockLabel jqDockMouse'+l+" jqDockLabel"+(f.Linked?"Link":"Image")+'" style="position:absolute;margin:0px;">'+f.Label.txt+"</div>").hide().appendTo(f.Img.parent());l+=1}c=function(){a.labels&&h.each(d.Elem,function(){J(d,this)});d.Yard.bind("mouseenter mouseleave mousemove",K)};if(a.fadeIn){if(f={dock:".jqDock",wrap:".jqDockWrap"}[a.fadeLayer.toString()]||""){f=h(f,d.Menu).hide();h(d.Menu).show()}else f=h(d.Menu);f.find(":not(.jqDockLabel)").css({filter:"inherit"}).end().fadeIn(a.fadeIn,
+c)}else{h(d.Menu).show();c()}}}}();h.fn.jqDock=function(c){this.length&&!this.not("img").length?this.each(function(d,a){var b=a.className.toString().match(/jqDockMouse(\d+)/),e=b?(h(a).parents("div.jqDock").attr("id")||"").match(/^jqDock(\d+)$/):0,g=0,i,j;c=c||{};if(e){e=1*e[1];b=1*b[1];i=m[e].Elem[b];j=i.Trans==i.Initial;h.each(H,function(l,k){var f;if(c[l]){f=(h.isFunction(c[l])?c[l].call(a,i[k],l):c[l]).toString();if(i[k]!==f){i[k]=f;g=(l=="src"?j:!j)?k:g}}});g&&h(a).attr("src",i[g])}}):this.not(".jqDocked").filter(function(){return!h(this).parents(".jqDocked").length&&
+!h(this).children().not("img").filter(function(){return h(this).filter("a").children("img").parent().children().length!==1}).length}).hide().addClass("jqDocked").each(function(){var d=m.length,a=function(j){var l=m[j.data.id],k=l.Elem[j.data.idx];k.height=this.height;k.width=this.width;++l.Loaded>=l.Elem.length&&q.setTimeout(function(){h.jqDock.initDock(j.data.id)},0)},b,e,g,i;m[d]={Elem:[],Menu:this,OnDock:false,Expanded:false,Timestamp:0,width:0,height:0,Spread:0,Borders:{},Yard:false,Opts:h.extend({},
+h.jqDock.defaults,c||{},h.metadata?h(this).metadata():{}),Current:false,Loaded:0,Inactive:null};b=m[d];e=b.Opts;g=!e.loader&&h.jqDock.useJqLoader||e.loader==="jquery";h.each(["size","distance","duration","inactivity","fadeIn","step"],function(j,l){e[l]=v(e[l])});i=e.coefficient*1;e.coefficient=isNaN(i)?1.5:i;e.attenuation=Math.pow(e.distance,e.coefficient);e.orient={left:1,center:1,right:1}[e.align]?{vh:"v",inv:"h"}:{vh:"h",inv:"v"};e.vh=h.extend({},t[e.orient.vh],{inv:t[e.orient.inv]});e.labels=
+e.labels===true?{top:"br",left:"tr"}[e.align]||"tl":/^[tmb][lcr]$/.test(e.labels.toString())?e.labels:false;h("img",this).each(function(j,l){var k=h(l),f=k.attr("src"),n=k.parent("a");b.Elem[j]={Img:k,Source:f,AltSource:(e.source?e.source.call(l,j):"")||I(l)||f,Label:{txt:k.attr("title")||n.attr("title")||"",width:0,height:0,widthPad:0,heightPad:0,el:0},Initial:0,Trans:0,TransInv:0,Final:0,Offset:0,Centre:0,Pad:{},Linked:!!n.length,width:0,height:0};h.each(o,function(z,p){b.Elem[j].Pad[p]=v(k.css("padding"+
+p))})});h.each(b.Elem,function(j,l){var k,f=l.AltSource;if(g)h("<img />").bind("load",{id:d,idx:j},a).attr({src:f});else{k=new Image;k.onload=function(){a.call(this,{data:{id:d,idx:j}});k.onload="";k=null};k.src=f}})});return this}}})(jQuery,window);

tracmacos/htdocs/mac.css

   position: fixed;
   top: 0;
   width: 100%;
-  z-index: 101;
+  z-index: 102;
 }
 
 #mainpanel {
   background-color: #FFFFCC;
 }
 
-  /* Main toolbar */
+/* Main toolbar */
 
-#mactb, #mactb div, #mactb table, #mactb tr, #mactb td, #mactb tr: hover td, #mactb img, #mactb a img, #mactb_min tr, #mactb_min td, #mactb_min img, #mactb_min a img, .mactb_td tr: hover td {
+#mactb, #mactb div, #mactb table, #mactb tr, 
+#mactb td, #mactb tr: hover td, #mactb img, 
+#mactb a img, #mactb_min tr, #mactb_min td, 
+#mactb_min img, #mactb_min a img, 
+.tb_td tr:hover td {
   background-color: transparent;
   border: medium none;
   border-collapse: separate;
   text-align: left;
 }
 
-#mactb, #mactb div, #mactb table, #mactb tr, #mactb td, #mactb tr: hover td, #mactb img, #mactb a img, #mactb_min tr, #mactb_min td, #mactb_min img, #mactb_min a img, .mactb_td tr: hover td {
+#mactb, #mactb div, #mactb table, #mactb tr, 
+#mactb td, #mactb tr: hover td, #mactb img, 
+#mactb a img, #mactb_min tr, #mactb_min td, 
+#mactb_min img, #mactb_min a img, 
+.tb_td tr:hover td {
   background-color: transparent;
   border: medium none;
   border-collapse: separate;
   line-height: 14px;
   position: fixed !important;
   width: 100%;
-  z-index: 9999999;
+  z-index: 103;
 }
 
 #tb_bl {
   background-image: url(tb_timeline.png);
 }
 
+/* Dock Navigation */
 
+#docknav {
+  position: fixed;
+  top: 60px;
+  width: 36px;
+  z-index: 101;
+}
+
+#docknav img {
+  width: 36px;  /* Overriden by docknav */
+}
+
+#docknav :link, #docknav :visited,
+#docknav :link:hover, #docknav :visited:hover {
+  background-color: transparent;
+  border: none;
+}
+
+.jqDocked {
+  top: 30px !important;
+}
+
+.jqDockLabel {
+  background-color: #FFFFCC;
+  color: #000000;
+  font-weight: bold;
+}
+

tracmacos/templates/mac_theme.html

       <!-- > ${navigation('metanav')} <!-->
 
     </div>
+    <div id="docknav">
+      <a py:for="itm in chrome.nav['mainnav']" href="${href.wiki()}" title="${macos.util.striptags(itm.label)}">
+        <img src="${href(macos.imgs.dock.get(itm.name, macos.imgs.dock_default))}" />
+      </a>
+    </div>
     <div id="outer-wrapper">
       <div id="content-wrapper">
 
           // Let's make external links open in a new window.
           jQuery(this).attr("target", jQuery(this).attr("href"));
         });
+      opts = {
+              align: 'left',
+              distance: 40,
+              fadeIn: 1000,
+              inactivity: 4000,
+              labels: 'tl',
+              size: 34
+              }
+     jQuery('#docknav').jqDock(opts)
     </script>
   </body></py:match>
 </html>

tracmacos/theme.py

 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from trac.core import *
+from trac.config import Option, ListOption
+from trac.web.chrome import add_script
+from trac.web.api import IRequestFilter
+
+from genshi.builder import Markup, Element, Fragment
+from genshi.util import striptags
 
 from themeengine.api import ThemeBase
 
 class MacTheme(ThemeBase):
     """A theme for Trac based on Mac OS appearance."""
+    implements(IRequestFilter)
+    dock_images = ListOption('docnav', 'images', 
+                                'wiki:/chrome/theme/dk_wiki.png,'
+                                'admin:/chrome/theme/dk_admin.png,'
+                                'search:/chrome/theme/dk_search.png,'
+                                'roadmap:/chrome/theme/dk_milestone.png',
+                                doc="Images rendered in dock menu.")
+    dock_default = Option('docnav', 'default', '/chrome/theme/dk_default.png',
+                                doc="Catch-all image in dock menu.")
     
     template = htdocs = css = screenshot = True
     
+    # IRequestFilter methods
+    def pre_process_request(self, req, handler):
+        add_script(req, '/chrome/theme/jquery.jqDock.min.js')
+        return handler
+    
+    def post_process_request(self, req, template, data, content_type):
+        def to_text(fragment):
+          if isinstance(fragment, (Element, Fragment, Markup)):
+            return striptags(unicode(fragment))
+          else:
+            return unicode(fragment)
+            
+        data['macos'] = {
+              'util' : {
+                  'striptags' : to_text,
+                  },
+              'imgs' : {
+                  'dock_default' : self.dock_default,
+                  'dock' : dict([k.strip(), v.strip()] \
+                                    for k,v in (i.split(':', 1) \
+                                                for i in self.dock_images))
+                  }
+            }
+        return template, data, content_type