Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dijit.Editor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dijit.Editor"] = true;
3
dojo.provide("dijit.Editor");
4
dojo.require("dijit._editor.RichText");
5
dojo.require("dijit.Toolbar");
6
dojo.require("dijit._editor._Plugin");
7
dojo.require("dijit._Container");
8
dojo.require("dojo.i18n");
9
dojo.requireLocalization("dijit._editor", "commands", null, "ko,zh,ja,zh-tw,ru,it,hu,fr,pt,pl,es,ROOT,de,cs");
10
 
11
dojo.declare(
12
	"dijit.Editor",
13
	dijit._editor.RichText,
14
	{
15
	// summary: A rich-text Editing widget
16
 
17
		// plugins: Array
18
		//		a list of plugin names (as strings) or instances (as objects)
19
		//		for this widget.
20
		plugins: null,
21
 
22
		// extraPlugins: Array
23
		//		a list of extra plugin names which will be appended to plugins array
24
		extraPlugins: null,
25
 
26
		constructor: function(){
27
			this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|",
28
			"insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull"/*"createLink"*/];
29
 
30
			this._plugins=[];
31
			this._editInterval = this.editActionInterval * 1000;
32
		},
33
 
34
		postCreate: function(){
35
			//for custom undo/redo
36
			if(this.customUndo){
37
				dojo['require']("dijit._editor.range");
38
				this._steps=this._steps.slice(0);
39
				this._undoedSteps=this._undoedSteps.slice(0);
40
//				this.addKeyHandler('z',this.KEY_CTRL,this.undo);
41
//				this.addKeyHandler('y',this.KEY_CTRL,this.redo);
42
			}
43
			if(dojo.isArray(this.extraPlugins)){
44
				this.plugins=this.plugins.concat(this.extraPlugins);
45
			}
46
 
47
//			try{
48
			dijit.Editor.superclass.postCreate.apply(this, arguments);
49
 
50
			this.commands = dojo.i18n.getLocalization("dijit._editor", "commands", this.lang);
51
 
52
			if(!this.toolbar){
53
				// if we haven't been assigned a toolbar, create one
54
				var toolbarNode = dojo.doc.createElement("div");
55
				dojo.place(toolbarNode, this.editingArea, "before");
56
				this.toolbar = new dijit.Toolbar({}, toolbarNode);
57
			}
58
 
59
			dojo.forEach(this.plugins, this.addPlugin, this);
60
			this.onNormalizedDisplayChanged(); //update toolbar button status
61
//			}catch(e){ console.debug(e); }
62
		},
63
		destroy: function(){
64
			dojo.forEach(this._plugins, function(p){
65
				if(p.destroy){
66
					p.destroy();
67
				}
68
			});
69
			this._plugins=[];
70
			this.toolbar.destroy(); delete this.toolbar;
71
			this.inherited('destroy',arguments);
72
		},
73
		addPlugin: function(/*String||Object*/plugin, /*Integer?*/index){
74
			//	summary:
75
			//		takes a plugin name as a string or a plugin instance and
76
			//		adds it to the toolbar and associates it with this editor
77
			//		instance. The resulting plugin is added to the Editor's
78
			//		plugins array. If index is passed, it's placed in the plugins
79
			//		array at that index. No big magic, but a nice helper for
80
			//		passing in plugin names via markup.
81
			//	plugin: String, args object or plugin instance. Required.
82
			//	args: This object will be passed to the plugin constructor.
83
			//	index:
84
			//		Integer, optional. Used when creating an instance from
85
			//		something already in this.plugins. Ensures that the new
86
			//		instance is assigned to this.plugins at that index.
87
			var args=dojo.isString(plugin)?{name:plugin}:plugin;
88
			if(!args.setEditor){
89
				var o={"args":args,"plugin":null,"editor":this};
90
				dojo.publish("dijit.Editor.getPlugin",[o]);
91
				if(!o.plugin){
92
					var pc = dojo.getObject(args.name);
93
					if(pc){
94
						o.plugin=new pc(args);
95
					}
96
				}
97
				if(!o.plugin){
98
					console.debug('Cannot find plugin',plugin);
99
					return;
100
				}
101
				plugin=o.plugin;
102
			}
103
			if(arguments.length > 1){
104
				this._plugins[index] = plugin;
105
			}else{
106
				this._plugins.push(plugin);
107
			}
108
			plugin.setEditor(this);
109
			if(dojo.isFunction(plugin.setToolbar)){
110
				plugin.setToolbar(this.toolbar);
111
			}
112
		},
113
		/* beginning of custom undo/redo support */
114
 
115
		// customUndo: Boolean
116
		//		Whether we shall use custom undo/redo support instead of the native
117
		//		browser support. By default, we only enable customUndo for IE, as it
118
		//		has broken native undo/redo support. Note: the implementation does
119
		//		support other browsers which have W3C DOM2 Range API.
120
		customUndo: dojo.isIE,
121
 
122
		//	editActionInterval: Integer
123
		//		When using customUndo, not every keystroke will be saved as a step.
124
		//		Instead typing (including delete) will be grouped together: after
125
		//		a user stop typing for editActionInterval seconds, a step will be
126
		//		saved; if a user resume typing within editActionInterval seconds,
127
		//		the timeout will be restarted. By default, editActionInterval is 3
128
		//		seconds.
129
		editActionInterval: 3,
130
		beginEditing: function(cmd){
131
			if(!this._inEditing){
132
				this._inEditing=true;
133
				this._beginEditing(cmd);
134
			}
135
			if(this.editActionInterval>0){
136
				if(this._editTimer){
137
					clearTimeout(this._editTimer);
138
				}
139
				this._editTimer = setTimeout(dojo.hitch(this, this.endEditing), this._editInterval);
140
			}
141
		},
142
		_steps:[],
143
		_undoedSteps:[],
144
		execCommand: function(cmd){
145
			if(this.customUndo && (cmd=='undo' || cmd=='redo')){
146
				return this[cmd]();
147
			}else{
148
				try{
149
					if(this.customUndo){
150
						this.endEditing();
151
						this._beginEditing();
152
					}
153
					var r = this.inherited('execCommand',arguments);
154
					if(this.customUndo){
155
						this._endEditing();
156
					}
157
					return r;
158
				}catch(e){
159
					if(dojo.isMoz && /copy|cut|paste/.test(cmd)){
160
						// Warn user of platform limitation.  Cannot programmatically access keyboard. See ticket #4136
161
						var sub = dojo.string.substitute,
162
							accel = {cut:'X', copy:'C', paste:'V'},
163
							isMac = navigator.userAgent.indexOf("Macintosh") != -1;
164
						alert(sub(this.commands.systemShortcutFF,
165
							[this.commands[cmd], sub(this.commands[isMac ? 'appleKey' : 'ctrlKey'], [accel[cmd]])]));
166
					}
167
					return false;
168
				}
169
			}
170
		},
171
		queryCommandEnabled: function(cmd){
172
			if(this.customUndo && (cmd=='undo' || cmd=='redo')){
173
				return cmd=='undo'?(this._steps.length>1):(this._undoedSteps.length>0);
174
			}else{
175
				return this.inherited('queryCommandEnabled',arguments);
176
			}
177
		},
178
		_changeToStep: function(from,to){
179
			this.setValue(to.text);
180
			var b=to.bookmark;
181
			if(!b){ return; }
182
			if(dojo.isIE){
183
				if(dojo.isArray(b)){//IE CONTROL
184
					var tmp=[];
185
					dojo.forEach(b,function(n){
186
						tmp.push(dijit.range.getNode(n,this.editNode));
187
					},this);
188
					b=tmp;
189
				}
190
			}else{//w3c range
191
				var r=dijit.range.create();
192
				r.setStart(dijit.range.getNode(b.startContainer,this.editNode),b.startOffset);
193
				r.setEnd(dijit.range.getNode(b.endContainer,this.editNode),b.endOffset);
194
				b=r;
195
			}
196
			dojo.withGlobal(this.window,'moveToBookmark',dijit,[b]);
197
		},
198
		undo: function(){
199
//			console.log('undo');
200
			this.endEditing(true);
201
			var s=this._steps.pop();
202
			if(this._steps.length>0){
203
				this.focus();
204
				this._changeToStep(s,this._steps[this._steps.length-1]);
205
				this._undoedSteps.push(s);
206
				this.onDisplayChanged();
207
				return true;
208
			}
209
			return false;
210
		},
211
		redo: function(){
212
//			console.log('redo');
213
			this.endEditing(true);
214
			var s=this._undoedSteps.pop();
215
			if(s && this._steps.length>0){
216
				this.focus();
217
				this._changeToStep(this._steps[this._steps.length-1],s);
218
				this._steps.push(s);
219
				this.onDisplayChanged();
220
				return true;
221
			}
222
			return false;
223
		},
224
		endEditing: function(ignore_caret){
225
			if(this._editTimer){
226
				clearTimeout(this._editTimer);
227
			}
228
			if(this._inEditing){
229
				this._endEditing(ignore_caret);
230
				this._inEditing=false;
231
			}
232
		},
233
		_getBookmark: function(){
234
			var b=dojo.withGlobal(this.window,dijit.getBookmark);
235
			if(dojo.isIE){
236
				if(dojo.isArray(b)){//CONTROL
237
					var tmp=[];
238
					dojo.forEach(b,function(n){
239
						tmp.push(dijit.range.getIndex(n,this.editNode).o);
240
					},this);
241
					b=tmp;
242
				}
243
			}else{//w3c range
244
				var tmp=dijit.range.getIndex(b.startContainer,this.editNode).o
245
				b={startContainer:tmp,
246
					startOffset:b.startOffset,
247
					endContainer:b.endContainer===b.startContainer?tmp:dijit.range.getIndex(b.endContainer,this.editNode).o,
248
					endOffset:b.endOffset};
249
			}
250
			return b;
251
		},
252
		_beginEditing: function(cmd){
253
			if(this._steps.length===0){
254
				this._steps.push({'text':this.savedContent,'bookmark':this._getBookmark()});
255
			}
256
		},
257
		_endEditing: function(ignore_caret){
258
			var v=this.getValue(true);
259
 
260
			this._undoedSteps=[];//clear undoed steps
261
			this._steps.push({'text':v,'bookmark':this._getBookmark()});
262
		},
263
		onKeyDown: function(e){
264
			if(!this.customUndo){
265
				this.inherited('onKeyDown',arguments);
266
				return;
267
			}
268
			var k=e.keyCode,ks=dojo.keys;
269
			if(e.ctrlKey){
270
				if(k===90||k===122){ //z
271
					dojo.stopEvent(e);
272
					this.undo();
273
					return;
274
				}else if(k===89||k===121){ //y
275
					dojo.stopEvent(e);
276
					this.redo();
277
					return;
278
				}
279
			}
280
			this.inherited('onKeyDown',arguments);
281
 
282
			switch(k){
283
					case ks.ENTER:
284
						this.beginEditing();
285
						break;
286
					case ks.BACKSPACE:
287
					case ks.DELETE:
288
						this.beginEditing();
289
						break;
290
					case 88: //x
291
					case 86: //v
292
						if(e.ctrlKey && !e.altKey && !e.metaKey){
293
							this.endEditing();//end current typing step if any
294
							if(e.keyCode == 88){
295
								this.beginEditing('cut');
296
								//use timeout to trigger after the cut is complete
297
								setTimeout(dojo.hitch(this, this.endEditing), 1);
298
							}else{
299
								this.beginEditing('paste');
300
								//use timeout to trigger after the paste is complete
301
								setTimeout(dojo.hitch(this, this.endEditing), 1);
302
							}
303
							break;
304
						}
305
						//pass through
306
					default:
307
						if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<dojo.keys.F1 || e.keyCode>dojo.keys.F15)){
308
							this.beginEditing();
309
							break;
310
						}
311
						//pass through
312
					case ks.ALT:
313
						this.endEditing();
314
						break;
315
					case ks.UP_ARROW:
316
					case ks.DOWN_ARROW:
317
					case ks.LEFT_ARROW:
318
					case ks.RIGHT_ARROW:
319
					case ks.HOME:
320
					case ks.END:
321
					case ks.PAGE_UP:
322
					case ks.PAGE_DOWN:
323
						this.endEditing(true);
324
						break;
325
					//maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
326
					case ks.CTRL:
327
					case ks.SHIFT:
328
					case ks.TAB:
329
						break;
330
				}
