interpret 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/app/controllers/interpret/base_controller.rb +10 -0
- data/app/controllers/interpret/search_controller.rb +7 -0
- data/app/controllers/interpret/tools_controller.rb +39 -0
- data/app/controllers/interpret/translations_controller.rb +47 -0
- data/app/models/interpret/translation.rb +257 -0
- data/app/sweepers/interpret/base_sweeper.rb +14 -0
- data/app/sweepers/interpret/translation_sweeper.rb +14 -0
- data/app/views/interpret/search/index.html.erb +29 -0
- data/app/views/interpret/search/perform.html.erb +38 -0
- data/app/views/interpret/tools/index.html.erb +38 -0
- data/app/views/interpret/translations/_form.html.erb +5 -0
- data/app/views/interpret/translations/_listing.html.erb +22 -0
- data/app/views/interpret/translations/edit.html.erb +5 -0
- data/app/views/interpret/translations/index.html.erb +28 -0
- data/app/views/layouts/interpret.html.erb +41 -0
- data/config/routes.rb +20 -0
- data/interpret.gemspec +30 -0
- data/lib/generators/interpret/migration_generator.rb +25 -0
- data/lib/generators/interpret/setup_generator.rb +21 -0
- data/lib/generators/interpret/templates/migration.rb +16 -0
- data/lib/generators/interpret/views_generator.rb +16 -0
- data/lib/interpret/capistrano.rb +15 -0
- data/lib/interpret/engine.rb +23 -0
- data/lib/interpret/helpers.rb +45 -0
- data/lib/interpret/lazy_hash.rb +21 -0
- data/lib/interpret/logger.rb +7 -0
- data/lib/interpret/version.rb +3 -0
- data/lib/interpret.rb +30 -0
- data/lib/tasks/interpret.rake +11 -0
- data/public/javascripts/jquery.purr.js +180 -0
- data/public/stylesheets/folder.png +0 -0
- data/public/stylesheets/interpret_style.css +542 -0
- data/test_app/Gemfile +11 -0
- data/test_app/README +256 -0
- data/test_app/Rakefile +7 -0
- data/test_app/app/controllers/application_controller.rb +3 -0
- data/test_app/app/controllers/pages_controller.rb +3 -0
- data/test_app/app/helpers/application_helper.rb +2 -0
- data/test_app/app/sweepers/page_sweeper.rb +12 -0
- data/test_app/app/views/layouts/application.html.erb +15 -0
- data/test_app/app/views/pages/contact.html.haml +8 -0
- data/test_app/app/views/pages/index.html.haml +9 -0
- data/test_app/config/application.rb +42 -0
- data/test_app/config/boot.rb +13 -0
- data/test_app/config/database.yml +23 -0
- data/test_app/config/environment.rb +5 -0
- data/test_app/config/environments/development.rb +27 -0
- data/test_app/config/environments/production.rb +51 -0
- data/test_app/config/environments/test.rb +35 -0
- data/test_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test_app/config/initializers/inflections.rb +10 -0
- data/test_app/config/initializers/interpret.rb +2 -0
- data/test_app/config/initializers/mime_types.rb +5 -0
- data/test_app/config/initializers/secret_token.rb +7 -0
- data/test_app/config/initializers/session_store.rb +8 -0
- data/test_app/config/locales/ca.yml +6 -0
- data/test_app/config/locales/es.yml +48 -0
- data/test_app/config/routes.rb +4 -0
- data/test_app/config.ru +4 -0
- data/test_app/db/migrate/20110209185258_interpret_create_translations.rb +16 -0
- data/test_app/db/schema.rb +23 -0
- data/test_app/db/seeds.rb +0 -0
- data/test_app/lib/lazy_hash.rb +22 -0
- data/test_app/lib/tasks/.gitkeep +0 -0
- data/test_app/lib/tasks/setup.rake +19 -0
- data/test_app/public/404.html +26 -0
- data/test_app/public/422.html +26 -0
- data/test_app/public/500.html +26 -0
- data/test_app/public/favicon.ico +0 -0
- data/test_app/public/index.html +29 -0
- data/test_app/public/javascripts/application.js +2 -0
- data/test_app/public/javascripts/best_in_place.js +456 -0
- data/test_app/public/javascripts/controls.js +965 -0
- data/test_app/public/javascripts/dragdrop.js +974 -0
- data/test_app/public/javascripts/effects.js +1123 -0
- data/test_app/public/javascripts/jquery.purr.js +180 -0
- data/test_app/public/javascripts/prototype.js +6001 -0
- data/test_app/public/javascripts/rails.js +134 -0
- data/test_app/public/robots.txt +5 -0
- data/test_app/public/stylesheets/.gitkeep +0 -0
- data/test_app/public/stylesheets/folder.png +0 -0
- data/test_app/public/stylesheets/interpret_style.css +530 -0
- data/test_app/script/rails +6 -0
- data/test_app/vendor/plugins/.gitkeep +0 -0
- metadata +262 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
class InterpretCreateTranslations < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :translations do |t|
|
4
|
+
t.string :locale
|
5
|
+
t.string :key
|
6
|
+
t.text :value
|
7
|
+
t.text :interpolations
|
8
|
+
t.boolean :is_proc, :default => false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table :translations
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended to check this file into your version control system.
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(:version => 20110209185258) do
|
14
|
+
|
15
|
+
create_table "translations", :force => true do |t|
|
16
|
+
t.string "locale"
|
17
|
+
t.string "key"
|
18
|
+
t.text "value"
|
19
|
+
t.text "interpolations"
|
20
|
+
t.boolean "is_proc", :default => false
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
File without changes
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# from https://gist.github.com/745617
|
2
|
+
|
3
|
+
module LazyHash
|
4
|
+
class << self
|
5
|
+
def lazy_add(hash, key, value, pre = nil)
|
6
|
+
skeys = key.split(".")
|
7
|
+
f = skeys.shift
|
8
|
+
if skeys.empty?
|
9
|
+
pre.nil? ? hash.send("[]=", f, value) : pre.send("[]=", f, value)
|
10
|
+
else
|
11
|
+
pre = pre.nil? ? hash.send("[]", f) : pre.send("[]", f)
|
12
|
+
lazy_add(hash, skeys.join("."), value, pre)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_hash
|
17
|
+
lazy = lambda { |h,k| h[k] = Hash.new(&lazy) }
|
18
|
+
Hash.new(&lazy)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
desc "Setup initial files for the app"
|
2
|
+
task :setup do
|
3
|
+
dir = "#{File.dirname(__FILE__)}/../../config/"
|
4
|
+
stubs = Dir[dir+ "*_example.yml"]
|
5
|
+
|
6
|
+
stubs.each do |file|
|
7
|
+
file =~ /(\w*)_example/
|
8
|
+
new_file = "#{dir}#{$1}.yml"
|
9
|
+
unless File.file?(new_file)
|
10
|
+
`cp #{dir}#{File.basename(file)} #{new_file}`
|
11
|
+
puts "Created file #{$1}.yml"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
`mkdir -p log`
|
16
|
+
`touch log/interpret.log`
|
17
|
+
end
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/404.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
23
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/422.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>The change you wanted was rejected.</h1>
|
23
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
File without changes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Cuca</title>
|
5
|
+
<link href="/stylesheets/interpret_style.css?1296240615" media="screen" rel="stylesheet" type="text/css" />
|
6
|
+
<script src="/javascripts/prototype.js?1296172967" type="text/javascript"></script>
|
7
|
+
<script src="/javascripts/effects.js?1296172967" type="text/javascript"></script>
|
8
|
+
<script src="/javascripts/dragdrop.js?1296172967" type="text/javascript"></script>
|
9
|
+
<script src="/javascripts/controls.js?1296172967" type="text/javascript"></script>
|
10
|
+
<script src="/javascripts/rails.js?1296172967" type="text/javascript"></script>
|
11
|
+
<script src="/javascripts/application.js?1296172967" type="text/javascript"></script>
|
12
|
+
<meta name="csrf-param" content="authenticity_token"/>
|
13
|
+
<meta name="csrf-token" content="q34JNbHJc2SgY2HwPZZCzuWwThAHB+394DaACl2h9M4="/>
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
This is the APPLICATION main Layout
|
17
|
+
<h1>Ara canvio cucamonga</h1>
|
18
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac odio quis dui tincidunt facilisis vitae sit amet nulla. Fusce tincidunt tempor dolor a ornare. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris placerat tincidunt tempus. Nullam at tortor sed magna aliquet pharetra. Curabitur lectus nulla, egestas in ultricies eu, euismod mollis quam.</p>
|
19
|
+
<h1>SEO experts will eventually decline</h1>
|
20
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ac odio quis dui tincidunt facilisis vitae sit amet nulla. Fusce tincidunt tempor dolor a ornare. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris placerat tincidunt tempus. Nullam at tortor sed magna aliquet pharetra. Curabitur lectus nulla, egestas in ultricies eu, euismod mollis quam.</p>
|
21
|
+
<h1>Designers will eventually master programming languages</h1>
|
22
|
+
<p>Aliquam eros enim, malesuada ac rutrum eget, tempor et tellus. Duis egestas, lectus vel blandit mollis, lectus tellus tristique lacus, vel iaculis enim sem vitae orci. In nibh nulla, congue et tempor sed, elementum eu risus. Quisque tempus commodo pretium. Suspendisse gravida ante metus, id placerat sapien. Vestibulum vulputate suscipit massa id cursus. Curabitur sit amet mollis quam. Aliquam erat volutpat. In commodo faucibus massa, id dignissim dui sollicitudin ac. Aenean lobortis consequat lacus, non lobortis ligula pellentesque at. Nunc porta placerat eros in consectetur. Pellentesque et turpis risus. Vestibulum arcu eros, sodales vitae molestie id, aliquet et diam. Duis euismod mollis metus eleifend accumsan. Suspendisse in mollis nisi. Curabitur lorem orci, auctor sed rutrum at, euismod id lacus. Etiam luctus, nunc at ultricies pharetra, ante ante porttitor magna, sit amet fringilla diam dolor id felis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec id feugiat dui.</p>
|
23
|
+
<p><strong>Pellentesque habitant morbi tristique</strong> senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. <em>Aenean ultricies mi vitae est.</em> Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, <code>commodo vitae</code>, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. <a href='#'>Donec non enim</a> in turpis pulvinar facilisis. Ut felis.</p>
|
24
|
+
<a href="/interpret">Traduccions</a>
|
25
|
+
|
26
|
+
|
27
|
+
</body>
|
28
|
+
</html>
|
29
|
+
|
@@ -0,0 +1,456 @@
|
|
1
|
+
/*
|
2
|
+
BestInPlace (for jQuery)
|
3
|
+
version: 0.1.0 (01/01/2011)
|
4
|
+
@requires jQuery >= v1.4
|
5
|
+
@requires jQuery.purr to display pop-up windows
|
6
|
+
|
7
|
+
By Bernat Farrero based on the work of Jan Varwig.
|
8
|
+
Examples at http://bernatfarrero.com
|
9
|
+
|
10
|
+
Licensed under the MIT:
|
11
|
+
http://www.opensource.org/licenses/mit-license.php
|
12
|
+
|
13
|
+
Usage:
|
14
|
+
|
15
|
+
Attention.
|
16
|
+
The format of the JSON object given to the select inputs is the following:
|
17
|
+
[["key", "value"],["key", "value"]]
|
18
|
+
The format of the JSON object given to the checkbox inputs is the following:
|
19
|
+
["falseValue", "trueValue"]
|
20
|
+
*/
|
21
|
+
|
22
|
+
function BestInPlaceEditor(e) {
|
23
|
+
this.element = jQuery(e);
|
24
|
+
this.initOptions();
|
25
|
+
this.bindForm();
|
26
|
+
this.initNil();
|
27
|
+
$(this.activator).bind('click', {editor: this}, this.clickHandler);
|
28
|
+
}
|
29
|
+
|
30
|
+
BestInPlaceEditor.prototype = {
|
31
|
+
// Public Interface Functions //////////////////////////////////////////////
|
32
|
+
|
33
|
+
activate : function() {
|
34
|
+
var elem = this.isNil ? "" : this.element.html();
|
35
|
+
this.oldValue = elem;
|
36
|
+
$(this.activator).unbind("click", this.clickHandler);
|
37
|
+
this.activateForm();
|
38
|
+
},
|
39
|
+
|
40
|
+
abort : function() {
|
41
|
+
if (this.isNil) this.element.html(this.nil);
|
42
|
+
else this.element.html(this.oldValue);
|
43
|
+
$(this.activator).bind('click', {editor: this}, this.clickHandler);
|
44
|
+
},
|
45
|
+
|
46
|
+
update : function() {
|
47
|
+
var editor = this;
|
48
|
+
if (this.formType in {"input":1, "textarea":1} && this.getValue() == this.oldValue)
|
49
|
+
{ // Avoid request if no change is made
|
50
|
+
this.abort();
|
51
|
+
return true;
|
52
|
+
}
|
53
|
+
this.isNil = false;
|
54
|
+
editor.ajax({
|
55
|
+
"type" : "post",
|
56
|
+
"dataType" : "text",
|
57
|
+
"data" : editor.requestData(),
|
58
|
+
"success" : function(data){ editor.loadSuccessCallback(data); },
|
59
|
+
"error" : function(request, error){ editor.loadErrorCallback(request, error); }
|
60
|
+
});
|
61
|
+
if (this.formType == "select") {
|
62
|
+
var value = this.getValue();
|
63
|
+
$.each(this.values, function(i, v) {
|
64
|
+
if (value == v[0]) {
|
65
|
+
editor.element.html(v[1]);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
);
|
69
|
+
} else if (this.formType == "checkbox") {
|
70
|
+
editor.element.html(this.getValue() ? this.values[1] : this.values[0]);
|
71
|
+
} else {
|
72
|
+
editor.element.html(this.getValue());
|
73
|
+
}
|
74
|
+
},
|
75
|
+
|
76
|
+
activateForm : function() {
|
77
|
+
alert("The form was not properly initialized. activateForm is unbound");
|
78
|
+
},
|
79
|
+
|
80
|
+
// Helper Functions ////////////////////////////////////////////////////////
|
81
|
+
|
82
|
+
initOptions : function() {
|
83
|
+
// Try parent supplied info
|
84
|
+
var self = this;
|
85
|
+
self.element.parents().each(function(){
|
86
|
+
self.url = self.url || jQuery(this).attr("data-url");
|
87
|
+
self.collection = self.collection || jQuery(this).attr("data-collection");
|
88
|
+
self.formType = self.formType || jQuery(this).attr("data-type");
|
89
|
+
self.objectName = self.objectName || jQuery(this).attr("data-object");
|
90
|
+
self.attributeName = self.attributeName || jQuery(this).attr("data-attribute");
|
91
|
+
self.nil = self.nil || jQuery(this).attr("data-nil");
|
92
|
+
});
|
93
|
+
|
94
|
+
// Try Rails-id based if parents did not explicitly supply something
|
95
|
+
self.element.parents().each(function(){
|
96
|
+
var res = this.id.match(/^(\w+)_(\d+)$/i);
|
97
|
+
if (res) {
|
98
|
+
self.objectName = self.objectName || res[1];
|
99
|
+
}
|
100
|
+
});
|
101
|
+
|
102
|
+
// Load own attributes (overrides all others)
|
103
|
+
self.url = self.element.attr("data-url") || self.url || document.location.pathname;
|
104
|
+
self.collection = self.element.attr("data-collection") || self.collection;
|
105
|
+
self.formType = self.element.attr("data-type") || self.formtype || "input";
|
106
|
+
self.objectName = self.element.attr("data-object") || self.objectName;
|
107
|
+
self.attributeName = self.element.attr("data-attribute") || self.attributeName;
|
108
|
+
self.activator = self.element.attr("data-activator") || self.element;
|
109
|
+
self.nil = self.element.attr("data-nil") || self.nil || "-";
|
110
|
+
|
111
|
+
if (!self.element.attr("data-sanitize")) {
|
112
|
+
self.sanitize = true;
|
113
|
+
}
|
114
|
+
else {
|
115
|
+
self.sanitize = (self.element.attr("data-sanitize") == "true");
|
116
|
+
}
|
117
|
+
|
118
|
+
if ((self.formType == "select" || self.formType == "checkbox") && self.collection !== null)
|
119
|
+
{
|
120
|
+
self.values = jQuery.parseJSON(self.collection);
|
121
|
+
}
|
122
|
+
},
|
123
|
+
|
124
|
+
bindForm : function() {
|
125
|
+
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
|
126
|
+
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
|
127
|
+
},
|
128
|
+
|
129
|
+
initNil: function() {
|
130
|
+
if (this.element.html() == "")
|
131
|
+
{
|
132
|
+
this.isNil = true
|
133
|
+
this.element.html(this.nil)
|
134
|
+
}
|
135
|
+
},
|
136
|
+
|
137
|
+
getValue : function() {
|
138
|
+
alert("The form was not properly initialized. getValue is unbound");
|
139
|
+
},
|
140
|
+
|
141
|
+
// Trim and Strips HTML from text
|
142
|
+
sanitizeValue : function(s) {
|
143
|
+
if (this.sanitize)
|
144
|
+
{
|
145
|
+
var tmp = document.createElement("DIV");
|
146
|
+
tmp.innerHTML = s;
|
147
|
+
s = tmp.textContent || tmp.innerText;
|
148
|
+
}
|
149
|
+
return jQuery.trim(s);
|
150
|
+
},
|
151
|
+
|
152
|
+
/* Generate the data sent in the POST request */
|
153
|
+
requestData : function() {
|
154
|
+
// To prevent xss attacks, a csrf token must be defined as a meta attribute
|
155
|
+
csrf_token = $('meta[name=csrf-token]').attr('content');
|
156
|
+
csrf_param = $('meta[name=csrf-param]').attr('content');
|
157
|
+
|
158
|
+
var data = "_method=put";
|
159
|
+
data += "&" + this.objectName + '[' + this.attributeName + ']=' + encodeURIComponent(this.getValue());
|
160
|
+
|
161
|
+
if (csrf_param !== undefined && csrf_token !== undefined) {
|
162
|
+
data += "&" + csrf_param + "=" + encodeURIComponent(csrf_token);
|
163
|
+
}
|
164
|
+
return data;
|
165
|
+
},
|
166
|
+
|
167
|
+
ajax : function(options) {
|
168
|
+
options.url = this.url;
|
169
|
+
options.beforeSend = function(xhr){ xhr.setRequestHeader("Accept", "application/json"); };
|
170
|
+
return jQuery.ajax(options);
|
171
|
+
},
|
172
|
+
|
173
|
+
// Handlers ////////////////////////////////////////////////////////////////
|
174
|
+
|
175
|
+
loadSuccessCallback : function(data) {
|
176
|
+
this.element.html(data[this.objectName]);
|
177
|
+
// Binding back after being clicked
|
178
|
+
$(this.activator).bind('click', {editor: this}, this.clickHandler);
|
179
|
+
},
|
180
|
+
|
181
|
+
loadErrorCallback : function(request, error) {
|
182
|
+
this.element.html(this.oldValue);
|
183
|
+
|
184
|
+
// Display all error messages from server side validation
|
185
|
+
$.each(jQuery.parseJSON(request.responseText), function(index, value) {
|
186
|
+
var container = $("<span class='flash-error'></span>").html(value);
|
187
|
+
container.purr();
|
188
|
+
});
|
189
|
+
|
190
|
+
// Binding back after being clicked
|
191
|
+
$(this.activator).bind('click', {editor: this}, this.clickHandler);
|
192
|
+
},
|
193
|
+
|
194
|
+
clickHandler : function(event) {
|
195
|
+
event.data.editor.activate();
|
196
|
+
}
|
197
|
+
};
|
198
|
+
|
199
|
+
|
200
|
+
BestInPlaceEditor.forms = {
|
201
|
+
"input" : {
|
202
|
+
activateForm : function() {
|
203
|
+
var output = '<form class="form_in_place" action="javascript:void(0)" style="display:inline;">';
|
204
|
+
output += '<input type="text" value="' + this.sanitizeValue(this.oldValue) + '"></form>';
|
205
|
+
this.element.html(output);
|
206
|
+
this.element.find('input')[0].select();
|
207
|
+
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
|
208
|
+
this.element.find("input").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
|
209
|
+
this.element.find("input").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
|
210
|
+
},
|
211
|
+
|
212
|
+
getValue : function() {
|
213
|
+
return this.sanitizeValue(this.element.find("input").val());
|
214
|
+
},
|
215
|
+
|
216
|
+
inputBlurHandler : function(event) {
|
217
|
+
event.data.editor.update();
|
218
|
+
},
|
219
|
+
|
220
|
+
submitHandler : function(event) {
|
221
|
+
event.data.editor.update();
|
222
|
+
},
|
223
|
+
|
224
|
+
keyupHandler : function(event) {
|
225
|
+
if (event.keyCode == 27) {
|
226
|
+
event.data.editor.abort();
|
227
|
+
}
|
228
|
+
}
|
229
|
+
},
|
230
|
+
|
231
|
+
"select" : {
|
232
|
+
activateForm : function() {
|
233
|
+
var output = "<form action='javascript:void(0)' style='display:inline;'><select>";
|
234
|
+
var selected = "";
|
235
|
+
var oldValue = this.oldValue;
|
236
|
+
$.each(this.values, function(index, value) {
|
237
|
+
selected = (value[1] == oldValue ? "selected='selected'" : "");
|
238
|
+
output += "<option value='" + value[0] + "' " + selected + ">" + value[1] + "</option>";
|
239
|
+
});
|
240
|
+
output += "</select></form>";
|
241
|
+
this.element.html(output);
|
242
|
+
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
243
|
+
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
244
|
+
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
|
245
|
+
this.element.find("select")[0].focus();
|
246
|
+
},
|
247
|
+
|
248
|
+
getValue : function() {
|
249
|
+
return this.sanitizeValue(this.element.find("select").val());
|
250
|
+
},
|
251
|
+
|
252
|
+
blurHandler : function(event) {
|
253
|
+
event.data.editor.update();
|
254
|
+
},
|
255
|
+
|
256
|
+
keyupHandler : function(event) {
|
257
|
+
if (event.keyCode == 27) event.data.editor.abort();
|
258
|
+
}
|
259
|
+
},
|
260
|
+
|
261
|
+
"checkbox" : {
|
262
|
+
activateForm : function() {
|
263
|
+
var newValue = Boolean(this.oldValue != this.values[1]);
|
264
|
+
var output = newValue ? this.values[1] : this.values[0];
|
265
|
+
this.element.html(output);
|
266
|
+
this.update();
|
267
|
+
},
|
268
|
+
|
269
|
+
getValue : function() {
|
270
|
+
return Boolean(this.element.html() == this.values[1]);
|
271
|
+
}
|
272
|
+
},
|
273
|
+
|
274
|
+
"textarea" : {
|
275
|
+
activateForm : function() {
|
276
|
+
// grab width and height of text
|
277
|
+
width = this.element.css('width');
|
278
|
+
height = this.element.css('height');
|
279
|
+
|
280
|
+
// construct the form
|
281
|
+
var output = '<form action="javascript:void(0)" style="display:inline;"><textarea>';
|
282
|
+
output += this.sanitizeValue(this.oldValue);
|
283
|
+
output += '</textarea></form>';
|
284
|
+
this.element.html(output);
|
285
|
+
|
286
|
+
// set width and height of textarea
|
287
|
+
jQuery(this.element.find("textarea")[0]).css({ 'min-width': width, 'min-height': height });
|
288
|
+
jQuery(this.element.find("textarea")[0]).elastic();
|
289
|
+
|
290
|
+
this.element.find("textarea")[0].focus();
|
291
|
+
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
|
292
|
+
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
|
293
|
+
},
|
294
|
+
|
295
|
+
getValue : function() {
|
296
|
+
return this.sanitizeValue(this.element.find("textarea").val());
|
297
|
+
},
|
298
|
+
|
299
|
+
blurHandler : function(event) {
|
300
|
+
event.data.editor.update();
|
301
|
+
},
|
302
|
+
|
303
|
+
keyupHandler : function(event) {
|
304
|
+
if (event.keyCode == 27) {
|
305
|
+
BestInPlaceEditor.forms.textarea.abort(event.data.editor);
|
306
|
+
}
|
307
|
+
},
|
308
|
+
|
309
|
+
abort : function(editor) {
|
310
|
+
if (confirm("Are you sure you want to discard your changes?")) {
|
311
|
+
editor.abort();
|
312
|
+
}
|
313
|
+
}
|
314
|
+
}
|
315
|
+
};
|
316
|
+
|
317
|
+
jQuery.fn.best_in_place = function() {
|
318
|
+
this.each(function(){
|
319
|
+
jQuery(this).data('bestInPlaceEditor', new BestInPlaceEditor(this));
|
320
|
+
});
|
321
|
+
return this;
|
322
|
+
};
|
323
|
+
|
324
|
+
|
325
|
+
|
326
|
+
/**
|
327
|
+
* @name Elastic
|
328
|
+
* @descripton Elastic is Jquery plugin that grow and shrink your textareas automaticliy
|
329
|
+
* @version 1.6.5
|
330
|
+
* @requires Jquery 1.2.6+
|
331
|
+
*
|
332
|
+
* @author Jan Jarfalk
|
333
|
+
* @author-email jan.jarfalk@unwrongest.com
|
334
|
+
* @author-website http://www.unwrongest.com
|
335
|
+
*
|
336
|
+
* @licens MIT License - http://www.opensource.org/licenses/mit-license.php
|
337
|
+
*/
|
338
|
+
|
339
|
+
(function(jQuery){
|
340
|
+
jQuery.fn.extend({
|
341
|
+
elastic: function() {
|
342
|
+
// We will create a div clone of the textarea
|
343
|
+
// by copying these attributes from the textarea to the div.
|
344
|
+
var mimics = [
|
345
|
+
'paddingTop',
|
346
|
+
'paddingRight',
|
347
|
+
'paddingBottom',
|
348
|
+
'paddingLeft',
|
349
|
+
'fontSize',
|
350
|
+
'lineHeight',
|
351
|
+
'fontFamily',
|
352
|
+
'width',
|
353
|
+
'fontWeight'];
|
354
|
+
|
355
|
+
return this.each( function() {
|
356
|
+
|
357
|
+
// Elastic only works on textareas
|
358
|
+
if ( this.type != 'textarea' ) {
|
359
|
+
return false;
|
360
|
+
}
|
361
|
+
|
362
|
+
var $textarea = jQuery(this),
|
363
|
+
$twin = jQuery('<div />').css({'position': 'absolute','display':'none','word-wrap':'break-word'}),
|
364
|
+
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
|
365
|
+
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
|
366
|
+
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
|
367
|
+
goalheight = 0,
|
368
|
+
i = 0;
|
369
|
+
|
370
|
+
// Opera returns max-height of -1 if not set
|
371
|
+
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
|
372
|
+
|
373
|
+
// Append the twin to the DOM
|
374
|
+
// We are going to meassure the height of this, not the textarea.
|
375
|
+
$twin.appendTo($textarea.parent());
|
376
|
+
|
377
|
+
// Copy the essential styles (mimics) from the textarea to the twin
|
378
|
+
var i = mimics.length;
|
379
|
+
while(i--){
|
380
|
+
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
|
381
|
+
}
|
382
|
+
|
383
|
+
|
384
|
+
// Sets a given height and overflow state on the textarea
|
385
|
+
function setHeightAndOverflow(height, overflow){
|
386
|
+
curratedHeight = Math.floor(parseInt(height,10));
|
387
|
+
if($textarea.height() != curratedHeight){
|
388
|
+
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
|
389
|
+
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
|
394
|
+
// This function will update the height of the textarea if necessary
|
395
|
+
function update() {
|
396
|
+
|
397
|
+
// Get curated content from the textarea.
|
398
|
+
var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ /g, ' ').replace(/<|>/g, '>').replace(/\n/g, '<br />');
|
399
|
+
|
400
|
+
// Compare curated content with curated twin.
|
401
|
+
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
|
402
|
+
|
403
|
+
if(textareaContent+' ' != twinContent){
|
404
|
+
|
405
|
+
// Add an extra white space so new rows are added when you are at the end of a row.
|
406
|
+
$twin.html(textareaContent+' ');
|
407
|
+
|
408
|
+
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
|
409
|
+
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
|
410
|
+
|
411
|
+
var goalheight = $twin.height()+lineHeight;
|
412
|
+
if(goalheight >= maxheight) {
|
413
|
+
setHeightAndOverflow(maxheight,'auto');
|
414
|
+
} else if(goalheight <= minheight) {
|
415
|
+
setHeightAndOverflow(minheight,'hidden');
|
416
|
+
} else {
|
417
|
+
setHeightAndOverflow(goalheight,'hidden');
|
418
|
+
}
|
419
|
+
|
420
|
+
}
|
421
|
+
|
422
|
+
}
|
423
|
+
|
424
|
+
}
|
425
|
+
|
426
|
+
// Hide scrollbars
|
427
|
+
$textarea.css({'overflow':'hidden'});
|
428
|
+
|
429
|
+
// Update textarea size on keyup, change, cut and paste
|
430
|
+
$textarea.bind('keyup change cut paste', function(){
|
431
|
+
update();
|
432
|
+
});
|
433
|
+
|
434
|
+
// Compact textarea on blur
|
435
|
+
// Lets animate this....
|
436
|
+
$textarea.bind('blur',function(){
|
437
|
+
if($twin.height() < maxheight){
|
438
|
+
if($twin.height() > minheight) {
|
439
|
+
$textarea.height($twin.height());
|
440
|
+
} else {
|
441
|
+
$textarea.height(minheight);
|
442
|
+
}
|
443
|
+
}
|
444
|
+
});
|
445
|
+
|
446
|
+
// And this line is to catch the browser paste event
|
447
|
+
$textarea.live('input paste',function(e){ setTimeout( update, 250); });
|
448
|
+
|
449
|
+
// Run update once when elastic is initialized
|
450
|
+
update();
|
451
|
+
|
452
|
+
});
|
453
|
+
|
454
|
+
}
|
455
|
+
});
|
456
|
+
})(jQuery);
|