1function makeWidgetAreaDroppable(widgetID, $element, widgetType, allowMultipleFiles, callback) { 2 if (!window.ContentCollectionInstance) { 3 window.ContentCollectionInstance = new ContentCollectionClass(); 4 window.ContentCollectionInstance.init(); 5 } 6 7 window.FileDroppableInstance = new widgetNS.FileDroppableClass(); 8 9 window.FileDroppableInstance.Init(widgetID, $element, widgetType, allowMultipleFiles, callback); 10 window.FileDroppableInstance.MakeFileDroppable(); 11} 12 13//Namespace 14var widgetNS = createNamespace('CivicPlus.Javascript.Widgets'); 15widgetNS.fileDropSlideshowType = 0; 16/************************************************************************/ 17/*************************File Droppable Class Definition***************** 18/************************************************************************/ 19 20widgetNS.FileDroppableClass = function () { 21 22 //Properties 23 this.documentIDCollection = ''; //List of documentIDs being uploaded. 24 this.createdWidgetID = ''; //In case of widget creation, ID of the new widget created. 25 this.storedInSession = false; //Whether or not the HttpPostedFileBase info is stored in session. Only populated in case of widget creation mechanicsm. 26 this.$allTargets = $('.pageContent').find('.target'); //Grid targets. 27 this.$allIndicators = $('.indicator'); //Grid indicators. 28 this.$element = null; //Element in the DOM on which files are being dropped 29 this.widgetID = ''; //WidgetID of the widget on which the files are being dropped. '' in case of widget creation, createdWidgetID is 30 this.widgetType = 0; 31 this.dropType = null; 32 this.allowMultipleFiles = false; 33 this.callback = null; 34 this.DocOverEventRanOnce = false; 35 36 //Enums 37 this.slideshowActionTypeENUM = { OptionNotChosenYet: 0, CreateNew: 1, ModifyExisting: 2 }; 38 this.dropTypeENUM = { CreateWidget: 1, AddToExistingWidget: 2 }; 39 this.widgetTypeENUM = { None: 0, RelatedDocuments: 5, Image: 2, Slideshow: 3 }; 40 41 //Constant variables. 42 this.MODULE_ID = 75; 43 this.MAX_FILE_SIZE = 20; //File size in MB 44 this.VALID_IMAGE_TYPES = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/tiff', 'image/raw', 'image/ico']; 45 this.MAX_FILES_FOR_MULTIPLE_UPLOADS = 50; //Max number of files allowed to be uploaded at once. 46} 47 48widgetNS.FileDroppableClass.prototype.MakeFileDroppable = function () { 49 var classRef = this; 50 classRef.$element.filedrop({ 51 //fallback_id: 'upload_button', // an identifier of a standard file input element, becomes the target of "click" events on the dropzone 52 url: '/Admin/DocumentCenter/FileDrop/Step2_CreateDocument', // upload handler, handles each file separately, can also be a function taking the file and returning a url 53 paramname: 'file', // POST parameter name used on serverside to reference file, can also be a function taking the filename and returning the paramname 54 withCredentials: true, // make a cross-origin request with cookies 55 data: { 56 contentCollectionID: window.ContentCollectionInstance.ContentCollectionID, 57 widgetID: classRef.$element.hasClass('target') ? classRef.createdWidgetID : classRef.widgetID, 58 widgetType: classRef.widgetType 59 }, 60 error: function (err, file) { 61 switch (err) { 62 case 'BrowserNotSupported': 63 alert('browser does not support HTML5 drag and drop'); 64 classRef.DropHoverEffect(); 65 break; 66 case 'TooManyFiles': 67 alert('More than one file cannot be uploaded for this widget.'); 68 classRef.DropHoverEffect(); 69 break; 70 case 'FileTooLarge': 71 // program encountered a file whose size is greater than 'maxfilesize' 72 alert(file.name + ' has a file size that is too large.'); 73 classRef.DropHoverEffect(); 74 break; 75 case 'FileTypeNotAllowed': 76 alert('This file cannot be dropped onto this widget. Please check your file extension.'); 77 classRef.DropHoverEffect(); 78 break; 79 case 'FileExtensionNotAllowed': 80 // The file extension is not in the specified list 'allowedfileextensions' 81 classRef.DropHoverEffect(); 82 break; 83 case 'Bad Request': 84 alert('Server refusing to accept the file. Please check file name or type.'); 85 break; 86 default:
87 classRef.DropHoverEffect(); 88 break; 89 } 90 }, 91 allowedfiletypes: classRef.dropType === classRef.dropTypeENUM.CreateWidget ? [] : (classRef.widgetType === classRef.widgetTypeENUM.RelatedDocuments ? [] : ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/bmp', 'image/tiff', 'image/raw', 'image/ico']), // filetypes allowed by Content-Type. Empty array means no restrictions 92 allowedfileextensions: classRef.dropType === classRef.dropTypeENUM.CreateWidget ? [] : (classRef.widgetType === classRef.widgetTypeENUM.RelatedDocuments ? [] : ['.jpg', '.jpeg', '.jfif', '.png', '.gif', '.bmp', '.tiff', '.raw', '.ico']), // file extensions allowed. Empty array means no restrictions 93 maxfiles: classRef.allowMultipleFiles ? classRef.MAX_FILES_FOR_MULTIPLE_UPLOADS : 1, 94 maxfilesize: classRef.MAX_FILE_SIZE, 95 dragOver: function() { classRef.CreateHoverEffect(); }, 96 dragLeave: function() { classRef.DropHoverEffect(); }, 97 docOver: function() { classRef.EnableDroppableGridTargets(); }, 98 docLeave: function() { classRef.DisableDroppableGridTargets(); }, 99 drop: function(e) { 100 //Do not execute any logic here if a widget has been dropped from the Widgets tab under LiveEdit tabs. Since the widget becomes fileDroppable, it tries to execute this logic when anything is dropped on it, but in case of widgets from layout tab, nothing needs to be executed here. 101 let continueDrop = false; 102 const files = e.originalEvent?.dataTransfer?.files; 103 if (files?.length > 0) { 104 const letters = /^[\w.,=~!\s\-\)\(\[\]\{\}]+$/g; 105 for (let i = 0; i < files.length; i++) { 106 const file = files[i]; 107 if (!file.name.match(letters)) { 108 alert('You have an invalid character in your filename: ' + file.name + '. These are the accepted characters: a-z A-Z 0-9 ~ !( ) - _ = [ ] { } , .'); 109 classRef.DropHoverEffect(); 110 return false; 111 } 112 } 113 let url = '/Admin/DocumentCenter/FolderForModal/HasRights'; 114 $.ajaxSetup({ async: false }); 115 AJAX(url, 'POST', '', function (response) { 116 if (response.HasRights) { 117 continueDrop = true; 118 if (classRef.dropType === classRef.dropTypeENUM.CreateWidget) { 119 classRef.CreateWidget(e); 120 } 121 AJAX('/Admin/DocumentCenter/FileDrop/Step1_CreateFolder', 'POST', { widgetType: classRef.widgetType }, null, false); 122 classRef.EnableDroppableGridTargetsRanOnce = false; 123 } else { 124 alert(response.Message); 125 } 126 }, false); 127 $.ajaxSetup({ async: true}); 128 } 129 return continueDrop; 130 }, 131 uploadStarted: function (i, file, len) { 132 if (classRef.dropType === classRef.dropTypeENUM.CreateWidget) { 133 var widgetTypeString = (classRef.widgetType === classRef.widgetTypeENUM.Image ? 'Image' : (classRef.widgetType === classRef.widgetTypeENUM.RelatedDocuments ? 'Related Documents' : 'SlideShow')); 134 ajaxPostBackStart('Creating ' + widgetTypeString + ' Widget'); 135 } else 136 ajaxPostBackStart('Saving'); 137 }, 138 uploadFinished: function (i, file, response, time) { 139 if (response.StoredInSession == 1) { 140 classRef.storedInSession = true; 141 } 142 if (response.DocumentIDCollection != null && response.DocumentIDCollection != 0) 143 classRef.documentIDCollection += response.DocumentIDCollection + ','; 144 }, 145 beforeSend: function (file, i, done, e) { 146 if (classRef.widgetType === classRef.widgetTypeENUM.Slideshow) { 147 if (classRef.ExistingSlideshow()) // a slideshow already present. 148 { 149 $popUp_Slideshow = openCpModal({ 150 title: 'Slideshow', 151 className: 'newCP adminWrap cpPopOver admin modalSlideshow', 152 isFrontEnd: false, 153 useIframe: false, 154 draggable: true, 155 url: '/Admin/DocumentCenter/FileDrop/SlideshowCreateModifyModal' 156 }); 157 var interval = window.setInterval(function (e) { 158 if (widgetNS.fileDropSlideshowType !== classRef.slideshowActionTypeENUM.OptionNotChosenYet) { 159 done(); 160 window.clearInterval(interval); 161 } 162 }, 1000); 163 } else 164 done(); //Create a new slideshow withot asking options from user, since its a new slideshow. 165 } else { 166 done(); 167 } 168 }, 169 afterAll: function () { 170 if (classRef.storedInSession) { 171 classRef.ExecutePostWidgetCreationProcess(); 172 } else { 173 classRef.ExecutePostFilesUploadProcess(); 174 } 175 } 176 }); 177}; 178 179widgetNS.FileDroppableClass.prototype.Init = function (widgetID, $element, widgetType, allowMultipleFiles, callback) { 180 var classRef = this; 181 classRef.widgetID = widgetID; 182 classRef.$element = $element; 183 classRef.widgetType = widgetType; 184 classRef.allowMultipleFiles = allowMultipleFiles; 185 classRef.callback = callback; 186 classRef.dropType = classRef.DetermineDropType(); 187}; 188 189widgetNS.FileDroppableClass.prototype.DetermineWidgetType = function (event) { 190 var classRef = this; 191 var nonImageFile = false; 192 var dataTransfer = event.originalEvent?.dataTransfer; 193 if (!dataTransfer) { 194 return; // no data transfer bail.
195 } 196 if (dataTransfer.files.length === 1 && classRef.VALID_IMAGE_TYPES.indexOf(dataTransfer.files[0].type) !== -1) 197 return classRef.widgetTypeENUM.Image; 198 199 for (var i = 0; i < dataTransfer.files.length; i++) { 200 if (classRef.VALID_IMAGE_TYPES.indexOf(dataTransfer.files[i].type) === -1) { 201 nonImageFile = true; 202 } 203 } 204 return nonImageFile ? classRef.widgetTypeENUM.RelatedDocuments : classRef.widgetTypeENUM.Slideshow; 205}; 206 207widgetNS.FileDroppableClass.prototype.EnableDroppableGridTargets = function () { 208 const classRef = this; 209 const $body = $('body'); 210 if (!$body.hasClass('docOverRan')) { 211 $body.addClass('docOverRan'); 212 classRef.$allTargets.removeClass("targetOver"); 213 classRef.$allIndicators.removeClass('active'); 214 $('.pageContent.preDragging').removeClass('preDragging').addClass('dragging'); 215 } 216}; 217 218widgetNS.FileDroppableClass.prototype.DisableDroppableGridTargets = function () { 219 const classRef = this; 220 const $body = $('body'); 221 if ($body.hasClass('docOverRan')) { 222 $('.pageContent.dragging').removeClass('dragging').addClass('preDragging'); 223 classRef.$allTargets.removeClass("targetOver"); 224 classRef.$allIndicators.removeClass('active'); 225 $body.removeClass('docOverRan'); 226 } 227}; 228 229widgetNS.FileDroppableClass.prototype.CreateHoverEffect = function () { 230 const classRef = this; 231 if (classRef.$element.hasClass('target') && !classRef.$element.hasClass("targetOver")) { 232 classRef.$allTargets.removeClass("targetOver"); 233 classRef.$allIndicators.removeClass('active'); 234 classRef.$element.addClass("targetOver"); 235 const indicatorID = `#indicator_${classRef.$element.data('contentcontainerid')}_${classRef.$element.data('widgetcontainerid')}_${classRef.$element.data('sequence')}`; 236 $(indicatorID).addClass('active'); 237 return; 238 } 239 if (!classRef.$element.hasClass('targeted') && !classRef.$element.hasClass('target')) { 240 classRef.$allTargets.removeClass("targetOver"); 241 classRef.$allIndicators.removeClass('active'); 242 classRef.$element.addClass('targeted'); 243 } 244}; 245 246widgetNS.FileDroppableClass.prototype.DropHoverEffect = function () { 247 const classRef = this; 248 $('#divPermissions').remove(); 249 classRef.$element.removeClass('targeted'); 250 const indicatorID = `#indicator_${classRef.$element.data('contentcontainerid')}_${classRef.$element.data('widgetcontainerid')}_${classRef.$element.data('sequence')}`; 251 $(indicatorID).removeClass('active'); 252}; 253 254widgetNS.FileDroppableClass.prototype.GetPermissionString = function (groupName) { 255 var permString = ''; 256 $('input[name=' + groupName + ']').each(function (e) { 257 permString = $(this).val() + ','; 258 }); 259 return permString; 260}; 261 262widgetNS.FileDroppableClass.prototype.DetermineDropType = function () { 263 var classRef = this; 264 if (classRef.$element.hasClass('target')) 265 return classRef.dropTypeENUM.CreateWidget; 266 else 267 return classRef.dropTypeENUM.AddToExistingWidget; 268}; 269 270widgetNS.FileDroppableClass.prototype.CreateWidget = function (event) { 271 var classRef = this; 272 var contentContainerID = classRef.$element.data('contentcontainerid'); 273 var widgetContainerID = classRef.$element.data('widgetcontainerid'); 274 var sequence = classRef.$element.data('sequence'); 275 classRef.widgetType = classRef.DetermineWidgetType(event); 276 if (!classRef.widgetType) { 277 return; 278 } 279 var url = '/Layout/WidgetAdd/Add?contentCollectionID=' + window.ContentCollectionInstance.ContentCollectionID + '&widgetContainerID=' + widgetContainerID + '&sequence=' + sequence + '&widgetType=' + classRef.widgetType + '&contentContainerID=' + contentContainerID + '&parentID=null'; 280 AJAX(url, 'POST', '', function (response) { 281 classRef.createdWidgetID = response.WidgetID; 282 }, false); 283}; 284 285widgetNS.FileDroppableClass.prototype.ExecutePostWidgetCreationProcess = function () { 286 var classRef = this; 287 //Make a call again to Step2_CreateDocument passing in the newly created widgetID this time. 288 AJAX('/Admin/DocumentCenter/FileDrop/Step2_CreateDocument_WidgetAdded', 'POST', { 289 contentCollectionID: window.ContentCollectionInstance.ContentCollectionID, 290 widgetID: classRef.createdWidgetID, 291 widgetType: classRef.widgetType 292 }, function (response) { 293 if (response.DocumentIDCollection != 0) 294 classRef.documentIDCollection += response.DocumentIDCollection + ','; 295 AJAX('/Admin/DocumentCenter/FileDrop/Step3_SaveLayoutWidgetOptions', 'POST', { 296 contentCollectionID: window.ContentCollectionInstance.ContentCollectionID, 297 widgetID: classRef.createdWidgetID, 298 widgetType: classRef.widgetType, 299 fileDropSlideshowType: widgetNS.fileDropSlideshowType, 300 documentIDs: classRef.documentIDCollection, 301 slideshowID: classRef.$element.find('.hdnSlideshowUniqueID').val() 302 }, function (response) { 303 ajaxPostBackEnd(); 304 //Reset global variables. 305 classRef.ResetGlobalVariables(); 306 var contentContainerID = classRef.$element.data('contentcontainerid'); 307 window.ContentCollectionInstance.CurrentContentContainerIDs.push(contentContainerID); 308 window.ContentCollectionInstance.reloadContent(function () { $(window.Pages).trigger('ContentReload', classRef.widgetType) }); 309 window.setTimeout(makeGridTargetsFileDroppable, 1000); 310 $(window.Pages).trigger('WidgetAdded', classRef.widgetType); 311 }, false); 312 }, false); 313};
314 315widgetNS.FileDroppableClass.prototype.ExecutePostFilesUploadProcess = function () { 316 var classRef = this; 317 // runs after all files have been uploaded or otherwise dealt with 318 AJAX('/Admin/DocumentCenter/FileDrop/Step3_SaveLayoutWidgetOptions', 'POST', { 319 contentCollectionID: window.ContentCollectionInstance.ContentCollectionID, 320 widgetID: classRef.widgetID, 321 widgetType: classRef.widgetType, 322 fileDropSlideshowType: widgetNS.fileDropSlideshowType, 323 documentIDs: classRef.documentIDCollection, 324 slideshowID: classRef.$element.find('.hdnSlideshowUniqueID').val() 325 }, function (response) { 326 //Call to render 327 AJAX('/Admin/DocumentCenter/FileDrop/Step4_Callback', 'POST', { 328 contentCollectionID: window.ContentCollectionInstance.ContentCollectionID, 329 widgetID: classRef.widgetID, 330 widgetType: classRef.widgetType, 331 contentContainerID: classRef.$element.parents('.pageContent').filter(":first").data('containerid'), 332 pageID: window.ContentCollectionInstance.PageID 333 }, function (response) { 334 //Reset global variables. 335 classRef.ResetGlobalVariables(); 336 //remove background style 337 classRef.DropHoverEffect(); 338 if ($('#divPermissions').length > 0) 339 $('#divPermissions').remove(); 340 // response is the data you got back from server in JSON format. 341 classRef.callback(classRef.widgetID, response); 342 ajaxPostBackEnd(); 343 }, false); 344 }, false); 345}; 346 347widgetNS.FileDroppableClass.prototype.ResetGlobalVariables = function () { 348 var classRef = this; 349 //Reset global variables after files have been uploaded. 350 widgetNS.fileDropSlideshowType = 0; 351 classRef.documentIDCollection = ''; 352 classRef.DisableDroppableGridTargets(); 353 classRef.createdWidgetID = ''; 354}; 355 356widgetNS.FileDroppableClass.prototype.ExistingSlideshow = function () { 357 var classRef = this; 358 return classRef.$element.find('.cpSlideshow').length > 0; 359}; 360 361/************************************************************************/ 362/*************************File Droppable Class Definition Ends***** 363/************************************************************************/ 364 365///Updates the text for placeholders for 366/// 1 - Slideshow widget 367/// 2 - Image widget 368/// 3 - RelatedDocuments widget 369///in case the browser version doesnt suppport FileReaderAPI. 370function browserVersionNotCompatibleWithDragDropTextUpdate($element, text) { 371 //Hide element 372 $element.hide(); 373 374 var notCompatible = false; 375 var version = browserVersion(); 376 377 if (version != null) { 378 //IE 379 if (isMsie() && parseInt(version) < 10) 380 notCompatible = true; 381 //FF 382 else if (isMozilla() && parseInt(version) < 4) 383 notCompatible = true; 384 } 385 //Chrome 386 else (navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./) !== null && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) < 7) 387 notcompatible = true; 388 389 //If the browser does not support Html5 FileReaderAPI, change the placeholder text for the element accordingly. 390 if (notCompatible) 391 $element.text(text); 392 393 //Show the element 394 $element.show(); 395}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.