331
		},
332
		_onBlur: function(){
333
			this.inherited('_onBlur',arguments);
334
			this.endEditing(true);
335
		},
336
		onClick: function(){
337
			this.endEditing(true);
338
			this.inherited('onClick',arguments);
339
		}
340
		/* end of custom undo/redo support */
341
	}
342
);
343
 
344
/* the following code is to registered a handler to get default plugins */
345
dojo.subscribe("dijit.Editor.getPlugin",null,function(o){
346
	if(o.plugin){ return; }
347
	var args=o.args, p;
348
	var _p = dijit._editor._Plugin;
349
	var name=args.name;
350
	switch(name){
351
		case "undo": case "redo": case "cut": case "copy": case "paste": case "insertOrderedList":
352
		case "insertUnorderedList": case "indent": case "outdent": case "justifyCenter":
353
		case "justifyFull": case "justifyLeft": case "justifyRight": case "delete":
354
		case "selectAll": case "removeFormat":
355
			p = new _p({ command: name });
356
			break;
357
 
358
		case "bold": case "italic": case "underline": case "strikethrough":
359
		case "subscript": case "superscript":
360
			p = new _p({ buttonClass: dijit.form.ToggleButton, command: name });
361
			break;
362
		case "|":
363
			p = new _p({ button: new dijit.ToolbarSeparator() });
364
			break;
365
		case "createLink":
366
//					dojo['require']('dijit._editor.plugins.LinkDialog');
367
			p = new dijit._editor.plugins.LinkDialog({ command: name });
368
			break;
369
		case "foreColor": case "hiliteColor":
370
			p = new dijit._editor.plugins.TextColor({ command: name });
371
			break;
372
		case "fontName": case "fontSize": case "formatBlock":
373
			p = new dijit._editor.plugins.FontChoice({ command: name });
374
	}
375
//	console.log('name',name,p);
376
	o.plugin=p;
377
});
378
 
379
}