source: Dev/trunk/src/client/dojox/editor/plugins/LocalImage.js

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 12.1 KB
Line 
1define([
2        "dojo",//FIXME
3        "dijit",//FIXME
4        "dijit/registry",
5        "dijit/_base/popup",
6        "dijit/_editor/_Plugin",
7        "dijit/_editor/plugins/LinkDialog",
8        "dijit/TooltipDialog",
9        "dijit/form/_TextBoxMixin",
10        "dijit/form/Button",
11        "dijit/form/ValidationTextBox",
12        "dijit/form/DropDownButton",
13        "dojo/_base/connect",
14        "dojo/_base/declare",
15        "dojo/_base/sniff",
16        "dojox/form/FileUploader", //FIXME: deprecated.  Use Uploader instead
17        "dojo/i18n!dojox/editor/plugins/nls/LocalImage"
18], function(dojo, dijit, registry, popup, _Plugin, LinkDialog, TooltipDialog,
19                        _TextBoxMixin, Button, ValidationTextBox, DropDownButton,
20                        connect, declare, has, FileUploader, messages) {
21
22var LocalImage = dojo.declare("dojox.editor.plugins.LocalImage", LinkDialog.ImgLinkDialog, {
23        // summary:
24        //              This plugin provides an enhanced image link dialog that
25        //              not only insert the online images, but upload the local image files onto
26        //              to server then insert them as well.
27        //
28        //              Dependencies:
29        //              This plugin depends on dojox.form.FileUploader to upload the images on the local driver.
30        //              Do the regression test whenever FileUploader is upgraded.
31       
32        // uploadable: [public] Boolean
33        //              Indicate whether the user can upload a local image file onto the server.
34        //              If it is set to true, the Browse button will be available.
35        uploadable: false,
36       
37        // uploadUrl: [public] String
38        //              The url targeted for uploading. Both absolute and relative URLs are OK.
39        uploadUrl: "",
40       
41        // baseImageUrl: [public] String
42        //              The prefix of the image url on the server.
43        //              For example, an image is uploaded and stored at
44        //              `http://www.myhost.com/images/uploads/test.jpg`.
45        //              When the image is uploaded, the server returns "uploads/test.jpg" as the
46        //              relative path. So the baseImageUrl should be set to "http://www.myhost.com/images/"
47        //              so that the client can retrieve the image from the server.
48        //              If the image file is located on the same domain as that of the current web page,
49        //              baseImageUrl can be a relative path. For example:
50        // |    baseImageUrl = images/
51        //              and the server returns uploads/test.jpg
52        //              The complete URL of the image file is images/upload/test.jpg
53        baseImageUrl: "",
54       
55        // fileMask: [public] String
56        //              Specify the types of images that are allowed to be uploaded.
57        //              Note that the type checking on server is also very important!
58        fileMask: "*.jpg;*.jpeg;*.gif;*.png;*.bmp",
59       
60        // urlRegExp: [protected] String
61        //              Used to validate if the input is a valid image URL.
62        urlRegExp: "",
63       
64        // htmlFieldName: [private] htmlFieldName
65        htmlFieldName:"uploadedfile",
66       
67        // _isLocalFile: [private] Boolean
68        //              Indicate if a local file is to be uploaded to the server
69        //              If false, the text of _urlInput field is regarded as the
70        //              URL of the online image
71        _isLocalFile: false,
72       
73        // _messages: [private] Array<String>
74        //              Contains i18n strings.
75        _messages: "",
76       
77        // _cssPrefix: [private] String
78        //              The prefix of the CSS style
79        _cssPrefix: "dijitEditorEilDialog",
80       
81        // _closable: [private] Boolean
82        //              Indicate if the tooltip dialog can be closed. Used to workaround Safari 5 bug
83        //              where the file dialog doesn't pop up in modal until after the first click.
84        _closable: true,
85       
86        // linkDialogTemplate: [protected] String
87        //              Over-ride for template since this is an enhanced image dialog.
88        linkDialogTemplate: [
89                "<div style='border-bottom: 1px solid black; padding-bottom: 2pt; margin-bottom: 4pt;'></div>", // <hr/> breaks the dialog in IE6
90                "<div class='dijitEditorEilDialogDescription'>${prePopuTextUrl}${prePopuTextBrowse}</div>",
91                "<table role='presentation'><tr><td colspan='2'>",
92                "<label for='${id}_urlInput' title='${prePopuTextUrl}${prePopuTextBrowse}'>${url}</label>",
93                "</td></tr><tr><td class='dijitEditorEilDialogField'>",
94                "<input dojoType='dijit.form.ValidationTextBox' class='dijitEditorEilDialogField'" +
95                "regExp='${urlRegExp}' title='${prePopuTextUrl}${prePopuTextBrowse}'  selectOnClick='true' required='true' " +
96                "id='${id}_urlInput' name='urlInput' intermediateChanges='true' invalidMessage='${invalidMessage}' " +
97                "prePopuText='&lt;${prePopuTextUrl}${prePopuTextBrowse}&gt'>",
98                "</td><td>",
99                "<div id='${id}_browse' style='display:${uploadable}'>${browse}</div>",
100                "</td></tr><tr><td colspan='2'>",
101                "<label for='${id}_textInput'>${text}</label>",
102                "</td></tr><tr><td>",
103                "<input dojoType='dijit.form.TextBox' required='false' id='${id}_textInput' " +
104                "name='textInput' intermediateChanges='true' selectOnClick='true' class='dijitEditorEilDialogField'>",
105                "</td><td></td></tr><tr><td>",
106                "</td><td>",
107                "</td></tr><tr><td colspan='2'>",
108                "<button dojoType='dijit.form.Button' id='${id}_setButton'>${set}</button>",
109                "</td></tr></table>"
110        ].join(""),
111
112        _initButton: function(){
113                // summary:
114                //              Override _Plugin._initButton() to initialize DropDownButton and TooltipDialog.
115                // tags:
116                //              protected
117                var _this = this;
118                this._messages = messages;
119                this.tag = "img";
120                var dropDown = (this.dropDown = new TooltipDialog({
121                        title: messages[this.command + "Title"],
122                        onOpen: function(){
123                                _this._initialFileUploader();
124                                _this._onOpenDialog();
125                                TooltipDialog.prototype.onOpen.apply(this, arguments);
126                                setTimeout(function(){
127                                        // Auto-select the text if it is not empty
128                                        _TextBoxMixin.selectInputText(_this._urlInput.textbox);
129                                        _this._urlInput.isLoadComplete = true;
130                                }, 0);
131                        },
132                        onClose: function(){
133                                dojo.disconnect(_this.blurHandler);
134                                _this.blurHandler = null;
135                                this.onHide();
136                        },
137                        onCancel: function(){
138                                setTimeout(dojo.hitch(_this, "_onCloseDialog"),0);
139                        }
140                }));
141               
142                var label = this.getLabel(this.command),
143                        className = this.iconClassPrefix + " " + this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1),
144                        props = dojo.mixin({
145                                        label: label,
146                                        showLabel: false,
147                                        iconClass: className,
148                                        dropDown: this.dropDown,
149                                        tabIndex: "-1"
150                                }, this.params || {});
151               
152                if(!has('ie')){
153                        // Workaround for Non-IE problem:
154                        // Safari 5: After the select-file dialog opens, the first time the user clicks anywhere (even on that dialog)
155                        // it's treated like a plain click on the page, and the tooltip dialog closes
156                        // FF & Chrome: the select-file dialog does not block the execution of JS
157                        props.closeDropDown = function(/*Boolean*/ focus){
158                                if(_this._closable){
159                                        if(this._opened){
160                                                popup.close(this.dropDown);
161                                                if(focus){ this.focus(); }
162                                                this._opened = false;
163                                                this.state = "";
164                                        }
165                                }
166                                setTimeout(function(){ _this._closable = true; }, 10);
167                        };
168                }
169               
170                this.button = new DropDownButton(props);
171               
172                // Generate the RegExp of the ValidationTextBox from fileMask
173                // *.jpg;*.png => /.*\.jpg|.*\.JPG|.*\.png|.*\.PNG/
174                var masks = this.fileMask.split(";"),
175                        temp = "";
176                dojo.forEach(masks, function(m){
177                        m = m.replace(/\./, "\\.").replace(/\*/g, ".*");
178                        temp += "|" + m + "|" + m.toUpperCase();
179                });
180                messages.urlRegExp = this.urlRegExp = temp.substring(1);
181               
182                if(!this.uploadable){
183                        messages.prePopuTextBrowse = ".";
184                }
185               
186                messages.id = registry.getUniqueId(this.editor.id);
187                messages.uploadable = this.uploadable ? "inline" : "none";
188                this._uniqueId = messages.id;
189                this._setContent("<div class='" + this._cssPrefix + "Title'>" + dropDown.title + "</div>" +
190                        dojo.string.substitute(this.linkDialogTemplate, messages));
191                dropDown.startup();
192               
193                var urlInput = (this._urlInput = registry.byId(this._uniqueId + "_urlInput"));
194                this._textInput = registry.byId(this._uniqueId + "_textInput");
195                this._setButton = registry.byId(this._uniqueId + "_setButton");
196               
197                if(urlInput){
198                        var pt = ValidationTextBox.prototype;
199                        urlInput = dojo.mixin(urlInput, {
200                                // Indicate if the widget is ready to validate the input text
201                                isLoadComplete: false,
202                                isValid: function(isFocused){
203                                        if(this.isLoadComplete){
204                                                return pt.isValid.apply(this, arguments);
205                                        }else{
206                                                return this.get("value").length > 0;
207                                        }
208                                },
209                                reset: function(){
210                                        this.isLoadComplete = false;
211                                        pt.reset.apply(this, arguments);
212                                }
213                        });
214                       
215                        this.connect(urlInput, "onKeyDown", "_cancelFileUpload");
216                        this.connect(urlInput, "onChange", "_checkAndFixInput");
217                }
218                if(this._setButton){
219                        this.connect(this._setButton, "onClick", "_checkAndSetValue");
220                }
221                this._connectTagEvents();
222        },
223       
224        _initialFileUploader: function(){
225                // summary:
226                //              Initialize the FileUploader and connect up its events
227                // tags:
228                //              private
229                var fup = null,
230                        _this = this,
231                        widgetId = _this._uniqueId,
232                        fUpId = widgetId + "_browse",
233                        urlInput = _this._urlInput;
234               
235                if(_this.uploadable && !_this._fileUploader){
236                        fup = _this._fileUploader = new FileUploader({
237                                force: "html", // Noticed that SWF may cause browsers to crash sometimes
238                                uploadUrl: _this.uploadUrl,
239                                htmlFieldName: _this.htmlFieldName,
240                                uploadOnChange: false,
241                                selectMultipleFiles: false,
242                                showProgress: true
243                        }, fUpId);
244                       
245                        // TooltipDialog will call reset on all the widgets contained within it.
246                        // Have FileUploader be responsive to this call.
247                        fup.reset = function(){
248                                _this._isLocalFile = false;
249                                fup._resetHTML();
250                        };
251                       
252                        _this.connect(fup, "onClick", function(){
253                                urlInput.validate(false);
254                                if(!has('ie')){
255                                        // Firefox, Chrome and Safari have a strange behavior:
256                                        // When the File Upload dialog is open, the browse div (FileUploader) will lose its focus
257                                        // and triggers onBlur event. This event will cause the whole tooltip dialog
258                                        // to be closed when the File Upload dialog is open. The popup dialog should hang up
259                                        // the js execution rather than triggering an event. IE does not have such a problem.
260                                        _this._closable = false;
261                                }
262                        });
263
264                       
265                        _this.connect(fup, "onChange", function(data){
266                                _this._isLocalFile = true;
267                                urlInput.set("value", data[0].name); //Single selection
268                                urlInput.focus();
269                        });
270                       
271                        _this.connect(fup, "onComplete", function(data){
272                                var urlPrefix = _this.baseImageUrl;
273                                urlPrefix = urlPrefix && urlPrefix.charAt(urlPrefix.length - 1) == "/" ? urlPrefix : urlPrefix + "/";
274                                urlInput.set("value", urlPrefix + data[0].file); //Single selection
275                                _this._isLocalFile = false;
276                                _this._setDialogStatus(true);
277                                _this.setValue(_this.dropDown.get("value"));
278                        });
279                       
280                        _this.connect(fup, "onError", function(evtObject){
281                                // summary:
282                                //              Fires on errors
283                                console.log("Error occurred when uploading image file!");
284                                _this._setDialogStatus(true);
285                        });
286                }
287        },
288       
289        _checkAndFixInput: function(){
290                // summary:
291                //              Over-ride the original method
292                this._setButton.set("disabled", !this._isValid());
293        },
294       
295        _isValid: function(){
296                // summary:
297                //              Invalid cases: URL is not ended with the suffix listed
298                return this._urlInput.isValid();
299        },
300       
301        _cancelFileUpload: function(){
302                this._fileUploader.reset();
303                this._isLocalFile = false;
304        },
305       
306        _checkAndSetValue: function(){
307                // summary:
308                //              Determine if a local file is to be uploaded.
309                //              If a local file is to be uploaded, do not close the dialog
310                //              until the file uploading is finished. Else, insert the image directly into the editor.
311                // tags:
312                //              private
313                if(this._fileUploader && this._isLocalFile){
314                        this._setDialogStatus(false);
315                        this._fileUploader.upload();
316                }else{
317                        this.setValue(this.dropDown.get("value"));
318                }
319        },
320       
321        _setDialogStatus: function(/*Boolean*/ value){
322                this._urlInput.set("disabled", !value);
323                this._textInput.set("disabled", !value);
324                this._setButton.set("disabled", !value);
325        },
326       
327        destroy: function(){
328                // summary:
329                //              Cleanup of the plugin.
330                this.inherited(arguments);
331                if(this._fileUploader){
332                        this._fileUploader.destroy();
333                        delete this._fileUploader;
334                }
335        }
336});
337
338var plugin = function(args){
339        return new LocalImage({
340                command: "insertImage",
341                uploadable: ("uploadable" in args) ? args.uploadable : false,
342                uploadUrl: ("uploadable" in args && "uploadUrl" in args) ? args.uploadUrl : "",
343                htmlFieldName: ("uploadable" in args && "htmlFieldName" in args) ? args.htmlFieldName : "uploadedfile",
344                baseImageUrl: ("uploadable" in args && "baseImageUrl" in args) ? args.baseImageUrl : "",
345                fileMask: ("fileMask" in args) ? args.fileMask : "*.jpg;*.jpeg;*.gif;*.png;*.bmp"
346        });
347};
348
349// Register the plugin and some name varients.
350_Plugin.registry["LocalImage"] = plugin;
351_Plugin.registry["localImage"] = plugin;
352_Plugin.registry["localimage"] = plugin;
353
354return LocalImage;
355
356});
Note: See TracBrowser for help on using the repository browser.