Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
if (typeof RedactorPlugins === 'undefined') var RedactorPlugins = {};
/* Generic draft support for osTicket. The plugins supports draft retrieval
* automatically, along with draft autosave, and image uploading.
*
* Configuration:
* draft_namespace: namespace for the draft retrieval
* draft_object_id: extension to the namespace for draft retrieval
*
* Caveats:
* Login (staff only currently) is required server-side for drafts and image
* uploads. Furthermore, the id of the staff is considered for the drafts,
* so one user will not retrieve drafts for another user.
*/
RedactorPlugins.draft = {
init: function() {
if (!this.opts.draft_namespace)
return;
this.opts.changeCallback = this.hideDraftSaved;
var autosave_url = 'ajax.php/draft/' + this.opts.draft_namespace;
if (this.opts.draft_object_id)
autosave_url += '.' + this.opts.draft_object_id;
this.opts.autosave = autosave_url;
this.opts.autosaveInterval = 4;
this.opts.autosaveCallback = this.setupDraftUpdate;
this.opts.initCallback = this.recoverDraft;
},
recoverDraft: function() {
var self = this;
$.ajax(this.opts.autosave, {
dataType: 'json',
statusCode: {
200: function(json) {
self.draft_id = json.draft_id;
// Relace the current content with the draft, sync, and make
// images editable
self.setupDraftUpdate(json);
if (!json.body) return;
self.set(json.body, false);
self.observeStart();
},
205: function() {
// Save empty draft immediately;
var ai = self.opts.autosaveInterval;
// Save immediately -- capture the created autosave
// interval and clear it as soon as possible. Note that
// autosave()ing doesn't happen immediately. It happens
// async after the autosaveInterval expires.
self.opts.autosaveInterval = 0;
self.autosave();
var interval = self.autosaveInterval;
setTimeout(function() {
clearInterval(interval);
}, 1);
// Reinstate previous autosave interval timing
self.opts.autosaveInterval = ai;
}
}
});
},
setupDraftUpdate: function(data) {
this.$box.parent().find('.draft-saved').show();
if (typeof data != 'object')
data = $.parseJSON(data);
if (!data || !data.draft_id)
return;
$('input[name=draft_id]', this.$box.closest('form'))
.val(data.draft_id);
this.draft_id = data.draft_id;
var self = this;
getConfig().then(function(c) {
if (c.allow_attachments) {
self.opts.clipboardUploadUrl =
self.opts.imageUpload =
'ajax.php/draft/'+data.draft_id+'/attach';
self.opts.imageUploadErrorCallback = self.displayError;
}
});
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
this.opts.autosave = 'ajax.php/draft/'+data.draft_id;
},
displayError: function(json) {
alert(json.error);
},
hideDraftSaved: function() {
this.$box.parent().find('.draft-saved').hide();
},
deleteDraft: function() {
var self = this;
$.ajax('ajax.php/draft/'+this.draft_id, {
type: 'delete',
success: function() {
self.opts.autosave = '';
self.opts.imageUpload = '';
self.draft_id = undefined;
clearInterval(self.autosaveInterval);
self.hideDraftSaved();
self.set('');
}
});
},
};
/* Redactor richtext init */
$(function() {
var captureImageSizes = function(html) {
$('img', this.$box).each(function(i, img) {
// TODO: Rewrite the entire <img> tag. Otherwise the @width
// and @height attributes will begin to accumulate
before = img.outerHTML;
$(img).attr('width', img.clientWidth)
.attr('height',img.clientHeight);
html = html.replace(before, img.outerHTML);
});
return html;
},
redact = function(el) {
var el = $(el),
options = {
'air': el.hasClass('no-bar'),
'airButtons': ['formatting', '|', 'bold', 'italic', 'deleted', '|', 'unorderedlist', 'orderedlist', 'outdent', 'indent', '|', 'image'],
'autoresize': !el.hasClass('no-bar'),
'minHeight': el.hasClass('small') ? 75 : 150,
'focus': false,
'plugins': ['fontcolor','fontfamily'],
'imageGetJson': 'ajax.php/draft/images/browse',
'syncBeforeCallback': captureImageSizes,
'linebreaks': true,
'tabFocus': false
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
if (el.hasClass('draft')) {
var reset = $('input[type=reset]', el.closest('form')),
draft_saved = $('<span>')
.addClass("pull-right draft-saved faded")
.css({'position':'relative','top':'-1.8em','right':'1em'})
.hide()
.append($('<span>')
.css({'position':'relative', 'top':'0.17em'})
.text('Draft Saved'));
el.closest('form').append($('<input type="hidden" name="draft_id"/>'));
if (reset) {
reset.click(function() {
if (el.hasClass('draft'))
el.redactor('deleteDraft');
else
el.redactor('set', '');
});
}
if (el.hasClass('draft-delete')) {
draft_saved.append($('<span>')
.addClass('action-button')
.click(function() {
el.redactor('deleteDraft');
return false;
})
.append($('<i>')
.addClass('icon-trash')
)
);
}
draft_saved.insertBefore(el);
options['plugins'].push('draft');
if (el.data('draftNamespace'))
options['draft_namespace'] = el.data('draftNamespace');
if (el.data('draftObjectId'))
options['draft_object_id'] = el.data('draftObjectId');
}
el.redactor(options);
},
findRichtextBoxes = function() {
$('.richtext').each(function(i,el) {
if ($(el).hasClass('ifhtml'))
// Check if html_thread is enabled first
getConfig().then(function(c) {
if (c.html_thread)
redact(el);
});
else
// Make a rich text editor immediately
redact(el);
});
};
findRichtextBoxes();
$('#user-info').ajaxComplete(findRichtextBoxes);