1 /** 2 * Copyright (C) 2005-2010 Alfresco Software Limited. 3 * 4 * This file is part of Alfresco 5 * 6 * Alfresco is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Alfresco is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 /** 21 * Content control component. 22 * 23 * This component renders an editor appropriate for the the mimetype 24 * of the content. 25 * 26 * Plain text content is rendered in a textarea. 27 * Rich text content is rendered in a TinyMCE editor. 28 * Images are displayed with a file upload control. 29 * 30 * @namespace Alfresco 31 * @class Alfresco.ContentControl 32 */ 33 (function() 34 { 35 /** 36 * YUI Library aliases 37 */ 38 var Dom = YAHOO.util.Dom; 39 40 /** 41 * ContentControl constructor. 42 * 43 * @param {String} htmlId The HTML id of the parent element 44 * @return {Alfresco.TextControl} The new ContentControl instance 45 * @constructor 46 */ 47 Alfresco.ContentControl = function(htmlId) 48 { 49 return Alfresco.ContentControl.superclass.constructor.call(this, htmlId, "Alfresco.ContentControl"); 50 }; 51 52 YAHOO.extend(Alfresco.ContentControl, Alfresco.RichTextControl, 53 { 54 /** 55 * Object container for initialization options 56 * 57 * @property options 58 * @type object 59 */ 60 options: 61 { 62 /** 63 * Current Form Mode: edit or create 64 * 65 * @property formMode 66 * @type string 67 */ 68 formMode: "edit", 69 70 /** 71 * NodeRef of the item the form is for 72 * 73 * @property nodeRef 74 * @type string 75 */ 76 nodeRef: null, 77 78 /** 79 * The mimetype of the content being created 80 * 81 * @property mimeType 82 * @type string 83 */ 84 mimeType: null, 85 86 /** 87 * Comma separated list of mime types that will be shown 88 * in a textarea 89 * 90 * @property plainMimeTypes 91 * @type string 92 */ 93 plainMimeTypes: "text/plain,text/xml", 94 95 /** 96 * Comma separated list of mime types that will be shown 97 * in the TinyMCE editor 98 * 99 * @property richMimeTypes 100 * @type string 101 */ 102 richMimeTypes: "text/html,text/xhtml", 103 104 /** 105 * Comma separated list of mime types that will be shown 106 * using the img tag and allow upload of new versions 107 * 108 * @property imageMimeTypes 109 * @type string 110 */ 111 imageMimeTypes: "image/jpeg,image/jpg,image/png", 112 113 /** 114 * Whether the (plain text) editor should be forced visible, e.g. mimetype unrecognized 115 * 116 * @property forceEditor 117 * @type boolean 118 */ 119 forceEditor: false, 120 121 /** 122 * Whether (empty) content should be created when editor is hidden, e.g. mimetype unrecognized. 123 * Note: Only relevant when forceEditor = false 124 * 125 * @property forceContent 126 * @type boolean 127 */ 128 forceContent: false 129 }, 130 131 /** 132 * Fired by YUI when parent element is available for scripting. 133 * Component initialisation, including instantiation of YUI widgets and event listener binding. 134 * 135 * @method onReady 136 */ 137 onReady: function ContentControl_onReady() 138 { 139 if (Alfresco.logger.isDebugEnabled()) 140 { 141 Alfresco.logger.debug("Rendering content control for element '" + this.id + "', value = '" + this.options.currentValue + 142 "', nodeRef = '" + this.options.nodeRef + "', mimetype = '" + this.options.mimeType + "'"); 143 Alfresco.logger.debug("Configured plain mimetypes for element '" + this.id + "': " + this.options.plainMimeTypes); 144 Alfresco.logger.debug("Configured rich mimetypes for element '" + this.id + "': " + this.options.richMimeTypes); 145 Alfresco.logger.debug("Configured image mimetypes for element '" + this.id + "': " + this.options.imageMimeTypes); 146 Alfresco.logger.debug("Editor parameters for element '" + this.id + "': " + 147 YAHOO.lang.dump(this.options.editorParameters)); 148 } 149 150 // get the mimetype of the content 151 var contentMimetype = this._determineMimeType(); 152 153 if (contentMimetype !== null) 154 { 155 if (this._isRichMimeType(contentMimetype)) 156 { 157 if (this.options.formMode === "create") 158 { 159 // in create mode render the editor immediately 160 if (!this.options.disabled) 161 { 162 this._renderEditor(); 163 } 164 } 165 else 166 { 167 // populate the textarea with the content and 168 // once that is complete call the provided 169 // callback function to render the TinyMCE 170 // editor (when it's not disabled) 171 this._populateContent( 172 { 173 successCallback: 174 { 175 fn: function() 176 { 177 if (!this.options.disabled) 178 { 179 this._renderEditor(); 180 } 181 }, 182 scope: this 183 } 184 }); 185 } 186 } 187 else if (this._isPlainMimeType(contentMimetype) || this.options.forceEditor) 188 { 189 // populate the textarea with the content 190 this._populateContent(); 191 } 192 else if (this._isImageMimeType(contentMimetype)) 193 { 194 this._hideField(); 195 196 if (Alfresco.logger.isDebugEnabled()) 197 Alfresco.logger.debug("Hidden field '" + this.id + "' as support for images is not completed yet"); 198 199 // TODO: remove textarea from DOM 200 // add <img> to field DOM programatically 201 // add <input type="file" /> to DOM programatically 202 // make the image height and width configurable 203 // generate URL to the image using the nodeRef (cmis content webscript?) 204 // investigate whether the picked image can be shown 205 } 206 else 207 { 208 this._hideField(); 209 210 if (Alfresco.logger.isDebugEnabled()) 211 Alfresco.logger.debug("Hidden field '" + this.id + "' as the content for the mimetype can not be displayed"); 212 } 213 } 214 else 215 { 216 this._hideField(); 217 218 if (Alfresco.logger.isDebugEnabled()) 219 Alfresco.logger.debug("Hidden field '" + this.id + "' as the mimetype is unknown"); 220 } 221 }, 222 223 /** 224 * Retrieves and populates the content for the current control 225 * 226 * @method _populateContent 227 * @param callback Optional object containing a callback function 228 * @private 229 */ 230 _populateContent: function ContentControl__populateContent(callback) 231 { 232 if (this.options.nodeRef !== null && this.options.nodeRef.length > 0) 233 { 234 if (Alfresco.logger.isDebugEnabled()) 235 Alfresco.logger.debug("Retrieving content for field '" + this.id + "' using nodeRef: " + this.options.nodeRef); 236 237 // success handler, show the content 238 var onSuccess = function ContentControl_populateContent_onSuccess(response) 239 { 240 Dom.get(this.id).value = response.serverResponse.responseText; 241 242 // if a callback was provided, execute it 243 if (callback && callback.successCallback) 244 { 245 if (Alfresco.logger.isDebugEnabled()) 246 Alfresco.logger.debug("calling callback"); 247 248 callback.successCallback.fn.call(callback.successCallback.scope, response); 249 } 250 }; 251 252 // failure handler, display alert 253 var onFailure = function ContentControl_populateContent_onFailure(response) 254 { 255 // hide the whole field so incorrect content does not get re-submitted 256 this._hideField(); 257 258 if (Alfresco.logger.isDebugEnabled()) 259 Alfresco.logger.debug("Hidden field '" + this.id + "' as content retrieval failed"); 260 }; 261 262 // attempt to retrieve content 263 var nodeRefUrl = this.options.nodeRef.replace("://", "/"); 264 Alfresco.util.Ajax.request( 265 { 266 url: Alfresco.constants.PROXY_URI + "api/node/content/" + nodeRefUrl, 267 method: "GET", 268 successCallback: 269 { 270 fn: onSuccess, 271 scope: this 272 }, 273 failureCallback: 274 { 275 fn: onFailure, 276 scope: this 277 } 278 }); 279 } 280 else if (this.options.formMode !== "create") 281 { 282 this._hideField(); 283 284 if (Alfresco.logger.isDebugEnabled()) 285 Alfresco.logger.debug("Hidden field '" + this.id + "' as the nodeRef parameter is missing"); 286 } 287 }, 288 289 /** 290 * Returns the mimetype for the content property. 291 * 292 * Returns null if the field is not a content property. 293 * 294 * If a mimetype can not be determined from the content url of the property 295 * the mimeType parameter is examined, if that is empty or null, null is returned. 296 * 297 * @method _determineMimeType 298 * @return the mimetype or null if it can not be determined 299 */ 300 _determineMimeType: function ContentControl__determineMimeType() 301 { 302 var result = null; 303 304 if (this.options.currentValue.indexOf("contentUrl=") === 0 && 305 this.options.currentValue.indexOf("mimetype=") !== -1) 306 { 307 // extract the mimetype from the content url 308 var mtBegIdx = this.options.currentValue.indexOf("mimetype=") + 9, 309 mtEndIdx = this.options.currentValue.indexOf("|", mtBegIdx); 310 result = this.options.currentValue.substring(mtBegIdx, mtEndIdx); 311 } 312 313 // if the content url did not contain the mimetype examine 314 // the mimeType parameter 315 if (this.options.mimeType !== null && this.options.mimeType.length > 0) 316 { 317 result = this.options.mimeType; 318 } 319 320 if (Alfresco.logger.isDebugEnabled()) 321 Alfresco.logger.debug("Determined mimetype: " + result); 322 323 return result; 324 }, 325 326 /** 327 * Determines whether the given mimetype is a configured 'rich' mimetype. 328 * 329 * @method _isRichMimeType 330 * @param mimetype {string} The mimetype to check 331 * @return true if the given mimetype is a 'rich' mimetype 332 */ 333 _isRichMimeType: function ContentControl__isRichMimeType(mimetype) 334 { 335 var result = false; 336 337 if (this.options.richMimeTypes !== null && this.options.richMimeTypes.length > 0 && 338 this.options.richMimeTypes.indexOf(mimetype) != -1) 339 { 340 result = true; 341 } 342 343 if (Alfresco.logger.isDebugEnabled()) 344 Alfresco.logger.debug("Testing whether '" + mimetype + "' is a configured rich mimetype: " + result); 345 346 return result; 347 }, 348 349 /** 350 * Determines whether the given mimetype is a configured 'plain' mimetype. 351 * 352 * @method _isPlainMimeType 353 * @param mimetype {string} The mimetype to check 354 * @return true if the given mimetype is a 'plain' mimetype 355 */ 356 _isPlainMimeType: function ContentControl__isPlainMimeType(mimetype) 357 { 358 var result = false; 359 360 if (this.options.plainMimeTypes !== null && this.options.plainMimeTypes.length > 0 && 361 this.options.plainMimeTypes.indexOf(mimetype) != -1) 362 { 363 result = true; 364 } 365 366 if (Alfresco.logger.isDebugEnabled()) 367 Alfresco.logger.debug("Testing whether '" + mimetype + "' is a configured plain mimetype: " + result); 368 369 return result; 370 }, 371 372 /** 373 * Determines whether the given mimetype is a configured 'image' mimetype. 374 * 375 * @method _isImageMimeType 376 * @param mimetype {string} The mimetype to check 377 * @return true if the given mimetype is an 'image' mimetype 378 */ 379 _isImageMimeType: function ContentControl__isImageMimeType(mimetype) 380 { 381 var result = false; 382 383 if (this.options.imageMimeTypes !== null && this.options.imageMimeTypes.length > 0 && 384 this.options.imageMimeTypes.indexOf(mimetype) != -1) 385 { 386 result = true; 387 } 388 389 if (Alfresco.logger.isDebugEnabled()) 390 Alfresco.logger.debug("Testing whether '" + mimetype + "' is a configured image mimetype: " + result); 391 392 return result; 393 }, 394 395 /** 396 * Hides the field, used when a content property can not be shown. 397 * 398 * @method _hideField 399 * @private 400 */ 401 _hideField: function ContentControl__hideField() 402 { 403 if (!this.options.forceContent) 404 { 405 // change the name of the textarea so it is not submitted as new content! 406 Dom.get(this.id).name = "-"; 407 } 408 409 // hide the whole field 410 Dom.get(this.id + "-field").style.display = "none"; 411 } 412 }); 413 })(); 414