source: trunk/plugins/SmartReplace/smart-replace.js @ 990

Last change on this file since 990 was 990, checked in by ray, 11 years ago
  • Property svn:keywords set to LastChangedDate LastChangedRevision LastChangedBy HeadURL Id
File size: 9.3 KB
Line 
1/*------------------------------------------*\
2 SmartReplace for Xinha
3 _______________________
4         
5\*------------------------------------------*/
6
7function SmartReplace(editor) {
8        this.editor = editor;
9       
10        var cfg = editor.config;
11        var self = this;
12       
13        cfg.registerButton
14        ({
15                id       : "smartreplace",
16                tooltip  : this._lc("SmartReplace"),
17                image    : _editor_url+"plugins/SmartReplace/img/smartquotes.gif",
18                textMode : false,
19                action   : function(e, objname, obj) { self.buttonPress(null, obj); }
20        });
21        cfg.addToolbarElement("smartreplace", "htmlmode", 1);
22}
23
24SmartReplace._pluginInfo = {
25  name          : "SmartReplace",
26  version       : "1.0",
27  developer     : "Raimund Meyer",
28  developer_url : "http://x-webservice.net",
29  c_owner       : "Raimund Meyer",
30  sponsor       : "",
31  sponsor_url   : "",
32  license       : "LGPL"
33};
34
35SmartReplace.prototype._lc = function(string) {
36        return Xinha._lc(string, 'SmartReplace');
37};
38
39Xinha.Config.prototype.SmartReplace =
40{
41        'defaultActive' : true,
42        'quotes' : null//[String.fromCharCode(187),String.fromCharCode(171),String.fromCharCode(8250),String.fromCharCode(8249)]
43}
44SmartReplace.prototype.toggleActivity = function(newState)
45{
46        if (typeof newState != 'undefined')
47        {
48                this.active = newState;
49        }
50        else
51        {
52                this.active = this.active ? false : true;               
53        }
54        this.editor._toolbarObjects.smartreplace.state("active", this.active);
55}
56
57SmartReplace.prototype.onUpdateToolbar = function() {
58        this.editor._toolbarObjects.smartreplace.state("active", this.active);
59}
60
61SmartReplace.prototype.onGenerate = function() {
62        this.active = this.editor.config.SmartReplace.defaultActive;
63        this.editor._toolbarObjects.smartreplace.state("active", this.active);
64       
65        var self = this;
66        Xinha._addEvent(
67                self.editor._doc,
68                 "keypress",
69                function (event)
70                {
71                  return self.keyEvent(Xinha.is_ie ? self.editor._iframe.contentWindow.event : event);
72                });
73       
74        var quotes = this.editor.config.SmartReplace.quotes;
75   
76        if (quotes && typeof quotes == 'object')
77        {
78                this.openingQuotes = quotes[0];
79                this.closingQuotes = quotes[1];
80                this.openingQuote  = quotes[2];
81                this.closingQuote  = quotes[3];
82        }
83        else
84        {
85                this.openingQuotes = this._lc("OpeningDoubleQuotes");
86                this.closingQuote  = this._lc("ClosingSingleQuote");
87                this.closingQuotes = this._lc("ClosingDoubleQuotes");
88                this.openingQuote  = this._lc("OpeningSingleQuote");
89        }
90       
91        if (this.openingQuotes == 'OpeningDoubleQuotes') //If nothing else is defined, English style as default
92        {
93                this.openingQuotes = String.fromCharCode(8220);
94                this.closingQuotes = String.fromCharCode(8221);
95                this.openingQuote = String.fromCharCode(8216);
96                this.closingQuote = String.fromCharCode(8217);
97        }
98};
99
100SmartReplace.prototype.keyEvent = function(ev)
101{
102        if ( !this.active) return true;
103        var editor = this.editor;
104        var charCode =  Xinha.is_ie ? ev.keyCode : ev.which;
105
106        var key = String.fromCharCode(charCode);
107
108        if ( key == '"' || key == "'")
109        {
110                Xinha._stopEvent(ev);
111                return this.smartQuotes(key);
112        }
113        if (charCode == 32) //space bar
114        {
115                return this.smartReplace(ev, 2, /^\s-/, ' –', false); // space-space -> dash
116        }
117        if ( key == '.' ) // ... -> ellipsis
118        {
119                return this.smartReplace(ev, 2, /\.\./, '
', true);
120        }
121        return true;
122}
123
124SmartReplace.prototype.smartQuotes = function(kind)
125{
126        if (kind == "'")
127        {
128                var opening = this.openingQuote;
129                var closing = this.closingQuote;
130        }
131        else
132        {
133                var opening = this.openingQuotes;
134                var closing = this.closingQuotes;
135        }
136       
137        var editor = this.editor;
138               
139        var sel = editor.getSelection();
140
141        if (Xinha.is_ie)
142        {
143                var r = editor.createRange(sel);
144                if (r.text !== '')
145                {
146                        r.text = '';
147                }
148                r.moveStart('character', -1);
149               
150                if(r.text.match(/\S/))
151                {
152                        r.moveStart('character', +1);
153                        r.text = closing;
154                       
155                }
156                else
157                {
158                        r.moveStart('character', +1);
159                        r.text = opening;
160                }
161        }
162        else
163        {
164                var r = editor.createRange(sel);
165
166                if (!r.collapsed)
167                {
168                        editor.insertNodeAtSelection(document.createTextNode(''));
169                }
170                if (r.startOffset > 0) r.setStart(r.startContainer, r.startOffset -1);
171
172               
173                if(r.toString().match(/[^\s\xA0]/))
174                {
175                        r.collapse(false);
176                        editor.insertNodeAtSelection(document.createTextNode(closing));
177                }
178                else
179                {
180                        editor.insertNodeAtSelection(document.createTextNode(opening));                         
181                }
182                editor.getSelection().collapseToEnd();
183        }
184        return false;
185}
186
187SmartReplace.prototype.smartReplace = function(ev, lookback, re, replace, stopEvent)
188{
189        var editor = this.editor;
190        var sel = this.editor.getSelection();
191        var r = this.editor.createRange(sel);
192       
193        if (Xinha.is_ie)
194        {
195                r.moveStart('character', -lookback);
196               
197                if(r.text.match(re))
198                {
199                        r.text = replace;
200                        if (stopEvent)
201                        {
202                                Xinha._stopEvent(ev);
203                                return false
204                        }
205                }
206        }
207        else
208        {
209                if (r.startOffset > 1) r.setStart(r.startContainer, r.startOffset -lookback);
210
211                if(r.toString().match(re))
212                {
213                        this.editor.insertNodeAtSelection(document.createTextNode(replace));
214                        r.deleteContents();
215                        r.collapse(true);
216                  if (stopEvent)
217                  {
218                                Xinha._stopEvent(ev);
219                                return false
220                  }
221                }
222                editor.getSelection().collapseToEnd();
223        }
224        return true;
225}
226
227
228SmartReplace.prototype.replaceAll = function()
229{
230        var doubleQuotes = [
231                                                        '"',
232                                                        String.fromCharCode(8220),
233                                                        String.fromCharCode(8221),
234                                                        String.fromCharCode(8222),
235                                                        String.fromCharCode(187),
236                                                        String.fromCharCode(171)
237                                                       
238                                                ];
239        var singleQuotes = [
240                                                        "'",
241                                                        String.fromCharCode(8216),
242                                                        String.fromCharCode(8217),
243                                                        String.fromCharCode(8218),
244                                                        String.fromCharCode(8250),
245                                                        String.fromCharCode(8249)
246                                                ];
247       
248        var html = this.editor.getHTML();
249        var reOpeningDouble = new RegExp ('(\\s|^|>)('+doubleQuotes.join('|')+')(\\S)','g');
250        html = html.replace(reOpeningDouble,'$1'+this.openingQuotes+'$3');
251       
252        var reOpeningSingle = new RegExp ('(\\s|^|>)('+singleQuotes.join('|')+')(\\S)','g');
253        html = html.replace(reOpeningSingle,'$1'+this.openingQuote+'$3');
254       
255        var reClosingDouble = new RegExp ('(\\S)('+doubleQuotes.join('|')+')','g');
256        html = html.replace(reClosingDouble,'$1'+this.closingQuotes);
257       
258        var reClosingSingle = new RegExp ('(\\S)('+singleQuotes.join('|')+')','g');
259        html = html.replace(reClosingSingle,'$1'+this.closingQuote);
260       
261        var reDash    = new RegExp ('( | )(-)( | )','g');
262        html = html.replace(reDash,' '+String.fromCharCode(8211)+' ');
263       
264        this.editor.setHTML(html);
265}
266SmartReplace.prototype.dialog = function()
267{
268        var self = this;
269        var action = function (param)
270        {
271                self.toggleActivity(param.enable);
272                if (param.convert)
273                {
274                        self.replaceAll();
275                }
276        }
277        var init = this;
278        Dialog(_editor_url+'plugins/SmartReplace/popups/dialog.html', action, init);
279}
280
281
282SmartReplace.prototype.buttonPress = function(opts, obj)
283{
284        var self = this;
285
286        if ( this._dialog.dialog.rootElem.style.display != 'none')
287        {
288                return this._dialog.hide();
289        }
290        var doOK = function()
291        {
292                var opts = self._dialog.hide();
293                self.toggleActivity((opts.enable) ? true : false);
294                if (opts.convert)
295                {
296                        self.replaceAll();
297                        self._dialog.dialog.getElementById("convert").checked = false;
298                }
299        }
300        var inputs =
301        {
302                enable : self.active ? "on" : '',
303                convert: ''
304        };
305        this._dialog.show(inputs, doOK);
306};
307
308SmartReplace.prototype.onGenerateOnce = function()
309{
310  if( !this._dialog)
311  {
312        this._dialog = new SmartReplace.Dialog(this);
313  }
314};
315
316SmartReplace.Dialog = function (mainPluginObject)
317{
318  this.Dialog_nxtid = 0;
319  this.mainPluginObject = mainPluginObject;
320  this.id = { }; // This will be filled below with a replace, nifty
321
322  this.ready = false;
323  this.files  = false;
324  this.html   = false;
325  this.dialog = false;
326
327  this._prepareDialog();
328
329};
330
331SmartReplace.Dialog.prototype._prepareDialog = function()
332{
333  var pluginDialogObject = this;
334  var editor = this.mainPluginObject.editor;
335
336  if(this.html == false)
337  {
338        Xinha._getback(_editor_url + 'plugins/SmartReplace/dialog.html', function(getback) { pluginDialogObject.html = getback; pluginDialogObject._prepareDialog(); });
339        return;
340  }
341 
342  // Now we have everything we need, so we can build the dialog.
343  this.dialog = new Xinha.Dialog(editor, this.html, 'SmartReplace');
344
345  this.ready = true;
346};
347
348SmartReplace.Dialog.prototype._lc = SmartReplace.prototype._lc;
349
350SmartReplace.Dialog.prototype.show = function(inputs, ok, cancel)
351{
352  if(!this.ready)
353  {
354        var pluginDialogObject = this;
355        window.setTimeout(function() {pluginDialogObject.show(inputs,ok,cancel);},100);
356        return;
357  }
358
359  // Connect the OK and Cancel buttons
360  var dialog = this.dialog;
361  var pluginDialogObject = this;
362  if(ok)
363  {
364        this.dialog.getElementById('ok').onclick = ok;
365  }
366  else
367  {
368        this.dialog.getElementById('ok').onclick = function() {pluginDialogObject.hide();};
369  }
370
371  if(cancel)
372  {
373        this.dialog.getElementById('cancel').onclick = cancel;
374  }
375  else
376  {
377        this.dialog.getElementById('cancel').onclick = function() { pluginDialogObject.hide()};
378  }
379
380  // Show the dialog
381  this.mainPluginObject.editor.disableToolbar(['fullscreen','smartreplace']);
382
383  this.dialog.show(inputs);
384
385  // Init the sizes
386  this.dialog.onresize();
387};
388
389SmartReplace.Dialog.prototype.hide = function()
390{
391  this.mainPluginObject.editor.enableToolbar();
392  return this.dialog.hide();
393};
Note: See TracBrowser for help on using the repository browser.