transit 0.0.1 → 0.0.2
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.
- data/Gemfile +19 -11
- data/app/assets/images/transit/icon24x24.png +0 -0
- data/app/assets/images/transit/icon24x24_files.png +0 -0
- data/app/assets/images/transit/jplayer.swf +0 -0
- data/app/assets/images/transit/uploadify.swf +0 -0
- data/app/assets/images/transit/video_player.swf +0 -0
- data/app/assets/javascripts/jqtools/expose.js +224 -0
- data/app/assets/javascripts/jqtools/flashembed.js +300 -0
- data/app/assets/javascripts/jqtools/overlay.js +294 -0
- data/app/assets/javascripts/jqtools/scrollable.js +3 -0
- data/app/assets/javascripts/jqtools/scrollable/autoscroll.js +81 -0
- data/app/assets/javascripts/jqtools/scrollable/base.js +335 -0
- data/app/assets/javascripts/jqtools/scrollable/navigator.js +139 -0
- data/app/assets/javascripts/jqtools/validator.js +590 -0
- data/app/assets/javascripts/jqueryui/accordion.js +611 -0
- data/app/assets/javascripts/jqueryui/autocomplete.js +612 -0
- data/app/assets/javascripts/jqueryui/button.js +388 -0
- data/app/assets/javascripts/jqueryui/core.js +312 -0
- data/app/assets/javascripts/jqueryui/datepicker.js +1791 -0
- data/app/assets/javascripts/jqueryui/dialog.js +878 -0
- data/app/assets/javascripts/jqueryui/draggable.js +815 -0
- data/app/assets/javascripts/jqueryui/droppable.js +285 -0
- data/app/assets/javascripts/jqueryui/effects/blind.js +49 -0
- data/app/assets/javascripts/jqueryui/effects/bounce.js +78 -0
- data/app/assets/javascripts/jqueryui/effects/clip.js +54 -0
- data/app/assets/javascripts/jqueryui/effects/core.js +746 -0
- data/app/assets/javascripts/jqueryui/effects/drop.js +50 -0
- data/app/assets/javascripts/jqueryui/effects/explode.js +79 -0
- data/app/assets/javascripts/jqueryui/effects/fade.js +32 -0
- data/app/assets/javascripts/jqueryui/effects/fold.js +56 -0
- data/app/assets/javascripts/jqueryui/effects/highlight.js +50 -0
- data/app/assets/javascripts/jqueryui/effects/pulsate.js +51 -0
- data/app/assets/javascripts/jqueryui/effects/scale.js +178 -0
- data/app/assets/javascripts/jqueryui/effects/shake.js +57 -0
- data/app/assets/javascripts/jqueryui/effects/slide.js +50 -0
- data/app/assets/javascripts/jqueryui/effects/transfer.js +45 -0
- data/app/assets/javascripts/jqueryui/mouse.js +160 -0
- data/app/assets/javascripts/jqueryui/position.js +252 -0
- data/app/assets/javascripts/jqueryui/progressbar.js +109 -0
- data/app/assets/javascripts/jqueryui/resizable.js +814 -0
- data/app/assets/javascripts/jqueryui/selectable.js +266 -0
- data/app/assets/javascripts/jqueryui/slider.js +666 -0
- data/app/assets/javascripts/jqueryui/sortable.js +1077 -0
- data/app/assets/javascripts/jqueryui/tabs.js +758 -0
- data/app/assets/javascripts/jqueryui/widget.js +262 -0
- data/app/assets/javascripts/libs/backbone.js +1152 -0
- data/app/assets/javascripts/libs/cookie.js +89 -0
- data/app/assets/javascripts/libs/fileinput.js +130 -0
- data/app/assets/javascripts/libs/jplayer.js +1768 -0
- data/app/assets/javascripts/libs/proper.js +541 -0
- data/app/assets/javascripts/libs/sanitize.js +282 -0
- data/app/assets/javascripts/libs/selecttolist.js +75 -0
- data/app/assets/javascripts/libs/underscore.js +807 -0
- data/app/assets/javascripts/libs/uploadify.js +677 -0
- data/app/assets/javascripts/libs/wymeditor.js +9538 -0
- data/app/assets/javascripts/transit.js +4 -0
- data/app/assets/javascripts/transit/admin.js +22 -0
- data/app/assets/javascripts/transit/admin/contexts.js +52 -0
- data/app/assets/javascripts/transit/admin/fields.js +36 -0
- data/app/assets/javascripts/transit/admin/upload.js +109 -0
- data/app/assets/javascripts/transit/config.js.erb +101 -0
- data/app/assets/javascripts/transit/contexts/audio.js +39 -0
- data/app/assets/javascripts/transit/contexts/video.js +79 -0
- data/app/assets/javascripts/transit/core.js +171 -0
- data/app/assets/javascripts/transit/frontend.js +3 -0
- data/app/assets/javascripts/transit/lib/base64.js +120 -0
- data/app/assets/javascripts/transit/lib/editor.js +177 -0
- data/app/assets/javascripts/transit/views/audio_player.jst +22 -0
- data/app/assets/javascripts/transit/views/editor_toolbar.jst +12 -0
- data/app/assets/javascripts/transit/views/file_upload.jst +5 -0
- data/app/assets/javascripts/transit/views/video_player.jst +20 -0
- data/app/assets/javascripts/transit/views/wym_box.jst +4 -0
- data/app/assets/javascripts/transit/views/wym_iframe.jst +3 -0
- data/app/assets/stylesheets/transit.css.scss.erb +42 -0
- data/app/assets/stylesheets/transit/forms.css.scss +66 -0
- data/app/assets/stylesheets/transit/media/audio.css.scss +65 -0
- data/app/assets/stylesheets/transit/media/video.css.scss +30 -0
- data/app/assets/stylesheets/transit/panel.css.scss +100 -0
- data/app/assets/stylesheets/transit/ui.css.scss +507 -0
- data/app/controllers/pages_controller.rb +3 -0
- data/app/controllers/posts_controller.rb +3 -0
- data/app/controllers/transit/assets_controller.rb +38 -0
- data/app/controllers/transit/contexts_controller.rb +12 -9
- data/app/controllers/transit/pages_controller.rb +26 -0
- data/app/controllers/transit/posts_controller.rb +31 -0
- data/app/controllers/transit/topics_controller.rb +5 -0
- data/app/controllers/transit_controller.rb +16 -0
- data/app/helpers/transit/admin_helper.rb +43 -0
- data/app/helpers/transit/form_helper.rb +17 -0
- data/app/helpers/transit/package_helper.rb +41 -0
- data/app/helpers/transit/pagination_helper.rb +58 -0
- data/app/helpers/transit_helper.rb +42 -0
- data/app/models/comment.rb +37 -0
- data/app/models/contexts/audio.rb +12 -0
- data/app/models/{text.rb → contexts/text.rb} +0 -0
- data/app/models/contexts/video.rb +24 -0
- data/app/models/topic.rb +19 -0
- data/app/models/transit/asset.rb +68 -0
- data/{lib → app/models}/transit/context.rb +29 -0
- data/app/views/contexts/_text.html.erb +1 -1
- data/app/views/posts/index.rss.builder +18 -0
- data/app/views/transit/assets/_file.html.erb +4 -0
- data/app/views/transit/assets/_image.html.erb +13 -0
- data/app/views/transit/assets/create.js.erb +8 -0
- data/app/views/transit/assets/destroy.js.erb +3 -0
- data/app/views/transit/assets/manage.html.erb +20 -0
- data/app/views/transit/contexts/_audio.html.erb +18 -0
- data/app/views/transit/contexts/_text.html.erb +6 -0
- data/app/views/transit/contexts/_video.html.erb +13 -0
- data/app/views/transit/contexts/destroy.js.erb +1 -0
- data/app/views/transit/contexts/index.html.erb +5 -0
- data/app/views/transit/contexts/new.js.erb +7 -0
- data/app/views/transit/contexts/show.html.erb +8 -0
- data/app/views/transit/index.html.erb +26 -0
- data/app/views/transit/index.js.erb +1 -0
- data/app/views/transit/interface/post_panel.html.erb +96 -0
- data/app/views/transit/pages/_table.html.erb +7 -0
- data/app/views/transit/pages/edit.html.erb +17 -0
- data/app/views/transit/pages/index.html.erb +17 -0
- data/app/views/transit/pages/update.js.erb +1 -0
- data/app/views/transit/posts/_form.html.erb +49 -0
- data/app/views/transit/posts/edit.html.erb +14 -0
- data/app/views/transit/posts/new.html.erb +21 -0
- data/app/views/transit/table.html.erb +13 -0
- data/app/views/transit/table.js.erb +8 -0
- data/app/views/transit/topics/manage.html.erb +28 -0
- data/config/locales/en.yml +22 -0
- data/config/routes.rb +3 -3
- data/lib/transit.rb +51 -17
- data/lib/transit/admin.rb +85 -0
- data/lib/transit/builders/form_builder.rb +319 -0
- data/lib/transit/builders/jst_builder.rb +38 -0
- data/lib/transit/builders/package_builder.rb +45 -0
- data/lib/transit/config.rb +20 -0
- data/lib/transit/controller/generator.rb +42 -0
- data/lib/transit/controller/responder.rb +34 -0
- data/lib/transit/core_ext.rb +18 -0
- data/lib/transit/errors/resource_not_found.rb +6 -0
- data/lib/transit/model/assets.rb +14 -0
- data/lib/transit/model/attachments.rb +55 -0
- data/lib/transit/model/auto_increment.rb +22 -0
- data/lib/transit/model/base.rb +56 -0
- data/lib/transit/model/comments.rb +19 -0
- data/lib/transit/model/hooks.rb +38 -0
- data/lib/transit/model/owners.rb +14 -0
- data/lib/transit/model/paginator.rb +92 -0
- data/lib/transit/model/topics.rb +14 -0
- data/lib/transit/package/page.rb +20 -12
- data/lib/transit/package/post.rb +87 -33
- data/lib/transit/package/post/validations.rb +14 -0
- data/lib/transit/rails/engine.rb +29 -13
- data/lib/transit/rails/railtie.rb +31 -0
- data/lib/transit/rails/routing.rb +11 -6
- data/lib/transit/services.rb +13 -0
- data/lib/transit/services/base.rb +14 -0
- data/lib/transit/services/facebook.rb +13 -0
- data/lib/transit/services/ted.rb +10 -0
- data/lib/transit/services/twitter.rb +13 -0
- data/lib/transit/services/vimeo.rb +10 -0
- data/lib/transit/services/you_tube.rb +12 -0
- data/lib/transit/version.rb +1 -1
- metadata +178 -31
- data/app/assets/stylesheets/includes/_compat.scss +0 -24
- data/app/assets/stylesheets/includes/_defaults.scss +0 -99
- data/app/assets/stylesheets/includes/_global.scss +0 -16
- data/app/assets/stylesheets/includes/_imports.scss +0 -27
- data/app/assets/stylesheets/includes/_mixins.scss +0 -38
- data/app/assets/stylesheets/includes/_setup.scss +0 -85
- data/app/assets/stylesheets/layout.css.scss +0 -29
- data/app/assets/stylesheets/transit.css +0 -3
- data/app/controllers/application_controller.rb +0 -5
- data/app/controllers/transit/index_controller.rb +0 -7
- data/app/controllers/transit/packages_controller.rb +0 -64
- data/app/controllers/transit/transit_controller.rb +0 -4
- data/app/helpers/routing_helpers.rb +0 -7
- data/app/models/audio.rb +0 -4
- data/app/models/package_asset.rb +0 -11
- data/app/models/video.rb +0 -8
- data/app/views/contexts/_audio.html.erb +0 -1
- data/app/views/contexts/_video.html.erb +0 -1
- data/app/views/layouts/transit.html.erb +0 -31
- data/app/views/transit/index/index.html.erb +0 -0
- data/lib/transit/helpers/controller_helpers.rb +0 -40
- data/lib/transit/helpers/model_helpers.rb +0 -26
- data/lib/transit/package.rb +0 -25
- data/lib/transit/package/base.rb +0 -49
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
// (c) 2011 Michael Aufreiter
|
|
2
|
+
// Proper is freely distributable under the MIT license.
|
|
3
|
+
// For all details and documentation:
|
|
4
|
+
// http://github.com/michael/proper
|
|
5
|
+
|
|
6
|
+
(function(){
|
|
7
|
+
|
|
8
|
+
// _.Events (borrowed from Backbone.js)
|
|
9
|
+
// -----------------
|
|
10
|
+
|
|
11
|
+
// A module that can be mixed in to *any object* in order to provide it with
|
|
12
|
+
// custom events. You may `bind` or `unbind` a callback function to an event;
|
|
13
|
+
// `trigger`-ing an event fires all callbacks in succession.
|
|
14
|
+
//
|
|
15
|
+
// var object = {};
|
|
16
|
+
// _.extend(object, Backbone.Events);
|
|
17
|
+
// object.bind('expand', function(){ alert('expanded'); });
|
|
18
|
+
// object.trigger('expand');
|
|
19
|
+
//
|
|
20
|
+
|
|
21
|
+
_.Events = window.Backbone ? Backbone.Events : {
|
|
22
|
+
|
|
23
|
+
// Bind an event, specified by a string name, `ev`, to a `callback` function.
|
|
24
|
+
// Passing `"all"` will bind the callback to all events fired.
|
|
25
|
+
bind : function(ev, callback) {
|
|
26
|
+
var calls = this._callbacks || (this._callbacks = {});
|
|
27
|
+
var list = this._callbacks[ev] || (this._callbacks[ev] = []);
|
|
28
|
+
list.push(callback);
|
|
29
|
+
return this;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
// Remove one or many callbacks. If `callback` is null, removes all
|
|
33
|
+
// callbacks for the event. If `ev` is null, removes all bound callbacks
|
|
34
|
+
// for all events.
|
|
35
|
+
unbind : function(ev, callback) {
|
|
36
|
+
var calls;
|
|
37
|
+
if (!ev) {
|
|
38
|
+
this._callbacks = {};
|
|
39
|
+
} else if (calls = this._callbacks) {
|
|
40
|
+
if (!callback) {
|
|
41
|
+
calls[ev] = [];
|
|
42
|
+
} else {
|
|
43
|
+
var list = calls[ev];
|
|
44
|
+
if (!list) return this;
|
|
45
|
+
for (var i = 0, l = list.length; i < l; i++) {
|
|
46
|
+
if (callback === list[i]) {
|
|
47
|
+
list.splice(i, 1);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return this;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
// Trigger an event, firing all bound callbacks. Callbacks are passed the
|
|
57
|
+
// same arguments as `trigger` is, apart from the event name.
|
|
58
|
+
// Listening for `"all"` passes the true event name as the first argument.
|
|
59
|
+
trigger : function(ev) {
|
|
60
|
+
var list, calls, i, l;
|
|
61
|
+
if (!(calls = this._callbacks)) return this;
|
|
62
|
+
if (list = calls[ev]) {
|
|
63
|
+
for (i = 0, l = list.length; i < l; i++) {
|
|
64
|
+
list[i].apply(this, Array.prototype.slice.call(arguments, 1));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (list = calls['all']) {
|
|
68
|
+
for (i = 0, l = list.length; i < l; i++) {
|
|
69
|
+
list[i].apply(this, arguments);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
_.stripTags = function(input, allowed) {
|
|
77
|
+
// Strips HTML and PHP tags from a string
|
|
78
|
+
//
|
|
79
|
+
// version: 1009.2513
|
|
80
|
+
// discuss at: http://phpjs.org/functions/strip_tags
|
|
81
|
+
allowed = (((allowed || "") + "")
|
|
82
|
+
.toLowerCase()
|
|
83
|
+
.match(/<[a-z][a-z0-9]*>/g) || [])
|
|
84
|
+
.join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
|
|
85
|
+
var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
|
|
86
|
+
commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
|
|
87
|
+
return input.replace(commentsAndPhpTags, '').replace(tags, function($0, $1){
|
|
88
|
+
return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Initial Setup
|
|
93
|
+
// -------------
|
|
94
|
+
|
|
95
|
+
controlsTpl = ' \
|
|
96
|
+
<div class="proper-commands"> \
|
|
97
|
+
<a href="#" title="Emphasis (CTRL+SHIFT+E)" class="command em" command="em"><div>Emphasis</div></a> \
|
|
98
|
+
<a href="#" title="Strong (CTRL+SHIFT+S)" class="command strong" command="strong"><div>Strong</div></a> \
|
|
99
|
+
<!--<a href="#" title="Inline Code (CTRL+SHIFT+C)" class="command code" command="code"><div>Code</div></a>--> \
|
|
100
|
+
<a title="Link (CTRL+SHIFT+L)" href="#" class="command link" command="link"><div>Link</div></a>\
|
|
101
|
+
<a href="#" title="Bullet List (CTRL+SHIFT+B)" class="command ul" command="ul"><div>Bullets List</div></a>\
|
|
102
|
+
<a href="#" title="Numbered List (CTRL+SHIFT+N)" class="command ol" command="ol"><div>Numbered List</div></a>\
|
|
103
|
+
<a href="#" title="Indent (TAB)" class="command indent" command="indent"><div>Indent</div></a>\
|
|
104
|
+
<a href="#" title="Outdent (SHIFT+TAB)" class="command outdent" command="outdent"><div>Outdent</div></a>\
|
|
105
|
+
<br class="clear"/>\
|
|
106
|
+
</div>';
|
|
107
|
+
|
|
108
|
+
var COMMANDS = {
|
|
109
|
+
"em": "italic",
|
|
110
|
+
"strong": "bold",
|
|
111
|
+
"ul": "insertUnorderedList",
|
|
112
|
+
"ol": "insertOrderedList"
|
|
113
|
+
// "link": "createLink" // for some reason Firefox can't work with that
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Proper
|
|
117
|
+
// -----------
|
|
118
|
+
|
|
119
|
+
this.Proper = function(options) {
|
|
120
|
+
var activeElement = null, // element that's being edited
|
|
121
|
+
$controls,
|
|
122
|
+
self = {},
|
|
123
|
+
that = this,
|
|
124
|
+
pendingChange = false,
|
|
125
|
+
options = {},
|
|
126
|
+
defaultOptions = { // default options
|
|
127
|
+
multiline: true,
|
|
128
|
+
markup: true,
|
|
129
|
+
placeholder: 'Enter Text'
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Setup temporary hidden DOM Node, for sanitization
|
|
133
|
+
$('body').append($('<div id="proper_content"></div>').hide());
|
|
134
|
+
var rawContent = $('<div id="proper_raw_content" contenteditable="true"></div>');
|
|
135
|
+
rawContent.css('position', 'fixed');
|
|
136
|
+
rawContent.css('top', '20px');
|
|
137
|
+
rawContent.css('left', '20px');
|
|
138
|
+
rawContent.css('opacity', '0');
|
|
139
|
+
|
|
140
|
+
$('body').append(rawContent);
|
|
141
|
+
|
|
142
|
+
// Commands
|
|
143
|
+
// -----------
|
|
144
|
+
|
|
145
|
+
function tagActive(element) {
|
|
146
|
+
var sel = window.getSelection();
|
|
147
|
+
var range = sel.getRangeAt(0);
|
|
148
|
+
return range.startContainer.parentNode.localName === element || range.endContainer.parentNode.localName === element;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// A proper implementation of execCommand
|
|
152
|
+
function toggleTag(tag) {
|
|
153
|
+
var sel = window.getSelection();
|
|
154
|
+
var range = sel.getRangeAt(0);
|
|
155
|
+
|
|
156
|
+
if (sel+"".length == 0) return;
|
|
157
|
+
|
|
158
|
+
if (tagActive(tag)) {
|
|
159
|
+
document.execCommand('removeFormat', false, true);
|
|
160
|
+
} else {
|
|
161
|
+
var sel = window.getSelection();
|
|
162
|
+
var range = sel.getRangeAt(0);
|
|
163
|
+
document.execCommand('removeFormat', false, true);
|
|
164
|
+
document.execCommand('insertHTML', false, '<'+tag+'>'+window.getSelection()+'</'+tag+'>');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
var commands = {
|
|
169
|
+
execEM: function() {
|
|
170
|
+
if (!document.queryCommandState('italic', false, true)) document.execCommand('removeFormat', false, true);
|
|
171
|
+
document.execCommand('italic', false, true);
|
|
172
|
+
return false;
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
execSTRONG: function() {
|
|
176
|
+
if (!document.queryCommandState('bold', false, true)) document.execCommand('removeFormat', false, true);
|
|
177
|
+
document.execCommand('bold', false, true);
|
|
178
|
+
return false;
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
execCODE: function() {
|
|
182
|
+
if (!tagActive('code')) document.execCommand('removeFormat', false, true);
|
|
183
|
+
toggleTag('code');
|
|
184
|
+
return false;
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
execUL: function() {
|
|
188
|
+
document.execCommand('insertUnorderedList', false, true);
|
|
189
|
+
return false;
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
execOL: function() {
|
|
193
|
+
document.execCommand('insertOrderedList', false, true);
|
|
194
|
+
return false;
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
execINDENT: function() {
|
|
198
|
+
if (document.queryCommandState('insertOrderedList', false, true) || document.queryCommandState('insertUnorderedList', false, true)) {
|
|
199
|
+
document.execCommand('indent', false, true);
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
execOUTDENT: function() {
|
|
205
|
+
if (document.queryCommandState('insertOrderedList', false, true) || document.queryCommandState('insertUnorderedList', false, true)) {
|
|
206
|
+
document.execCommand('outdent', false, true);
|
|
207
|
+
}
|
|
208
|
+
return false;
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
execLINK: function() {
|
|
212
|
+
document.execCommand('createLink', false, prompt('URL:'));
|
|
213
|
+
return false;
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
showHTML: function() {
|
|
217
|
+
alert($(this.el).html());
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// TODO: enable proper sanitizing that allows markup to be pasted too
|
|
222
|
+
function sanitize() {
|
|
223
|
+
var rawContent = document.getElementById('proper_raw_content');
|
|
224
|
+
$('#proper_content').html($(rawContent).text());
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function updateCommandState() {
|
|
228
|
+
if (!options.markup) return;
|
|
229
|
+
$(activeElement).focus();
|
|
230
|
+
|
|
231
|
+
$controls.find('.command').removeClass('selected');
|
|
232
|
+
_.each(COMMANDS, function(command, key) {
|
|
233
|
+
if (document.queryCommandState(command, false, true)) {
|
|
234
|
+
$controls.find('.command.'+key).addClass('selected');
|
|
235
|
+
}
|
|
236
|
+
if (tagActive('code')) {
|
|
237
|
+
$controls.find('.command.code').addClass('selected');
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Used for placeholders
|
|
243
|
+
function checkEmpty() {
|
|
244
|
+
if ($(activeElement).text().trim().length === 0) {
|
|
245
|
+
$(activeElement).addClass('empty');
|
|
246
|
+
if (options.markup) {
|
|
247
|
+
$(activeElement).html('<p>« '+options.placeholder+' »</p>');
|
|
248
|
+
} else {
|
|
249
|
+
$(activeElement).html('« '+options.placeholder+' »');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Clean up the mess produced by contenteditable
|
|
256
|
+
function semantify(html) {
|
|
257
|
+
return html.replace(/<i>/g, '<em>')
|
|
258
|
+
.replace(/<\/i>/g, '</em>')
|
|
259
|
+
.replace(/<b>/g, '<strong>')
|
|
260
|
+
.replace(/<\/b>/g, '</strong>');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function saveSelection() {
|
|
264
|
+
if (window.getSelection) {
|
|
265
|
+
sel = window.getSelection();
|
|
266
|
+
if (sel.getRangeAt && sel.rangeCount) {
|
|
267
|
+
return sel.getRangeAt(0);
|
|
268
|
+
}
|
|
269
|
+
} else if (document.selection && document.selection.createRange) {
|
|
270
|
+
return document.selection.createRange();
|
|
271
|
+
}
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function restoreSelection(range) {
|
|
276
|
+
if (range) {
|
|
277
|
+
if (window.getSelection) {
|
|
278
|
+
sel = window.getSelection();
|
|
279
|
+
sel.removeAllRanges();
|
|
280
|
+
sel.addRange(range);
|
|
281
|
+
} else if (document.selection && range.select) {
|
|
282
|
+
range.select();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function selectAll() {
|
|
288
|
+
range = document.createRange();
|
|
289
|
+
range.selectNodeContents($(activeElement)[0]);
|
|
290
|
+
selection = window.getSelection();
|
|
291
|
+
selection.removeAllRanges();
|
|
292
|
+
selection.addRange(range);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function bindEvents(el) {
|
|
296
|
+
$(el).unbind('paste');
|
|
297
|
+
$(el).unbind('keydown');
|
|
298
|
+
$(el).unbind('keyup');
|
|
299
|
+
|
|
300
|
+
$(el).bind('paste', function() {
|
|
301
|
+
var selection = saveSelection();
|
|
302
|
+
$('#proper_raw_content').focus();
|
|
303
|
+
|
|
304
|
+
// Immediately sanitize pasted content
|
|
305
|
+
setTimeout(function() {
|
|
306
|
+
sanitize();
|
|
307
|
+
restoreSelection(selection);
|
|
308
|
+
$(el).focus();
|
|
309
|
+
|
|
310
|
+
// Avoid nested paragraph correction resulting from paste
|
|
311
|
+
var content = $('#proper_content').html().trim();
|
|
312
|
+
|
|
313
|
+
// For some reason last </p> gets injected anyway
|
|
314
|
+
document.execCommand('insertHTML', false, content);
|
|
315
|
+
$('#proper_raw_content').html('');
|
|
316
|
+
}, 1);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// Prevent multiline
|
|
320
|
+
$(el).bind('keydown', function(e) {
|
|
321
|
+
if (!options.multiline && e.keyCode === 13) {
|
|
322
|
+
e.stopPropagation();
|
|
323
|
+
return false;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (e.keyCode == 8 && $(activeElement).text().trim().length == 0) {
|
|
327
|
+
e.stopPropagation();
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
$(el).bind('blur', checkEmpty);
|
|
333
|
+
$(el).bind('click', updateCommandState);
|
|
334
|
+
|
|
335
|
+
$(el).bind('keyup', function(e) {
|
|
336
|
+
updateCommandState();
|
|
337
|
+
if ($(activeElement).text().trim().length > 0) {
|
|
338
|
+
$(activeElement).removeClass('empty');
|
|
339
|
+
} else {
|
|
340
|
+
// TODO: problematic when hitting enter on an empty div
|
|
341
|
+
selectAll();
|
|
342
|
+
document.execCommand('delete', false, "");
|
|
343
|
+
$(activeElement).addClass('empty');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Trigger change events, but consolidate them to 200ms time slices
|
|
347
|
+
setTimeout(function() {
|
|
348
|
+
// Skip if there's already a change pending
|
|
349
|
+
if (!pendingChange) {
|
|
350
|
+
pendingChange = true;
|
|
351
|
+
setTimeout(function() {
|
|
352
|
+
pendingChange = false;
|
|
353
|
+
self.trigger('changed');
|
|
354
|
+
}, 200);
|
|
355
|
+
}
|
|
356
|
+
}, 10);
|
|
357
|
+
return true;
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Instance methods
|
|
362
|
+
// -----------
|
|
363
|
+
|
|
364
|
+
self.deactivate = function() {
|
|
365
|
+
$(activeElement).attr('contenteditable', 'false');
|
|
366
|
+
$(activeElement).unbind('paste');
|
|
367
|
+
$(activeElement).unbind('keydown');
|
|
368
|
+
$('.proper-commands').remove();
|
|
369
|
+
self.unbind('changed');
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
// Activate editor for a given element
|
|
373
|
+
self.activate = function(el, opts) {
|
|
374
|
+
options = {};
|
|
375
|
+
_.extend(options, defaultOptions, opts);
|
|
376
|
+
|
|
377
|
+
// Deactivate previously active element
|
|
378
|
+
self.deactivate();
|
|
379
|
+
|
|
380
|
+
// Make editable
|
|
381
|
+
$(el).attr('contenteditable', true);
|
|
382
|
+
activeElement = el;
|
|
383
|
+
bindEvents(el);
|
|
384
|
+
|
|
385
|
+
// Setup controls
|
|
386
|
+
if (options.markup) {
|
|
387
|
+
$controls = $(controlsTpl);
|
|
388
|
+
$controls.appendTo($(options.controlsTarget));
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Keyboard bindings
|
|
392
|
+
if (options.markup) {
|
|
393
|
+
$(activeElement).bind('keydown', 'ctrl+shift+e', commands.execEM);
|
|
394
|
+
$(activeElement).bind('keydown', 'ctrl+shift+s', commands.execSTRONG);
|
|
395
|
+
$(activeElement).bind('keydown', 'ctrl+shift+c', commands.execCODE);
|
|
396
|
+
$(activeElement).bind('keydown', 'ctrl+shift+l', commands.execLINK);
|
|
397
|
+
$(activeElement).bind('keydown', 'ctrl+shift+b', commands.execUL);
|
|
398
|
+
$(activeElement).bind('keydown', 'ctrl+shift+n', commands.execOL);
|
|
399
|
+
$(activeElement).bind('keydown', 'tab', commands.execINDENT);
|
|
400
|
+
$(activeElement).bind('keydown', 'shift+tab', commands.execOUTDENT);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
updateCommandState();
|
|
404
|
+
if (el.hasClass('empty')) {
|
|
405
|
+
selectAll();
|
|
406
|
+
document.execCommand('delete', false, "");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
$('.proper-commands a.command').click(function(e) {
|
|
410
|
+
commands['exec'+ $(e.currentTarget).attr('command').toUpperCase()]();
|
|
411
|
+
updateCommandState();
|
|
412
|
+
setTimeout(function() {
|
|
413
|
+
self.trigger('changed');
|
|
414
|
+
}, 10);
|
|
415
|
+
return false;
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
// Get current content
|
|
420
|
+
self.content = function() {
|
|
421
|
+
if ($(activeElement).hasClass('empty')) return '';
|
|
422
|
+
|
|
423
|
+
if (options.markup) {
|
|
424
|
+
return activeElement ? semantify($(activeElement).html()).trim() : '';
|
|
425
|
+
} else {
|
|
426
|
+
if (options.multiline) {
|
|
427
|
+
return _.stripTags($(activeElement).html().replace(/<div>/g, '\n')
|
|
428
|
+
.replace(/<\/div>/g, '')).trim();
|
|
429
|
+
} else {
|
|
430
|
+
return _.stripTags($(activeElement).html()).trim();
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
// Expose public API
|
|
436
|
+
// -----------
|
|
437
|
+
|
|
438
|
+
_.extend(self, _.Events);
|
|
439
|
+
return self;
|
|
440
|
+
};
|
|
441
|
+
})();
|
|
442
|
+
|
|
443
|
+
/*
|
|
444
|
+
* jQuery Hotkeys Plugin
|
|
445
|
+
* Copyright 2010, John Resig
|
|
446
|
+
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
447
|
+
*
|
|
448
|
+
* Based upon the plugin by Tzury Bar Yochay:
|
|
449
|
+
* http://github.com/tzuryby/hotkeys
|
|
450
|
+
*
|
|
451
|
+
* Original idea by:
|
|
452
|
+
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
|
|
453
|
+
*/
|
|
454
|
+
|
|
455
|
+
(function(jQuery){
|
|
456
|
+
|
|
457
|
+
jQuery.hotkeys = {
|
|
458
|
+
version: "0.8",
|
|
459
|
+
|
|
460
|
+
specialKeys: {
|
|
461
|
+
8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
|
|
462
|
+
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
|
|
463
|
+
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
|
|
464
|
+
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
|
|
465
|
+
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
|
|
466
|
+
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
|
|
467
|
+
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
|
|
468
|
+
},
|
|
469
|
+
|
|
470
|
+
shiftNums: {
|
|
471
|
+
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
|
|
472
|
+
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
|
|
473
|
+
".": ">", "/": "?", "\\": "|"
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
function keyHandler( handleObj ) {
|
|
478
|
+
// Only care when a possible input has been specified
|
|
479
|
+
if ( typeof handleObj.data !== "string" ) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
var origHandler = handleObj.handler,
|
|
484
|
+
keys = handleObj.data.toLowerCase().split(" ");
|
|
485
|
+
|
|
486
|
+
handleObj.handler = function( event ) {
|
|
487
|
+
// Don't fire in text-accepting inputs that we didn't directly bind to
|
|
488
|
+
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
|
|
489
|
+
event.target.type === "text") ) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Keypress represents characters, not special keys
|
|
494
|
+
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
|
|
495
|
+
character = String.fromCharCode( event.which ).toLowerCase(),
|
|
496
|
+
key, modif = "", possible = {};
|
|
497
|
+
|
|
498
|
+
// check combinations (alt|ctrl|shift+anything)
|
|
499
|
+
if ( event.altKey && special !== "alt" ) {
|
|
500
|
+
modif += "alt+";
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if ( event.ctrlKey && special !== "ctrl" ) {
|
|
504
|
+
modif += "ctrl+";
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// TODO: Need to make sure this works consistently across platforms
|
|
508
|
+
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
|
|
509
|
+
modif += "meta+";
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if ( event.shiftKey && special !== "shift" ) {
|
|
513
|
+
modif += "shift+";
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if ( special ) {
|
|
517
|
+
possible[ modif + special ] = true;
|
|
518
|
+
|
|
519
|
+
} else {
|
|
520
|
+
possible[ modif + character ] = true;
|
|
521
|
+
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
|
|
522
|
+
|
|
523
|
+
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
|
|
524
|
+
if ( modif === "shift+" ) {
|
|
525
|
+
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
for ( var i = 0, l = keys.length; i < l; i++ ) {
|
|
530
|
+
if ( possible[ keys[i] ] ) {
|
|
531
|
+
return origHandler.apply( this, arguments );
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
jQuery.each([ "keydown", "keyup", "keypress" ], function() {
|
|
538
|
+
jQuery.event.special[ this ] = { add: keyHandler };
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
})( jQuery );
|