Move to sane directory structure. Don't make 'cms' the top level of the silverstripe...
[silverstripe-elijah.git] / javascript / AssetAdmin.js
blobb998831841238cb8aba7f83a4496916653da4851
1 /**
2  * Configuration for the left hand tree
3  */
4 if(typeof SiteTreeHandlers == 'undefined') SiteTreeHandlers = {};
5 SiteTreeHandlers.parentChanged_url = 'admin/assets/ajaxupdateparent';
6 SiteTreeHandlers.orderChanged_url = 'admin/assets/ajaxupdatesort';
7 SiteTreeHandlers.loadPage_url = 'admin/assets/getitem';
8 SiteTreeHandlers.loadTree_url = 'admin/assets/getsubtree';
9 SiteTreeHandlers.showRecord_url = 'admin/assets/show/';
10 var _HANDLER_FORMS = {
11         addpage : 'addpage_options',
12         deletepage : 'deletepage_options',
13         sortitems : 'sortitems_options'
16 /**
17  * Top-right actions
18  */
20 function action_upload_right(e) {
21         if(frames['AssetAdmin_upload'].document && frames['AssetAdmin_upload'].document.getElementById('Form_UploadForm')) {
22                 // make sure at least one file is selected for upload
23                 var values = "";
24                 var inputs = $A(frames['AssetAdmin_upload'].document.getElementsByTagName("input"));
25                 inputs.each(function(input) {
26                         if(input.type == "file") values += input.value;
27                 }.bind(this));
28                 
29                 if(values.length == 0) {
30                         alert("Please select at least one file for uploading");
31                         openTab("Root_Upload");
32                 } else {
33                         frames['AssetAdmin_upload'].document.getElementById('Form_UploadForm').submit();
34                 }
35         }
36         Event.stop(e);
37         return false;
40 /**
41  * Set up save folder name action
42  */
43 Behaviour.register( {
44         '#Form_EditForm_save': {
45                 onclick : function() {
46                         $('Form_EditForm').save(false, null, 'save', false);
47                         return false;
48                 }
49         }
50 });
52 MarkingPropertiesButton = Class.create();
53 MarkingPropertiesButton.applyTo('#Form_EditForm_deletemarked', "Please select some files to delete!", 'deletemarked', 'Do you really want to delete the marked files?');
55 MarkingPropertiesButton.prototype = {
56         initialize: function(noneCheckedError, action, confirmMessage) {
57                 this.noneCheckedError = noneCheckedError;
58                 this.action = action;
59                 this.confirmMessage = confirmMessage;
60         },
61         
62         onclick: function() {
63                 var i, list = "", checkboxes = $('Form_EditForm').elements['Files[]'];
64                 if(!checkboxes) checkboxes = [];
65                 if(!checkboxes.length) checkboxes = [ checkboxes ];
66                 for(i=0;i<checkboxes.length;i++) {
67                         if(checkboxes[i].checked) list += (list?',':'') + checkboxes[i].value;
68                 }
69                 
70                 if(list == "") {
71                         alert(this.noneCheckedError);
72                         return false;
73                         
74                 } else {
75                         $('Form_EditForm_FileIDs').value = list;
76                 }
77                 // If there is a confirmation message, show it before submitting
78                 if('' != this.confirmMessage) {
79                         // Only submit if OK button is clicked
80                         if (confirm(this.confirmMessage)) {
81                                 $('Form_EditForm').save(false, null, this.action);
82                         }
83                 } else {
84                         $('Form_EditForm').save(false, null, this.action);
85                 }
86                 return false;
87         }
91 // CheckBoxRange adapted from: http://jroller.com/page/rmcmahon?entry=checkboxrange_with_prototype
92 var CheckBoxRange = Class.create();
94 CheckBoxRange.prototype = {
95         currentBox: null,
96         form: null,
97         field: null,
99         initialize: function(form, field) {
100                 this.form = form;
101                 this.field = field;
102                 this.eventPossibleCheckHappened = this.possibleCheckHappened.bindAsEventListener(this);
103                 Event.observe(form, "click", this.eventPossibleCheckHappened);
104                 Event.observe(form, "keyup", this.eventPossibleCheckHappened);
105         },
106                 
107         possibleCheckHappened: function(event) {
108                 var target = Event.element(event);
109                         
110                 if ((event.button == 0 || event.keyCode == 32 || event.keyCode == 17) && 
111                         this.isCheckBox(target) && target.form == $(this.form) && target.name == this.field) {
112                         // If ctrl or shift is keys are pressed
113                         if ((event.shiftKey || event.ctrlKey  ) && this.currentBox)
114                                 this.updateCheckBoxRange(this.currentBox, target);
115                 this.currentBox = target;
116                 }
117         },
119         isCheckBox: function(e) {
120                 return (e.tagName.toLowerCase() == "input" && e.type.toLowerCase() == "checkbox");
121         },
123         updateCheckBoxRange: function(start, end) {
124                 var last_clicked = end;
125                 var checkboxes = Form.getInputs(this.form, 'checkbox', this.field);
126                 var checkbox;
127                 var last;
128                 
129                 for (var i=0; (checkbox = checkboxes[i]); ++i) {
130                 if (checkbox == end) {
131                         last = start;
132                         break;
133                 }
134                 if (checkbox == start) {
135                         last = end;
136                         break;
137                 }
138                 }
139                 
140                 for (; (checkbox = checkboxes[i]); ++i) {
141                         if (checkbox != last_clicked && checkbox.checked != last_clicked.checked)
142                                 checkbox.click();
143                         if (checkbox == last)
144                                 break;
145                 }
146         }
149 // SubsDraggable adapted from http://dev.rubyonrails.org/ticket/5771
151 // extentions for scriptaculous dragdrop.js
152 Object.extend(Class, {
153         superrise: function(obj, names){
154                 names.each( function(n){ obj['super_' + n] = obj[n] } )
155                 return obj;
156         }
159 // Draggable that allows substitution of draggable element
160 var SubsDraggable = Class.create();
162 SubsDraggable.prototype = Object.extend({}, Draggable.prototype);
163 Class.superrise(SubsDraggable.prototype, ['initialize', 'startDrag', 'finishDrag'])
164 Object.extend( SubsDraggable.prototype , {
165         initialize: function(event) {
166                 this.super_initialize.apply(this, arguments);
167                 if( typeof(this.options.dragelement) == 'undefined' ) this.options.dragelement = false;
168         },
169         startDrag: function(event) {
170                 if( this.options.dragelement ) {
171                         this._originalElement = this.element;
172                         // Get the id of the file being dragged
173                         var beingDraggedId = this.element.id.replace('drag-Files-','');
174                         this.element = this.options.dragelement(this.element);
175                         Position.absolutize(this.element);
176                         Position.clone(this._originalElement, this.element);
177                         // Add # files being moved message
178                         this.element.className = 'dragfile DraggedHandle';
179                         // We are at least moving the 1 file being dragged
180                         var numMoved = 1;
181                         var i, checkboxes = $('Form_EditForm').elements['Files[]'];
182                         if(!checkboxes) checkboxes = [];
183                         if(!checkboxes.length) checkboxes = [ checkboxes ];
184                         for(i=0;i<checkboxes.length;i++) {
185                                 // Total up the other files that are checked
186                                 if(checkboxes[i].checked && checkboxes[i].value != beingDraggedId) {
187                                         numMoved++;
188                                 }
189                         }
190                         numFilesIndicator = document.createElement('span');
191                         numFilesIndicator.innerHTML = 'Moving ' + numMoved + ' files';
192                         numFilesIndicator.className = 'NumFilesIndicator';
193                         this.element.appendChild(numFilesIndicator);
194                 }
195                 this.super_startDrag(event);
196         },
197         finishDrag: function(event, success) {
198                 this.super_finishDrag(event, success);
199         
200                 if(this.options.dragelement){
201                         Element.remove(this.element);
202                         this.element = this._originalElement;
203                         this._originalElement = null;
204                 }
205         }
207 // gets element that should be dragged instead of original element
208 // returned element should be added to DOM tree, and will be deleted by dragdrop library
209 function getDragElement(element){
210         var el = element.cloneNode(true);
211         el.id = '';
212         document.body.appendChild(el);
213         return el;
216 // Set up DRAG handle
217 DragFileItem = Class.create();
218 DragFileItem.prototype = {
219         initialize: function() {
220                         if (this.id)
221                         {
222                                 this.draggable = new SubsDraggable(this.id, {revert:true,ghosting:false,dragelement:getDragElement});
223                         }
224         },
225         destroy: function() {
226                 this.draggable = null;
227         }
229 DragFileItem.applyTo('#Form_EditForm_Files tr td.markingcheckbox div.dragfile');
231 // Set up folder drop target
232 DropFileItem = Class.create();
233 DropFileItem.prototype = {
234         initialize: function() {
235                 // Get this.recordID from the last "-" separated chunk of the id HTML attribute
236                 // eg: <li id="treenode-6"> would give a recordID of 6
237                 if(this.id && this.id.match(/-([^-]+)$/))
238                         this.recordID = RegExp.$1;
239                 // Do not allow files to be dropped to the root
240                 if (this.recordID != 'root') {
241                         this.droppable = Droppables.add(this.id, {accept:'dragfile', hoverclass:'filefolderhover',
242                                 onDrop:function(droppedElement) {
243                                         // Get this.recordID from the last "-" separated chunk of the id HTML attribute
244                                         // eg: <li id="treenode-6"> would give a recordID of 6
245                                         if(this.element.id && this.element.id.match(/-([^-]+)$/))
246                                                 this.recordID = RegExp.$1;
247                                         $('Form_EditForm').elements['DestFolderID'].value = this.recordID;
249                                         // Add the dropped file to the list of files to move
250                                         var list = droppedElement.getElementsByTagName('img')[0].id.replace('drag-img-Files-','');
251                                         var i, checkboxes = $('Form_EditForm').elements['Files[]'];
252                                         if(!checkboxes) checkboxes = [];
253                                         if(!checkboxes.length) checkboxes = [ checkboxes ];
254                                         // Add each checked file to the list of ones to move
255                                         for(i=0;i<checkboxes.length;i++) {
256                                                 if(checkboxes[i].checked) list += (list?',':'') + checkboxes[i].value;
257                                         }
258                                         $('Form_EditForm_FileIDs').value = list;
259                                         $('Form_EditForm').save(false, null, 'movemarked')
260                                 }
261                         });
262                 }
263         },
264         destroy: function() {
265                 this.droppable = null;
266                 this.recordID = null;
267         }
269 DropFileItem.applyTo('#sitetree li');
273  * Add File Action
274  */
275 addfolder = Class.create();
276 addfolder.applyTo('#addpage');
277 addfolder.prototype = {
278         initialize: function () {
279                 Observable.applyTo($(this.id + '_options'));
280                 this.getElementsByTagName('button')[0].onclick = returnFalse;
281                 $(this.id + '_options').onsubmit = this.form_submit;
282                 
283         },
284         
285         onclick : function() {
286                 statusMessage('Creating new folder...');
287                 this.form_submit();
288 /*              
289                         if(treeactions.toggleSelection(this)) {
290                         var selectedNode = $('sitetree').firstSelected();
291                         
292                         if(selectedNode) {
293                                 while(selectedNode.parentTreeNode && !selectedNode.hints.defaultChild) {
294                                         $('sitetree').changeCurrentTo(selectedNode.parentTreeNode);
295                                         selectedNode = selectedNode.parentTreeNode;
296                                 }
297                         }
298                 }
299 */              
300                 return false;
301         },
303         form_submit : function() {
304                 var st = $('sitetree');
306                 $('addpage_options').elements.ParentID.value = st.getIdxOf(st.firstSelected());         
307                 Ajax.SubmitForm('addpage_options', null, {
308                         onSuccess : this.onSuccess,
309                         onFailure : this.showAddPageError
310                 });
311                 return false;
312         },
313         onSuccess: function(response) {
314                 Ajax.Evaluator(response);
315                 // Make it possible to drop files into the new folder
316                 DropFileItem.applyTo('#sitetree li');
317         },
318         showAddPageError: function(response) {
319                 errorMessage('Error adding folder', response);
320         }       
325  * Delete folder action
326  */
327 deletefolder = {
328         button_onclick : function() {
329                 if(treeactions.toggleSelection(this)) {
330                         deletefolder.o1 = $('sitetree').observeMethod('SelectionChanged', deletefolder.treeSelectionChanged);
331                         deletefolder.o2 = $('deletepage_options').observeMethod('Close', deletefolder.popupClosed);
332                         
333                         addClass($('sitetree'),'multiselect');
335                         deletefolder.selectedNodes = { };
337                         var sel = $('sitetree').firstSelected()
338                         if(sel) {
339                                 var selIdx = $('sitetree').getIdxOf(sel);
340                                 deletefolder.selectedNodes[selIdx] = true;
341                                 sel.removeNodeClass('current');
342                                 sel.addNodeClass('selected');           
343                         }
344                 }
345                 return false;
346         },
348         treeSelectionChanged : function(selectedNode) {
349                 var idx = $('sitetree').getIdxOf(selectedNode);
351                 if(selectedNode.selected) {
352                         selectedNode.removeNodeClass('selected');
353                         selectedNode.selected = false;
354                         deletefolder.selectedNodes[idx] = false;
356                 } else {
357                         selectedNode.addNodeClass('selected');
358                         selectedNode.selected = true;
359                         deletefolder.selectedNodes[idx] = true;
360                 }
361                 
362                 return false;
363         },
364         
365         popupClosed : function() {
366                 removeClass($('sitetree'),'multiselect');
367                 $('sitetree').stopObserving(deletefolder.o1);
368                 $('deletepage_options').stopObserving(deletefolder.o2);
370                 for(var idx in deletefolder.selectedNodes) {
371                         if(deletefolder.selectedNodes[idx]) {
372                                 node = $('sitetree').getTreeNodeByIdx(idx);
373                                 if(node) {
374                                         node.removeNodeClass('selected');
375                                         node.selected = false;
376                                 }
377                         }
378                 }
379         },
381         form_submit : function() {
382                 var csvIDs = "";
383                 for(var idx in deletefolder.selectedNodes) {
384                         var selectedNode = $('sitetree').getTreeNodeByIdx(idx);
385                         var link = selectedNode.getElementsByTagName('a')[0];
386                         
387                         if(deletefolder.selectedNodes[idx] && ( !Element.hasClassName( link, 'contents' ) || confirm( "'" + link.firstChild.nodeValue + "' contains files. Would you like to delete the files and folder?" ) ) ) 
388                                 csvIDs += (csvIDs ? "," : "") + idx;
389                 }
390                 
391                 if(csvIDs) {
392                         $('deletepage_options').elements.csvIDs.value = csvIDs;
393                         
394                         statusMessage('deleting pages');
396                         Ajax.SubmitForm('deletepage_options', null, {
397                                 onSuccess : deletefolder.submit_success,
398                                 onFailure : function(response) {
399                                         errorMessage('Error deleting pages', response);
400                                 }
401                         });
403                         $('deletepage').getElementsByTagName('button')[0].onclick();
404                         
405                 } else {
406                         alert("Please select at least 1 page.");
407                 }
409                 return false;
410         },
411         
412         submit_success: function(response) {
413                 Ajax.Evaluator(response);
414                 treeactions.closeSelection($('deletepage'));
415         }
418 Behaviour.register({
419         '#Form_EditForm_Files': {
420                 removeFile : function(fileID) {
421                         var record;
422                         if(record = $('record-' + fileID)) {
423                                 record.parentNode.removeChild(record);
424                         } 
425                 }
426         },      
427         
428         '#Form_EditForm_Files a.deletelink' : {
429                 onclick : function(event) {
430                         ajaxLink(this.href);
431                         Event.stop(event);
432                         return false;
433                 }
434         },
435         
436         
437         '#Form_EditForm' : {
438                 changeDetection_fieldsToIgnore : {
439                         'Files[]' : true
440                 }
441         }
445  * We don't want hitting the enter key in the name field
446  * to submit the form.
447  */
448  Behaviour.register({
449         '#Form_EditForm_Name' : {
450                 onkeypress : function(event) {
451                         event = (event) ? event : window.event;
452                         var kc = event.keyCode ? event.keyCode : event.charCode;
453                         if(kc == 13) {
454                                 return false;
455                         }
456                 }
457         }
458  });
460 /** 
461  * Initialisation function to set everything up
462  */
463 appendLoader(function () {
464         // Set up delete page
465         Observable.applyTo($('deletepage_options'));
466         if($('deletepage')) {
467                 $('deletepage').onclick = deletefolder.button_onclick;
468                 $('deletepage').getElementsByTagName('button')[0].onclick = function() { return false; };
469                 $('deletepage_options').onsubmit = deletefolder.form_submit;
470         }