LocalImage.js 13 KB

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