lit 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Prograils.com
1
+ Copyright (c) 2013 Prograils.com
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Lost in translation
2
2
  ### Rails i18n web interface
3
3
 
4
- Translate your apps with pleasure (sort of...) and for free. It's simple i18n
5
- web interface, build on top of twitter bootstrap, that one may find helpful in
6
- translating app by non-technicals.
4
+ Translate your apps with pleasure (sort of...) and for free. It's simple i18n
5
+ web interface, build on top of twitter bootstrap, that one may find helpful in
6
+ translating app by non-technicals.
7
7
 
8
8
  Highly inspired by Copycopter by thoughtbot.
9
9
 
@@ -15,6 +15,7 @@ Highly inspired by Copycopter by thoughtbot.
15
15
  4. Possibility to synchronize between environments or even apps
16
16
  5. Easy to install - works as an engine, comes with simple generator
17
17
  6. You can always export all translations to plain old YAML file
18
+ 7. Has build in wysiwyg editor ([jQuery TE](http://jqueryte.com/))
18
19
 
19
20
  ### Screenshots
20
21
 
@@ -30,6 +31,7 @@ gem "lit"
30
31
  2. run `bundle install`
31
32
 
32
33
  3. run installation generator `bundle exec rails g lit:install`
34
+ (for production/staging environment `redis` is suggested as key value engine. `hash` will not work in multi process environment)
33
35
 
34
36
  4. After doing above and restarting app, point your browser to ```http://app/lit```
35
37
 
@@ -41,17 +43,18 @@ You may want to take a look at generated initializer in `config/initializers/lit
41
43
 
42
44
  ### ToDo
43
45
 
44
- * ~~Versioning~~
46
+ * ~~Versioning~~
45
47
  * ~~API~~
46
48
  * ~~Synchronization between environments~~
47
49
  * Rewrite initializer
48
50
  * Rewrite exporter (which is now code from copycopter)
49
51
  * ~~Support for array types (ie. `date.abbr_day_names`)~~
50
52
  * ~~Generator~~
51
- * Support for wysiwyg
53
+ * ~~Support for wysiwyg~~
52
54
  * Better cache
53
55
  * ~~Support for other key value providers (ie. Redis does not support Array types in easy way)~~ (not applicable, as array storage works now with redis).
54
56
  * Integration with ActiveAdmin
57
+ * Support for Proc defaults (like in `I18n.t("not_exising_keys", :default=> lambda{|_, options| "text"})` )
55
58
 
56
59
 
57
60
  ### License
@@ -18,4 +18,5 @@
18
18
 
19
19
  $(document).ready(function(){
20
20
  $('.title').tooltip();
21
+
21
22
  });
@@ -0,0 +1,9 @@
1
+ /*!
2
+ *
3
+ * jQuery TE 1.4.0 , http://jqueryte.com/
4
+ * Copyright (C) 2013, Fatih Koca (fattih@fattih.com), (http://jqueryte.com/about)
5
+
6
+ * jQuery TE is provided under the MIT LICENSE.
7
+ *
8
+ */
9
+ (function(e){e.fn.jqte=function(t){function l(e,t,n,r,i){var s=f.length+1;return f.push({name:e,cls:s,command:t,key:n,tag:r,emphasis:i})}var n=[{title:"Text Format"},{title:"Font Size"},{title:"Color"},{title:"Bold",hotkey:"B"},{title:"Italic",hotkey:"I"},{title:"Underline",hotkey:"U"},{title:"Ordered List",hotkey:"."},{title:"Unordered List",hotkey:","},{title:"Subscript",hotkey:"down arrow"},{title:"Superscript",hotkey:"up arrow"},{title:"Outdent",hotkey:"left arrow"},{title:"Indent",hotkey:"right arrow"},{title:"Justify Left"},{title:"Justify Center"},{title:"Justify Right"},{title:"Strike Through",hotkey:"K"},{title:"Add Link",hotkey:"L"},{title:"Remove Link"},{title:"Cleaner Style",hotkey:"Delete"},{title:"Horizontal Rule",hotkey:"H"},{title:"Source"}];var r=[["p","Normal"],["h1","Header 1"],["h2","Header 2"],["h3","Header 3"],["h4","Header 4"],["h5","Header 5"],["h6","Header 6"],["pre","Preformatted"]];var i=["10","12","16","18","20","24","28"];var s=["0,0,0","68,68,68","102,102,102","153,153,153","204,204,204","238,238,238","243,243,243","255,255,255",null,"255,0,0","255,153,0","255,255,0","0,255,0","0,255,255","0,0,255","153,0,255","255,0,255",null,"244,204,204","252,229,205","255,242,204","217,234,211","208,224,227","207,226,243","217,210,233","234,209,220","234,153,153","249,203,156","255,229,153","182,215,168","162,196,201","159,197,232","180,167,214","213,166,189","224,102,102","246,178,107","255,217,102","147,196,125","118,165,175","111,168,220","142,124,195","194,123,160","204,0,0","230,145,56","241,194,50","106,168,79","69,129,142","61,133,198","103,78,167","166,77,121","153,0,0","180,95,6","191,144,0","56,118,29","19,79,92","11,83,148","53,28,117","116,27,71","102,0,0","120,63,4","127,96,0","39,78,19","12,52,61","7,55,99","32,18,77","76,17,48"];var o=["Web Address","E-mail Address","Picture URL"];var u=e.extend({status:true,css:"jqte",title:true,titletext:n,button:"OK",format:true,formats:r,fsize:true,fsizes:i,funit:"px",color:true,linktypes:o,b:true,i:true,u:true,ol:true,ul:true,sub:true,sup:true,outdent:true,indent:true,left:true,center:true,right:true,strike:true,link:true,unlink:true,remove:true,rule:true,source:true,placeholder:false,br:true,p:true,change:"",focus:"",blur:""},t);e.fn.jqteVal=function(t){e(this).closest("."+u.css).find("."+u.css+"_editor").html(t)};var a=navigator.userAgent.toLowerCase();if(/msie [1-7]./.test(a))u.title=false;var f=[];l("format","formats","","",false);l("fsize","fSize","","",false);l("color","colors","","",false);l("b","Bold","B",["b","strong"],true);l("i","Italic","I",["i","em"],true);l("u","Underline","U",["u"],true);l("ol","insertorderedlist","¾",["ol"],true);l("ul","insertunorderedlist","¼",["ul"],true);l("sub","subscript","(",["sub"],true);l("sup","superscript","&",["sup"],true);l("outdent","outdent","%",["blockquote"],false);l("indent","indent","'",["blockquote"],true);l("left","justifyLeft","","",false);l("center","justifyCenter","","",false);l("right","justifyRight","","",false);l("strike","strikeThrough","K",["strike"],true);l("link","linkcreator","L",["a"],true);l("unlink","unlink","",["a"],false);l("remove","removeformat",".","",false);l("rule","inserthorizontalrule","H",["hr"],false);l("source","displaysource","","",false);return this.each(function(){function B(){if(window.getSelection)return window.getSelection();else if(document.selection&&document.selection.createRange&&document.selection.type!="None")return document.selection.createRange()}function j(e,t){var n,r=B();if(window.getSelection){if(r.anchorNode&&r.getRangeAt)n=r.getRangeAt(0);if(n){r.removeAllRanges();r.addRange(n)}if(!a.match(/msie/))document.execCommand("StyleWithCSS",false,false);document.execCommand(e,false,t)}else if(document.selection&&document.selection.createRange&&document.selection.type!="None"){n=document.selection.createRange();n.execCommand(e,false,t)}q(false,false)}function F(t,n,r){if(v.not(":focus"))v.focus();if(window.getSelection){var i=B(),s,o,u;if(i.anchorNode&&i.getRangeAt){s=i.getRangeAt(0);o=document.createElement(t);e(o).attr(n,r);u=s.extractContents();o.appendChild(u);s.insertNode(o);i.removeAllRanges();if(n=="style")q(e(o),r);else q(e(o),false)}}else if(document.selection&&document.selection.createRange&&document.selection.type!="None"){var a=document.selection.createRange();var f=a.htmlText;var l="<"+t+" "+n+'="'+r+'">'+f+"</"+t+">";document.selection.createRange().pasteHTML(l)}}function q(e,t){var n=I();n=n?n:e;if(n&&t==false){if(n.parent().is("[style]"))n.attr("style",n.parent().attr("style"));if(n.is("[style]"))n.find("*").attr("style",n.attr("style"))}else if(e&&t&&e.is("[style]")){var r=t.split(";");r=r[0].split(":");if(e.is("[style*="+r[0]+"]"))e.find("*").css(r[0],r[1]);R(e)}}function R(t){if(t){var t=t[0];if(document.body.createTextRange){var n=document.body.createTextRange();n.moveToElementText(t);n.select()}else if(window.getSelection){var r=window.getSelection();var n=document.createRange();if(t!="undefined"&&t!=null){n.selectNodeContents(t);r.removeAllRanges();r.addRange(n);if(e(t).is(":empty")){e(t).append(" ");R(e(t))}}}}}function U(){if(!p.data("sourceOpened")){var t=I();var n="http://";W(true);if(t){var r=t.prop("tagName").toLowerCase();if(r=="a"&&t.is("[href]")){n=t.attr("href");t.attr(S,"")}else F("a",S,"")}else y.val(n).focus();g.click(function(t){if(e(t.target).hasClass(u.css+"_linktypetext")||e(t.target).hasClass(u.css+"_linktypearrow"))X(true)});w.find("a").click(function(){var t=e(this).attr(u.css+"-linktype");w.data("linktype",t);E.find("."+u.css+"_linktypetext").html(w.find("a:eq("+w.data("linktype")+")").text());V(n);X()});V(n);y.focus().val(n).bind("keypress keyup",function(e){if(e.keyCode==13){z(h.find("["+S+"]"));return false}});b.click(function(){z(h.find("["+S+"]"))})}else W(false)}function z(t){y.focus();R(t);t.removeAttr(S);if(w.data("linktype")!="2")j("createlink",y.val());else{j("insertImage",y.val());v.find("img").each(function(){var t=e(this).prev("a");var n=e(this).next("a");if(t.length>0&&t.html()=="")t.remove();else if(n.length>0&&n.html()=="")n.remove()})}W();v.trigger("change")}function W(e){Q("["+S+"]:not([href])");h.find("["+S+"][href]").removeAttr(S);if(e){p.data("linkOpened",true);d.show()}else{p.data("linkOpened",false);d.hide()}X()}function X(e){if(e)w.show();else w.hide()}function V(e){var t=w.data("linktype");if(t=="1"&&(y.val()=="http://"||y.is("[value^=http://]")||!y.is("[value^=mailto]")))y.val("mailto:");else if(t!="1"&&!y.is("[value^=http://]"))y.val("http://");else y.val(e)}function J(t){if(!p.data("sourceOpened")){if(t=="fSize")styleField=P;else if(t=="colors")styleField=H;K(styleField,true);styleField.find("a").unbind("click").click(function(){var n=e(this).attr(u.css+"-styleval");if(t=="fSize"){styleType="font-size";n=n+u.funit}else if(t=="colors"){styleType="color";n="rgb("+n+")"}var r=G(styleType);F("span","style",styleType+":"+n+";"+r);K("",false);e("."+u.css+"_title").remove();v.trigger("change")})}else K(styleField,false);W(false)}function K(e,t){var n="",r=[{d:"fsizeOpened",f:P},{d:"cpallOpened",f:H}];if(e!=""){for(var i=0;i<r.length;i++){if(e==r[i]["f"])n=r[i]}}if(t){p.data(n["d"],true);n["f"].slideDown(100);for(var i=0;i<r.length;i++){if(n["d"]!=r[i]["d"]){p.data(r[i]["d"],false);r[i]["f"].slideUp(100)}}}else{for(var i=0;i<r.length;i++){p.data(r[i]["d"],false);r[i]["f"].slideUp(100)}}}function Q(t){h.find(t).each(function(){e(this).before(e(this).html()).remove()})}function G(e){var t=I();if(t&&t.is("[style]")&&t.css(e)!=""){var n=t.css(e);t.css(e,"");var r=t.attr("style");t.css(e,n);return r}else return""}function Y(){Z(true);D.find("a").click(function(){e("*",this).click(function(e){e.preventDefault();return false});et(e(this).text());var t=e(this).attr(u.css+"-formatval");j("formatBlock","<"+t+">");Z(false)})}function Z(e){var t=e?true:false;t=e&&D.data("status")?true:false;if(t||!e)D.data("status",false).slideUp(200);else D.data("status",true).slideDown(200)}function et(e){var t=D.closest("."+u.css+"_tool").find("."+u.css+"_tool_label").find("."+u.css+"_tool_text");if(e.length>10)e=e.substr(0,7)+"...";t.html(e)}function tt(e){var t,n,r;t=e.replace(/\n/gim,"").replace(/\r/gim,"").replace(/\t/gim,"").replace(/ /gim," ");n=[/\<span(|\s+.*?)><span(|\s+.*?)>(.*?)<\/span><\/span>/gim,/<(\w*[^p])\s*[^\/>]*>\s*<\/\1>/gim,/\<div(|\s+.*?)>(.*?)\<\/div>/gim,/\<strong(|\s+.*?)>(.*?)\<\/strong>/gim,/\<em(|\s+.*?)>(.*?)\<\/em>/gim];r=["<span$2>$3</span>","","<p$1>$2</p>","<b$1>$2</b>","<i$1>$2</i>"];for(A=0;A<5;A++){for(var i=0;i<n.length;i++){t=t.replace(n[i],r[i])}}if(!u.p)t=t.replace(/\<p(|\s+.*?)>(.*?)\<\/p>/ig,"<br/>$2");if(!u.br){n=[/\<br>(.*?)/ig,/\<br\/>(.*?)/ig];r=["<p>$1</p>","<p>$1</p>"];for(var i=0;i<n.length;i++){t=t.replace(n[i],r[i])}}if(!u.p&&!u.br)t=t.replace(/\<p>(.*?)\<\/p>/ig,"<div>$1</div>");return t}function nt(){var e=v.text()==""&&v.html().length<12?"":v.html();l.val(tt(e))}function rt(){v.html(tt(l.val()))}function it(t){var n=false,r=I(),i;if(r){e.each(t,function(t,s){i=r.prop("tagName").toLowerCase();if(i==s)n=true;else{r.parents().each(function(){i=e(this).prop("tagName").toLowerCase();if(i==s)n=true})}});return n}else return false}function st(t){for(var n=0;n<f.length;n++){if(u[f[n].name]&&f[n].emphasis&&f[n].tag!="")it(f[n].tag)?p.find("."+u.css+"_tool_"+f[n].cls).addClass(m):e("."+u.css+"_tool_"+f[n].cls).removeClass(m)}if(u.format&&e.isArray(u.formats)){var r=false;for(var i=0;i<u.formats.length;i++){var s=[];s[0]=u.formats[i][0];if(u.formats[i][0].length>0&&it(s)){et(u.formats[i][1]);r=true;break}}if(!r)et(u.formats[0][1])}K("",false);Z(false)}if(!e(this).data("jqte")||e(this).data("jqte")==null||e(this).data("jqte")=="undefined")e(this).data("jqte",true);else e(this).data("jqte",false);if(!u.status||!e(this).data("jqte")){if(e(this).closest("."+u.css).length>0){var t=e(this).closest("."+u.css).find("."+u.css+"_editor").html();var n="";e(e(this)[0].attributes).each(function(){if(this.nodeName!="style")n=n+" "+this.nodeName+'="'+this.nodeValue+'"'});var r=e(this).is("[data-origin]")&&e(this).attr("data-origin")!=""?e(this).attr("data-origin"):"textarea";var i=">"+t;if(r=="input"||r=="option"){t=t.replace(/"/g,"&#34;").replace(/'/g,"&#39;").replace(/</g,"<").replace(/>/g,">");i='value="'+t+'">'}var o=e(this).clone();e(this).data("jqte",false).closest("."+u.css).before(o).remove();o.replaceWith("<"+r+n+i+"</"+r+">")}return}var l=e(this);var r=e(this).prop("tagName").toLowerCase();e(this).attr("data-origin",r);var c=e(this).is("[value]")||r=="textarea"?e(this).val():e(this).html();c=c.replace(/&#34;/g,'"').replace(/&#39;/g,"'").replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&");e(this).after('<div class="'+u.css+'"></div>');var h=e(this).next("."+u.css);h.html('<div class="'+u.css+"_toolbar"+'" role="toolbar" unselectable></div><div class="'+u.css+'_linkform" style="display:none" role="dialog"></div><div class="'+u.css+"_editor"+'"></div>');var p=h.find("."+u.css+"_toolbar");var d=h.find("."+u.css+"_linkform");var v=h.find("."+u.css+"_editor");var m=u.css+"_tool_depressed";d.append('<div class="'+u.css+'_linktypeselect" unselectable></div><input class="'+u.css+'_linkinput" type="text/css" value=""><div class="'+u.css+'_linkbutton" unselectable>'+u.button+'</div> <div style="height:1px;float:none;clear:both"></div>');var g=d.find("."+u.css+"_linktypeselect");var y=d.find("."+u.css+"_linkinput");var b=d.find("."+u.css+"_linkbutton");g.append('<div class="'+u.css+'_linktypeview" unselectable></div><div class="'+u.css+'_linktypes" role="menu" unselectable></div>');var w=g.find("."+u.css+"_linktypes");var E=g.find("."+u.css+"_linktypeview");var S=u.css+"-setlink";v.after('<div class="'+u.css+"_source "+u.css+'_hiddenField"></div>');var x=h.find("."+u.css+"_source");l.appendTo(x);if(r!="textarea"){var n="";e(l[0].attributes).each(function(){if(this.nodeName!="type"&&this.nodeName!="value")n=n+" "+this.nodeName+'="'+this.nodeValue+'"'});l.replaceWith("<textarea "+n+">"+c+"</textarea>");l=x.find("textarea")}v.attr("contenteditable","true").html(c);for(var T=0;T<f.length;T++){if(u[f[T].name]){var N=f[T].key.length>0?u.titletext[T].hotkey!=null&&u.titletext[T].hotkey!="undefined"&&u.titletext[T].hotkey!=""?" (Ctrl+"+u.titletext[T].hotkey+")":"":"";var C=u.titletext[T].title!=null&&u.titletext[T].title!="undefined"&&u.titletext[T].title!=""?u.titletext[T].title+N:"";p.append('<div class="'+u.css+"_tool "+u.css+"_tool_"+f[T].cls+'" role="button" data-tool="'+T+'" unselectable><a class="'+u.css+'_tool_icon" unselectable></a></div>');p.find("."+u.css+"_tool[data-tool="+T+"]").data({tag:f[T].tag,command:f[T].command,emphasis:f[T].emphasis,title:C});if(f[T].name=="format"&&e.isArray(u.formats)){var k=u.formats[0][1].length>0&&u.formats[0][1]!="undefined"?u.formats[0][1]:"";p.find("."+u.css+"_tool_"+f[T].cls).find("."+u.css+"_tool_icon").replaceWith('<a class="'+u.css+'_tool_label" unselectable><span class="'+u.css+'_tool_text" unselectable>'+k+'</span><span class="'+u.css+'_tool_icon" unselectable></span></a>');p.find("."+u.css+"_tool_"+f[T].cls).append('<div class="'+u.css+'_formats" unselectable></div>');for(var L=0;L<u.formats.length;L++){p.find("."+u.css+"_formats").append("<a "+u.css+'-formatval="'+u.formats[L][0]+'" class="'+u.css+"_format"+" "+u.css+"_format_"+L+'" role="menuitem" unselectable>'+u.formats[L][1]+"</a>")}p.find("."+u.css+"_formats").data("status",false)}else if(f[T].name=="fsize"&&e.isArray(u.fsizes)){p.find("."+u.css+"_tool_"+f[T].cls).append('<div class="'+u.css+'_fontsizes" unselectable></div>');for(var L=0;L<u.fsizes.length;L++){p.find("."+u.css+"_fontsizes").append("<a "+u.css+'-styleval="'+u.fsizes[L]+'" class="'+u.css+"_fontsize"+'" style="font-size:'+u.fsizes[L]+u.funit+'" role="menuitem" unselectable>Abcdefgh...</a>')}}else if(f[T].name=="color"&&e.isArray(s)){p.find("."+u.css+"_tool_"+f[T].cls).append('<div class="'+u.css+'_cpalette" unselectable></div>');for(var A=0;A<s.length;A++){if(s[A]!=null)p.find("."+u.css+"_cpalette").append("<a "+u.css+'-styleval="'+s[A]+'" class="'+u.css+"_color"+'" style="background-color: rgb('+s[A]+')" role="gridcell" unselectable></a>');else p.find("."+u.css+"_cpalette").append('<div class="'+u.css+"_colorSeperator"+'"></div>')}}}}w.data("linktype","0");for(var T=0;T<3;T++){w.append("<a "+u.css+'-linktype="'+T+'" unselectable>'+u.linktypes[T]+"</a>");E.html('<div class="'+u.css+'_linktypearrow" unselectable></div><div class="'+u.css+'_linktypetext">'+w.find("a:eq("+w.data("linktype")+")").text()+"</div>")}var O="";if(/msie/.test(a))O="-ms-";else if(/chrome/.test(a)||/safari/.test(a)||/yandex/.test(a))O="-webkit-";else if(/mozilla/.test(a))O="-moz-";else if(/opera/.test(a))O="-o-";else if(/konqueror/.test(a))O="-khtml-";else O="";if(u.placeholder&&u.placeholder!=""){h.prepend('<div class="'+u.css+'_placeholder" unselectable><div class="'+u.css+'_placeholder_text">'+u.placeholder+"</div></div>");var M=h.find("."+u.css+"_placeholder");M.click(function(){v.focus()})}h.find("[unselectable]").css(O+"user-select","none").addClass("unselectable").attr("unselectable","on").on("selectstart mousedown",false);var _=p.find("."+u.css+"_tool");var D=p.find("."+u.css+"_formats");var P=p.find("."+u.css+"_fontsizes");var H=p.find("."+u.css+"_cpalette");var I=function(){var t,n;if(window.getSelection){n=getSelection();t=n.anchorNode}if(!t&&document.selection&&document.selection.createRange&&document.selection.type!="None"){n=document.selection;var r=n.getRangeAt?n.getRangeAt(0):n.createRange();t=r.commonAncestorContainer?r.commonAncestorContainer:r.parentElement?r.parentElement():r.item(0)}if(t){return t.nodeName=="#text"?e(t.parentNode):e(t)}else return false};_.unbind("click").click(function(t){if(e(this).data("command")=="displaysource"&&!p.data("sourceOpened")){p.find("."+u.css+"_tool").addClass(u.css+"_hiddenField");e(this).removeClass(u.css+"_hiddenField");p.data("sourceOpened",true);l.css("height",v.outerHeight());x.removeClass(u.css+"_hiddenField");v.addClass(u.css+"_hiddenField");l.focus();W(false);K("",false);Z();if(u.placeholder&&u.placeholder!="")M.hide()}else{if(!p.data("sourceOpened")){if(e(this).data("command")=="linkcreator"){if(!p.data("linkOpened"))U();else{W(false);Z(false)}}else if(e(this).data("command")=="formats"){if(e(this).data("command")=="formats"&&!e(t.target).hasClass(u.css+"_format"))Y();K("",false);if(v.not(":focus"))v.focus()}else if(e(this).data("command")=="fSize"||e(this).data("command")=="colors"){if(e(this).data("command")=="fSize"&&!e(t.target).hasClass(u.css+"_fontsize")||e(this).data("command")=="colors"&&!e(t.target).hasClass(u.css+"_color"))J(e(this).data("command"));Z(false);if(v.not(":focus"))v.focus()}else{if(v.not(":focus"))v.focus();j(e(this).data("command"),null);K("",false);Z(false);X();e(this).data("emphasis")==true&&!e(this).hasClass(m)?e(this).addClass(m):e(this).removeClass(m);x.addClass(u.css+"_hiddenField");v.removeClass(u.css+"_hiddenField")}}else{p.data("sourceOpened",false);p.find("."+u.css+"_tool").removeClass(u.css+"_hiddenField");x.addClass(u.css+"_hiddenField");v.removeClass(u.css+"_hiddenField")}if(u.placeholder&&u.placeholder!="")v.html()!=""?M.hide():M.show()}v.trigger("change")}).hover(function(t){if(u.title&&e(this).data("title")!=""&&(e(t.target).hasClass(u.css+"_tool")||e(t.target).hasClass(u.css+"_tool_icon"))){e("."+u.css+"_title").remove();h.append('<div class="'+u.css+'_title"><div class="'+u.css+'_titleArrow"><div class="'+u.css+'_titleArrowIcon"></div></div><div class="'+u.css+'_titleText">'+e(this).data("title")+"</div></div>");var n=e("."+u.css+"_title:first");var r=n.find("."+u.css+"_titleArrowIcon");var i=e(this).position();var s=i.left+e(this).outerWidth()-n.outerWidth()/2-e(this).outerWidth()/2;var o=i.top+e(this).outerHeight()+5;n.delay(400).css({top:o,left:s}).fadeIn(200)}},function(){e("."+u.css+"_title").remove()});var ot=null;v.bind("keypress keyup keydown drop cut copy paste DOMCharacterDataModified DOMSubtreeModified",function(){if(!p.data("sourceOpened"))e(this).trigger("change");X();if(e.isFunction(u.change))u.change();if(u.placeholder&&u.placeholder!="")e(this).text()!=""?M.hide():M.show()}).bind("change",function(){if(!p.data("sourceOpened")){clearTimeout(ot);ot=setTimeout(nt,10)}}).keydown(function(e){if(e.ctrlKey){for(var t=0;t<f.length;t++){if(u[f[t].name]&&e.keyCode==f[t].key.charCodeAt(0)){if(f[t].command!=""&&f[t].command!="linkcreator")j(f[t].command,null);else if(f[t].command=="linkcreator")U();return false}}}}).bind("mouseup keyup",st).focus(function(){if(e.isFunction(u.focus))u.focus();h.addClass(u.css+"_focused");if(/opera/.test(a)){var t=document.createRange();t.selectNodeContents(v[0]);t.collapse(false);var n=window.getSelection();n.removeAllRanges();n.addRange(t)}}).focusout(function(){_.removeClass(m);K("",false);Z(false);X();if(e.isFunction(u.blur))u.blur();h.removeClass(u.css+"_focused");if(e.isArray(u.formats))et(u.formats[0][1])});l.bind("keydown keyup",function(){setTimeout(rt,0);e(this).height(e(this)[0].scrollHeight);if(e(this).val()=="")e(this).height(0)}).focus(function(){h.addClass(u.css+"_focused")}).focusout(function(){h.removeClass(u.css+"_focused")})})}})(jQuery)
@@ -2,10 +2,11 @@
2
2
  $(document).ready ->
3
3
  $('td.localization_row[data-editing=0]').on 'click', ->
4
4
  $this = $(this)
5
- edited_rows[$this.data('id')] = $this.html()
6
- unless parseInt($this.data('editing'))
7
- $this.data('editing', '1')
8
- $.get $this.data('edit')
5
+ if parseInt($this.data('editing'))==0
6
+ edited_rows[$this.data('id')] = $this.html()
7
+ unless parseInt($this.data('editing'))
8
+ $this.data('editing', '1')
9
+ $.get $this.data('edit')
9
10
  $('td.localization_row').on 'click', 'form button.cancel', (e)->
10
11
  $this = $(this)
11
12
  if $this[0].localName=='button'
@@ -19,3 +20,5 @@ $(document).ready ->
19
20
  $parent = $this.parents('tr.localization_versions_row')
20
21
  $parent.addClass('hidden')
21
22
  $parent.children('td').html('')
23
+ $('tr.localization_key_row').on 'click', 'input.wysiwyg_switch', (e)->
24
+ $(this).parents('form').find("textarea").jqte()
@@ -9,6 +9,7 @@
9
9
  * compiled file, but it's generally better to create a new file per style scope.
10
10
  *
11
11
  *= require './bootstrap_and_overrides.css'
12
+ *= require './jquery-te-1.4.0.css'
12
13
  *= require_self
13
14
  */
14
15
  .detail_wrapper{
@@ -0,0 +1,457 @@
1
+ /*!
2
+ *
3
+ * jQuery TE 1.4.0 , http://jqueryte.com/
4
+ * Copyright (C) 2013, Fatih Koca (fattih@fattih.com), (http://jqueryte.com/about)
5
+
6
+ * jQuery TE is provided under the MIT LICENSE.
7
+ *
8
+ */
9
+
10
+ /* editor's general field */
11
+ .jqte {
12
+ /*margin:30px 0;
13
+ border:#000 1px solid;
14
+ border-radius:5px; -webkit-border-radius:5px; -moz-border-radius:5px;
15
+ box-shadow:0 0 3px #999; -webkit-box-shadow:0 0 3px #999; -moz-box-shadow:0 0 3px #999;
16
+ overflow:hidden;
17
+ transition:box-shadow 0.4s, border 0.4s; -webkit-transition:-webkit-box-shadow 0.4s, border 0.4s; -moz-transition:-moz-box-shadow 0.4s, border 0.4s; -o-transition:-o-box-shadow 0.4s, border 0.4s;
18
+ }
19
+ .jqte * {
20
+ color:#333;
21
+ font-family:Arial, Helvetica, sans-serif;
22
+ font-size:14px;
23
+ }
24
+ .jqte_focused {
25
+ border-color:#00AAE7;
26
+ box-shadow:0 0 10px #00BDFF; -webkit-box-shadow:0 0 10px #00BDFF; -moz-box-shadow:0 0 10px #00BDFF;
27
+ }
28
+ /* toolbar */
29
+ .jqte_toolbar {
30
+ overflow:auto;
31
+ padding:3px 4px;
32
+ background:#EEE;
33
+ border-bottom:#BBB 1px solid;
34
+ }
35
+ .jqte_tool {
36
+ float:left;
37
+ margin:0;
38
+ padding:0;
39
+ cursor:pointer;
40
+ }
41
+ .jqte_tool, .jqte_tool_icon, .jqte_tool_label {
42
+ border:#EEE 1px solid;
43
+ border-radius:3px; -webkit-border-radius:3px; -moz-border-radius:3px
44
+ }
45
+ .jqte_hiddenField {
46
+ display:none
47
+ }
48
+ .jqte_tool_icon {
49
+ display:block;
50
+ width:22px;
51
+ height:22px;
52
+ background:image-url('lit/jquery-te.png') no-repeat
53
+ }
54
+ .jqte_tool.jqte_tool_1 .jqte_tool_label {
55
+ position:relative;
56
+ display:block;
57
+ padding:3px;
58
+ width:70px;
59
+ height:16px;
60
+ overflow:hidden;
61
+ }
62
+ .jqte_tool.jqte_tool_1 .jqte_tool_text {
63
+ font:bold 13px Arial,sans-serif;
64
+ color:#222;
65
+ }
66
+ .jqte_tool.jqte_tool_1 .jqte_tool_icon {
67
+ position:absolute;
68
+ top:10px;
69
+ right:2px;
70
+ width:6px;
71
+ height:4px;
72
+ background-position:-19px -23px;
73
+ border:none;
74
+ border-radius:none; -webkit-border-radius:none; -moz-border-radius:none
75
+ }
76
+ .jqte_tool.jqte_tool_2 .jqte_tool_icon {
77
+ background-position:0 0
78
+ }
79
+ .jqte_tool.jqte_tool_3 .jqte_tool_icon {
80
+ background-position:-22px 0
81
+ }
82
+ .jqte_tool.jqte_tool_4 .jqte_tool_icon {
83
+ background-position:-44px 0
84
+ }
85
+ .jqte_tool.jqte_tool_5 .jqte_tool_icon {
86
+ background-position:-66px 0
87
+ }
88
+ .jqte_tool.jqte_tool_6 .jqte_tool_icon {
89
+ background-position:-88px 0
90
+ }
91
+ .jqte_tool.jqte_tool_7 .jqte_tool_icon {
92
+ background-position:-110px 0
93
+ }
94
+ .jqte_tool.jqte_tool_8 .jqte_tool_icon {
95
+ background-position:-132px 0
96
+ }
97
+ .jqte_tool.jqte_tool_9 .jqte_tool_icon {
98
+ background-position:-154px 0
99
+ }
100
+ .jqte_tool.jqte_tool_10 .jqte_tool_icon {
101
+ background-position:-176px 0
102
+ }
103
+ .jqte_tool.jqte_tool_11 .jqte_tool_icon {
104
+ background-position:-198px 0
105
+ }
106
+ .jqte_tool.jqte_tool_12 .jqte_tool_icon {
107
+ background-position:-220px 0
108
+ }
109
+ .jqte_tool.jqte_tool_13 .jqte_tool_icon {
110
+ background-position:-242px 0
111
+ }
112
+ .jqte_tool.jqte_tool_14 .jqte_tool_icon {
113
+ background-position:-264px 0
114
+ }
115
+ .jqte_tool.jqte_tool_15 .jqte_tool_icon {
116
+ background-position:-286px 0
117
+ }
118
+ .jqte_tool.jqte_tool_16 .jqte_tool_icon {
119
+ background-position:-308px 0
120
+ }
121
+ .jqte_tool.jqte_tool_17 .jqte_tool_icon {
122
+ background-position:-330px 0
123
+ }
124
+ .jqte_tool.jqte_tool_18 .jqte_tool_icon {
125
+ background-position:-352px 0
126
+ }
127
+ .jqte_tool.jqte_tool_19 .jqte_tool_icon {
128
+ background-position:-374px 0
129
+ }
130
+ .jqte_tool.jqte_tool_20 .jqte_tool_icon {
131
+ background-position:-396px 0
132
+ }
133
+ .jqte_tool.jqte_tool_21 .jqte_tool_icon {
134
+ background-position:-418px 0
135
+ }
136
+ .jqte_tool:hover {
137
+ background-color:#FFF;
138
+ border-color:#FFF
139
+ }
140
+ .jqte_tool:hover .jqte_tool_icon, .jqte_tool:hover .jqte_tool_label {
141
+ border:#AAA 1px solid
142
+ }
143
+ .jqte_tool:active .jqte_tool_icon, .jqte_tool:active .jqte_tool_label {
144
+ border:#777 1px solid
145
+ }
146
+ .jqte_tool.jqte_tool_1:hover .jqte_tool_icon, .jqte_tool.jqte_tool_1:active .jqte_tool_icon {
147
+ border:none
148
+ }
149
+ .jqte_tool_depressed {
150
+ background-color:#DDD;
151
+ border-color:#CCC
152
+ }
153
+ .jqte_tool_depressed .jqte_tool_icon {
154
+ border-color:#AAA
155
+ }
156
+ .jqte_tool_depressed:hover {
157
+ background-color:#EEE
158
+ }
159
+ /* link form area */
160
+ .jqte_linkform {
161
+ padding:5px 10px;
162
+ background:#DDD;
163
+ border-bottom:#BBB 1px solid;
164
+ }
165
+ .jqte_linktypeselect {
166
+ position:relative;
167
+ float:left;
168
+ width:130px;
169
+ background:#EEE;
170
+ cursor:pointer
171
+ }
172
+ .jqte_linktypeselect:Active {
173
+ background:#FFF
174
+ }
175
+ .jqte_linktypeview {
176
+ padding:3px 5px;
177
+ border:#333 1px solid;
178
+ color:#777;
179
+ border-radius:3px; -webkit-border-radius:3px; -moz-border-radius:3px;
180
+ outline:none
181
+ }
182
+ .jqte_linktypetext {
183
+ font-size:12px;
184
+ }
185
+ .jqte_linktypearrow {
186
+ position:absolute;
187
+ bottom:8px; right:6px;
188
+ width:7px;
189
+ height:6px;
190
+ margin:0 auto;
191
+ background:image-url('lit/jquery-te.png') -7px -23px no-repeat;
192
+ }
193
+ .jqte_linktypes {
194
+ display:none;
195
+ position:absolute;
196
+ top:22px; left:1px;
197
+ width:125px;
198
+ background:#FFF;
199
+ border:#333 1px solid;
200
+ box-shadow:0 1px 4px #AAA; -webkit-box-shadow:0 1px 4px #AAA; -moz-box-shadow:0 1px 4px #AAA
201
+ }
202
+ .jqte_linktypes a {
203
+ display:block;
204
+ padding:4px 5px;
205
+ font-size:12px;
206
+ }
207
+ .jqte_linktypes a:hover {
208
+ background:#DDD
209
+ }
210
+ .jqte_linkinput {
211
+ float:left;
212
+ margin:0 5px;
213
+ padding:3px 5px;
214
+ width:300px;
215
+ background:#EEE;
216
+ border:#333 1px solid;
217
+ color:#777;
218
+ font-size:12px;
219
+ border-radius:3px; -webkit-border-radius:3px; -moz-border-radius:3px;
220
+ outline:none;
221
+ }
222
+ .jqte_linkinput:focus, .jqte_linkinput:hover {
223
+ background:#FFF;
224
+ border-color:#000;
225
+ }
226
+ .jqte_linkbutton {
227
+ float:left;
228
+ padding:3px 12px;
229
+ background:#AAA;
230
+ border:#333 1px solid;
231
+ color:#FFF;
232
+ font-size:12px;
233
+ font-weight:bold;
234
+ cursor:pointer;
235
+ border-radius:3px; -webkit-border-radius:3px; -moz-border-radius:3px;
236
+ box-shadow:inset 0 1px #EEE; -webkit-box-shadow:inset 0 1px #EEE; -moz-box-shadow:inset 0 1px #EEE;
237
+ }
238
+ .jqte_linkbutton:hover {
239
+ background:#A1A1A1
240
+ }
241
+ .jqte_linkbutton:active {
242
+ box-shadow:inset 0 1px #CCC; -webkit-box-shadow:inset 0 1px #CCC; -moz-box-shadow:inset 0 1px #CCC;
243
+ background:#888;
244
+ }
245
+
246
+ /* text format menu */
247
+ .jqte_formats {
248
+ display:none;
249
+ position:absolute;
250
+ width:180px;
251
+ oveflow-x:hidden;
252
+ overflow-y:auto;
253
+ background:#FFF;
254
+ border:#AAA 1px solid;
255
+ box-shadow:0 0 5px #AAA; -webkit-box-shadow:0 0 5px #AAA; -moz-box-shadow:0 0 5px #AAA;
256
+ z-index:100;
257
+ }
258
+ .jqte_format {
259
+ display:block;
260
+ padding:4px 7px;
261
+ font-size:13px
262
+ }
263
+ .jqte_format:hover {
264
+ background:#DDD
265
+ }
266
+ .jqte_format_1, .jqte_format_2, .jqte_format_3, .jqte_format_4, .jqte_format_5, .jqte_format_6 {
267
+ font-weight:bold
268
+ }
269
+ .jqte_format_1 {
270
+ font-size:22px
271
+ }
272
+ .jqte_format_2 {
273
+ font-size:20px
274
+ }
275
+ .jqte_format_3 {
276
+ font-size:18px
277
+ }
278
+ .jqte_format_4 {
279
+ font-size:16px
280
+ }
281
+ .jqte_format_5 {
282
+ font-size:14px
283
+ }
284
+ .jqte_format_6 {
285
+ font-size:12px
286
+ }
287
+ .jqte_format_7 {
288
+ font-family:"Courier New", Courier, monospace
289
+ }
290
+
291
+ /* font size menu */
292
+ .jqte_fontsizes {
293
+ display:none;
294
+ position:absolute;
295
+ width:180px;
296
+ height:198px;
297
+ oveflow-x:hidden;
298
+ overflow-y:auto;
299
+ background:#FFF;
300
+ border:#AAA 1px solid;
301
+ box-shadow:0 0 5px #AAA; -webkit-box-shadow:0 0 5px #AAA; -moz-box-shadow:0 0 5px #AAA
302
+ }
303
+ .jqte_fontsize {
304
+ display:block;
305
+ padding:3px 7px;
306
+ }
307
+ .jqte_fontsize:hover {
308
+ background:#DDD
309
+ }
310
+
311
+ /* color pallette */
312
+ .jqte_cpalette {
313
+ display:none;
314
+ position:absolute;
315
+ padding:6px;
316
+ width:144px;
317
+ background:#FFF;
318
+ border:#AAA 1px solid;
319
+ box-shadow:0 0 5px #AAA; -webkit-box-shadow:0 0 5px #AAA; -moz-box-shadow:0 0 5px #AAA
320
+ }
321
+ .jqte_color {
322
+ display:block;
323
+ float:left;
324
+ width:16px;
325
+ height:16px;
326
+ border:#FFF 1px solid;
327
+ }
328
+ .jqte_color:hover {
329
+ border-color:#000
330
+ }
331
+ .jqte_colorSeperator {
332
+ float:none;
333
+ clear:both;
334
+ height:7px;
335
+ }
336
+
337
+ /* editor area */
338
+ .jqte_editor, .jqte_source {
339
+ padding:10px;
340
+ background:#FFF;
341
+ min-height:100px;
342
+ max-height:900px;
343
+ overflow:auto;
344
+ outline:none;
345
+ word-wrap:break-word; -ms-word-wrap:break-word;
346
+ resize:vertical
347
+ }
348
+ .jqte_editor div, .jqte_editor p {
349
+ margin:0 0 7px
350
+ }
351
+ .jqte_editor a:link, .jqte_editor a:link * {
352
+ color:#0066FF !important;
353
+ text-decoration:underline;
354
+ }
355
+ .jqte_editor blockquote {
356
+ margin-top:0;
357
+ margin-bottom:7px
358
+ }
359
+ .jqte_editor img {
360
+ float:left;
361
+ margin:0 10px 5px 0
362
+ }
363
+ .jqte_editor a[jqte-setlink], .jqte_editor a[jqte-setlink] * {
364
+ background:#3297FD !important;
365
+ color:#FFF !important
366
+ }
367
+ .jqte_editor h1, .jqte_editor h2, .jqte_editor h3, .jqte_editor h4, .jqte_editor h5, .jqte_editor h6, .jqte_editor pre {
368
+ display:block;
369
+ margin:0 0 3px;
370
+ }
371
+ .jqte_editor h1, .jqte_editor h1 * {
372
+ font-size:26px
373
+ }
374
+ .jqte_editor h2, .jqte_editor h2 * {
375
+ font-size:24px
376
+ }
377
+ .jqte_editor h3, .jqte_editor h3 * {
378
+ font-size:22px
379
+ }
380
+ .jqte_editor h4, .jqte_editor h4 * {
381
+ font-size:20px
382
+ }
383
+ .jqte_editor h5, .jqte_editor h5 * {
384
+ font-size:18px
385
+ }
386
+ .jqte_editor h6, .jqte_editor h6 * {
387
+ font-size:15px
388
+ }
389
+ .jqte_editor pre, .jqte_editor pre * {
390
+ font-family:"Courier New", Courier, monospace
391
+ }
392
+
393
+ /* source area */
394
+ .jqte_source, .jqte_source textarea {
395
+ background:#FFF1E8
396
+ }
397
+ .jqte_source textarea {
398
+ margin:0 !important;
399
+ padding:0 !important;
400
+ display:block !important;
401
+ width:100% !important;
402
+ min-height:100px;
403
+ font-family:Courier, Arial, sans-serif !important;
404
+ font-weight:normal;
405
+ font-size:15px;
406
+ overflow:hidden !important;
407
+ outline:none;
408
+ resize:none;
409
+ }
410
+ .jqte_source textarea, .jqte_source textarea:focus {
411
+ css_shadow:none !important;
412
+ background:none !important;
413
+ border:none !important;
414
+ }
415
+
416
+ /* title box */
417
+ .jqte_title {
418
+ display:none;
419
+ position:absolute;
420
+ z-index:9999;
421
+ }
422
+ .jqte_titleArrow {
423
+ position:relative;
424
+ }
425
+ .jqte_titleArrowIcon {
426
+ width:7px;
427
+ height:6px;
428
+ margin:0 auto;
429
+ background:image-url('lit/jquery-te.png') 0 -23px no-repeat;
430
+ }
431
+ .jqte_titleText {
432
+ padding:5px 7px;
433
+ margin-top:0;
434
+ min-width:5px;
435
+ min-height:1px;
436
+ max-width:400px;
437
+ background:#000;
438
+ border-radius:3px; -webkit-border-radius:3px; -moz-border-radius:3px;
439
+ word-wrap:break-word; -ms-word-wrap:break-word
440
+ }
441
+ .jqte_titleText, .jqte_titleText * {
442
+ color:#FFF;
443
+ font-size:11px
444
+ }
445
+
446
+ /* placeholder */
447
+ .jqte_placeholder {
448
+ position:relative;
449
+ display:none;
450
+ }
451
+ .jqte_placeholder_text {
452
+ position:absolute;
453
+ top:43px;
454
+ left:10px;
455
+ font-size:14px;
456
+ color:#CCC;
457
+ }
@@ -36,16 +36,12 @@ module Lit
36
36
  def get_localization_scope
37
37
  @search_options = params.slice(*valid_keys)
38
38
  @search_options[:include_completed] = '1' if @search_options.empty?
39
- @scope = LocalizationKey.uniq.search(@search_options)
39
+ @scope = LocalizationKey.uniq.preload(:localizations => :locale).search(@search_options)
40
40
  end
41
41
 
42
42
  def get_localization_keys
43
- key_parts = if @search_options[:key_prefix].present?
44
- key_parts = @search_options[:key_prefix].split('.').length
45
- else
46
- 0
47
- end
48
- @prefixes = @scope.uniq.pluck(:localization_key).map{|lk| lk.split('.').shift(key_parts+1).join('.') }.uniq.sort
43
+ key_parts = @search_options[:key_prefix].to_s.split('.').length
44
+ @prefixes = @scope.reorder(nil).uniq.pluck(:localization_key).map{|lk| lk.split('.').shift(key_parts+1).join('.') }.uniq.sort
49
45
  if @search_options[:key_prefix].present?
50
46
  parts = @search_options[:key_prefix].split('.')
51
47
  @parent_prefix = parts[0,parts.length-1].join('.')
@@ -58,8 +54,51 @@ module Lit
58
54
  end
59
55
 
60
56
  def valid_keys
61
- %w( key include_completed key_prefix )
57
+ %w( key include_completed key_prefix order )
62
58
  end
63
59
 
60
+ def grouped_localizations
61
+ @_grouped_localizations ||= begin
62
+ {}.tap do |hash|
63
+ @localization_keys.each do |lk|
64
+ hash[lk] = {}
65
+ lk.localizations.each do |l|
66
+ hash[lk][l.locale.locale.to_sym] = l
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ def localization_for(locale, localization_key)
74
+ @_localization_for ||= {}
75
+ key = [locale, localization_key]
76
+ ret = @_localization_for[key]
77
+ if ret == false
78
+ nil
79
+ elsif ret.nil?
80
+ ret = grouped_localizations[localization_key][locale]
81
+ unless ret
82
+ Lit.init.cache.refresh_key("#{locale}.#{localization_key.localization_key}")
83
+ ret = localization_key.localizations.where(:locale_id=>Lit.init.cache.find_locale(locale).id).first
84
+ end
85
+ @_localization_for[key] = ret ? ret : false
86
+ else
87
+ ret
88
+ end
89
+
90
+ end
91
+
92
+ helper_method :localization_for
93
+
94
+ def has_versions?(localization)
95
+ @_versions ||= begin
96
+ ids = grouped_localizations.values.map(&:values).flatten.map(&:id)
97
+ Lit::Localization.where(:id => ids).joins(:versions).group("#{Lit::Localization.quoted_table_name}.id").count
98
+ end
99
+ @_versions[localization.id].to_i > 0
100
+ end
101
+
102
+ helper_method :has_versions?
64
103
  end
65
104
  end
@@ -52,8 +52,24 @@ module Lit
52
52
  mark_completed!
53
53
  end
54
54
 
55
+ def self.order_options
56
+ ["localization_key asc", "localization_key desc", "created_at asc", "created_at desc"]
57
+ end
58
+
59
+ # it can be overridden in parent application, for example: {:order => "created_at desc"}
60
+ def self.default_search_options
61
+ {}
62
+ end
63
+
55
64
  def self.search(options={})
56
- s = scoped.ordered
65
+ options = options.reverse_merge(default_search_options)
66
+ s = self
67
+ if options[:order] && order_options.include?(options[:order])
68
+ column, order = options[:order].split(" ")
69
+ s = s.order("#{Lit::LocalizationKey.quoted_table_name}.#{connection.quote_column_name(column)} #{order}" )
70
+ else
71
+ s = s.ordered
72
+ end
57
73
  if options[:key_prefix].present?
58
74
  q = "#{options[:key_prefix]}%"
59
75
  s = s.where('lit_localization_keys.localization_key like ?', q)
@@ -1,4 +1,5 @@
1
1
  <h3><%= t('.header', :default=>"Localization keys") %></h3>
2
+ <% available_locales = I18n.backend.available_locales %>
2
3
 
3
4
  <table class="table">
4
5
  <%- @localization_keys.each do |lk| %>
@@ -16,13 +17,9 @@
16
17
  </div>
17
18
  <div class="detail_wrapper">
18
19
  <table class="table table-bordered table-striped">
19
- <%- I18n.backend.available_locales.each do |locale| %>
20
- <%- localization = lk.localizations.where(:locale_id=>Lit.init.cache.find_locale(locale).id).first %>
20
+ <%- available_locales.each do |locale| %>
21
+ <%- localization = localization_for(locale, lk) %>
21
22
  <tr>
22
- <% unless localization %>
23
- <% Lit.init.cache.refresh_key("#{locale}.#{lk.localization_key}") %>
24
- <%- localization = lk.localizations.where(:locale_id=>Lit.init.cache.find_locale(locale).id).first %>
25
- <% end %>
26
23
  <td class="localization_row" data-id="<%= localization.id%>" data-edit="<%= edit_localization_key_localization_path(lk, localization) %>" data-editing=0 data-content="">
27
24
  <%= render :partial=>"localization_row", :locals=>{:localization=>Lit.init.cache["#{locale}.#{lk.localization_key}"]} %>
28
25
  </td>
@@ -30,7 +27,7 @@
30
27
  <%= image_tag "lit/famfamfam_flags/#{locale[0,2]}.png" %>
31
28
  <%= locale %>
32
29
  <% if localization %>
33
- <%= link_to lit.previous_versions_localization_key_localization_path(lk, localization), :class=>"show_prev_versions #{'hidden' if localization.versions.empty?}", :remote=>true do %>
30
+ <%= link_to lit.previous_versions_localization_key_localization_path(lk, localization), :class=>"show_prev_versions #{'hidden' unless has_versions?(localization)}", :remote=>true do %>
34
31
  <%= draw_icon 'random', :title=>t('lit.common.previous_versions', :default=>"Previous versions") %>
35
32
  <% end %>
36
33
  <% end %>
@@ -78,10 +75,18 @@
78
75
  starred
79
76
  <% end %>
80
77
  </li>
78
+ <li class="nav-header"><%= t(".order_by", :default => "Order by") %>:</li>
79
+ <% Lit::LocalizationKey.order_options.each do |order| %>
80
+ <li class="<%= "active" if order == @search_options[:order] %>">
81
+ <%= link_to url_for(@search_options.merge(:order => order)) do %>
82
+ <%= t("lit.order_options.#{order.gsub(" ", "_")}", :default => order.humanize) %>
83
+ <% end %>
84
+ </li>
85
+ <% end %>
81
86
  <li class="nav-header">Narrow with prefix</li>
82
87
  <% if @search_options[:key_prefix].present? %>
83
88
  <li>
84
- <%= link_to url_for(:key_prefix=>p, :key=>@search_options[:key], :include_completed=>@search_options[:include_completed]), :title=>(@parent_prefix.present? ? @parent_prefix : 'show all') do %>
89
+ <%= link_to url_for(@search_options.merge(:key_prefix=>p)), :title=>(@parent_prefix.present? ? @parent_prefix : 'show all') do %>
85
90
  <%= draw_icon('chevron-left') %>
86
91
  <%= @parent_prefix.present? ? @parent_prefix.split('.').last : 'show all' %>
87
92
  <% end %>
@@ -89,7 +94,7 @@
89
94
  <% end %>
90
95
  <% @prefixes.each do |p| %>
91
96
  <li class="key_prefix">
92
- <%= link_to url_for(:key_prefix=>p, :key=>@search_options[:key], :include_completed=>@search_options[:include_completed]) do %>
97
+ <%= link_to url_for(@search_options.merge(:key_prefix=>p)) do %>
93
98
  <%= draw_icon('chevron-right') %>
94
99
  <%= p.split('.').last %>
95
100
  <% end %>
@@ -8,7 +8,12 @@
8
8
  </ul>
9
9
  <% else %>
10
10
  <%= f.text_area :translated_value, :size=>"40x2", :class=>"input-xxlarge" %>
11
+ <br />
12
+ <label>
13
+ <input type="checkbox" class="wysiwyg_switch" /> use wysiwyg editor
14
+ </label>
11
15
  <% end %>
16
+
12
17
  <button class="btn" type="submit"><%= t('lit.common.update', :default=>"Update") %></button>
13
18
  <button class="btn cancel"><%= t('lit.common.cancel', :default=>'Cancel') %></button>
14
19
  <% end %>
@@ -1,4 +1,7 @@
1
1
  var $row = $('td.localization_row[data-id="<%= @localization.id %>"]');
2
2
  $row.data('editing', 1);
3
3
  $row.html("<%= ejs render(:partial=>'form') %>");
4
- $row.find('textarea').focus();
4
+ $row.find('textarea').focus();
5
+ <% if @localization.full_key.ends_with?('_html') -%>
6
+ $row.find('.wysiwyg_switch').click();
7
+ <% end %>
@@ -30,6 +30,6 @@
30
30
  </div>
31
31
 
32
32
  <div class="actions">
33
- <%= f.submit t('lit.common.save'), :class=>"btn" %>
33
+ <%= f.submit t('lit.common.save', :default => "Save"), :class=>"btn" %>
34
34
  </div>
35
35
  <% end %>
@@ -1,3 +1,21 @@
1
+ module I18n
2
+ class << self
3
+ @@cache_store = nil
4
+
5
+ def cache_store
6
+ @@cache_store || I18n.backend.cache
7
+ end
8
+
9
+ def cache_store=(store)
10
+ @@cache_store = store
11
+ end
12
+
13
+ def perform_caching?
14
+ !cache_store.nil?
15
+ end
16
+ end
17
+ end
18
+
1
19
  module Lit
2
20
  class Cache
3
21
 
@@ -42,6 +60,13 @@ module Lit
42
60
  @localizations[key] = localization.get_value if localization
43
61
  end
44
62
 
63
+ def delete_locale(key)
64
+ key = key.to_s
65
+ locale_key, key_without_locale = split_key(key)
66
+ locale = find_locale(locale_key)
67
+ delete_localization(locale, key_without_locale)
68
+ end
69
+
45
70
  def load_all_translations(oninit=false)
46
71
  doinit = false
47
72
  first = Localization.order('id ASC').first
@@ -83,6 +108,8 @@ module Lit
83
108
  load_all_translations
84
109
  end
85
110
 
111
+ alias_method :clear, :reset
112
+
86
113
  def find_locale(locale_key)
87
114
  locale_key = locale_key.to_s
88
115
  @locale_cache ||= {}
@@ -178,6 +205,15 @@ module Lit
178
205
  end
179
206
  end
180
207
 
208
+ def delete_localization(locale, key_without_locale)
209
+ localization = find_localization(locale, key_without_locale)
210
+ if localization.persisted?
211
+ @localizations.delete("#{locale.locale}.#{key_without_locale}")
212
+ @localization_keys.delete(key_without_locale)
213
+ localization.destroy # or localization.default_value = nil; localization.save!
214
+ end
215
+ end
216
+
181
217
  ## checks parameter type and returns value basing on it
182
218
  ## symbols are beeing looked up in db
183
219
  ## string are returned directly
@@ -196,7 +232,7 @@ module Lit
196
232
  when String then
197
233
  new_value = v
198
234
  when Proc then
199
- new_value = v.call
235
+ new_value = nil # was v.call - requires more love
200
236
  else
201
237
  new_value = v.to_s
202
238
  end
@@ -213,10 +249,7 @@ module Lit
213
249
  end
214
250
 
215
251
  def split_key(key)
216
- key_split = key.split('.')
217
- locale_key = key_split.first
218
- key_without_locale = key_split[1..-1].join('.')
219
- [locale_key, key_without_locale]
252
+ key.split('.', 2)
220
253
  end
221
254
 
222
255
  def find_or_create_localization_key(key_without_locale)
@@ -4,6 +4,8 @@ module Lit
4
4
  class I18nBackend
5
5
  include I18n::Backend::Simple::Implementation
6
6
 
7
+ attr_reader :cache
8
+
7
9
  def initialize(cache)
8
10
  @cache = cache
9
11
  end
@@ -18,7 +20,7 @@ module Lit
18
20
  end
19
21
 
20
22
  def available_locales
21
- Lit::Locale.ordered.visible.all.map{|l| l.locale.to_sym }
23
+ Lit::Locale.ordered.visible.map{|l| l.locale.to_sym }
22
24
  end
23
25
 
24
26
  # Stores the given translations.
@@ -39,6 +41,8 @@ module Lit
39
41
 
40
42
  ## check in cache or in simple backend
41
43
  content = @cache[key_with_locale] || super
44
+ return content if parts.size <= 1
45
+
42
46
  newly_created = false
43
47
  unless @cache.has_key?(key_with_locale)
44
48
  @cache.init_key_with_value(key_with_locale, content)
@@ -59,25 +63,29 @@ module Lit
59
63
  end
60
64
  elsif data.respond_to?(:to_str)
61
65
  key = ([locale] + scope).join('.')
62
- @cache[key] = data
66
+ @cache[key] ||= data
67
+ elsif data.nil?
68
+ key = ([locale] + scope).join('.')
69
+ @cache.delete_locale(key)
63
70
  end
64
71
  end
65
72
 
66
73
  def load_translations(*filenames)
67
- super
68
74
  @cache.load_all_translations
75
+ super
69
76
  end
70
77
 
71
78
  def default(locale, object, subject, options = {})
72
79
  content = super(locale, object, subject, options)
73
80
  if content.respond_to?(:to_str)
74
81
  parts = I18n.normalize_keys(locale, object, options[:scope], options[:separator])
75
- key = parts.join('.')
76
- @cache[key] = content
82
+ if parts.size > 1
83
+ key = parts.join('.')
84
+ @cache[key] = content
85
+ end
77
86
  end
78
87
  content
79
88
  end
80
89
 
81
- attr_reader :cache
82
90
  end
83
91
  end
@@ -1,3 +1,3 @@
1
1
  module Lit
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-25 00:00:00.000000000 Z
12
+ date: 2013-10-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -381,13 +381,16 @@ files:
381
381
  - app/assets/images/lit/famfamfam_flags/za.png
382
382
  - app/assets/images/lit/famfamfam_flags/zm.png
383
383
  - app/assets/images/lit/famfamfam_flags/zw.png
384
+ - app/assets/images/lit/jquery-te.png
384
385
  - app/assets/javascripts/lit/application.js
385
386
  - app/assets/javascripts/lit/bootstrap.js.coffee
386
387
  - app/assets/javascripts/lit/dashboard.js
388
+ - app/assets/javascripts/lit/jquery-te-1.4.0.min.js
387
389
  - app/assets/javascripts/lit/localizations.js.coffee
388
390
  - app/assets/stylesheets/lit/application.css
389
391
  - app/assets/stylesheets/lit/bootstrap_and_overrides.css.scss
390
392
  - app/assets/stylesheets/lit/dashboard.css
393
+ - app/assets/stylesheets/lit/jquery-te-1.4.0.css.scss
391
394
  - app/controllers/lit/api/v1/base_controller.rb
392
395
  - app/controllers/lit/api/v1/locales_controller.rb
393
396
  - app/controllers/lit/api/v1/localization_keys_controller.rb
@@ -430,7 +433,7 @@ files:
430
433
  - app/views/lit/localization_keys/star.js.erb
431
434
  - app/views/lit/localizations/_form.html.erb
432
435
  - app/views/lit/localizations/_previous_versions_rows.html.erb
433
- - app/views/lit/localizations/edit.html.erb
436
+ - app/views/lit/localizations/edit.js.erb
434
437
  - app/views/lit/localizations/previous_versions.js.erb
435
438
  - app/views/lit/localizations/update.js.erb
436
439
  - app/views/lit/sources/_form.html.erb
@@ -464,7 +467,8 @@ files:
464
467
  - Rakefile
465
468
  - README.md
466
469
  homepage: https://github.com/prograils/lit
467
- licenses: []
470
+ licenses:
471
+ - MIT
468
472
  post_install_message:
469
473
  rdoc_options: []
470
474
  require_paths: