Common.js - whitespace fixes
[civicrm-core.git] / js / angular-crmAttachment.js
index 07578cbd2a7781620fad3d5202ea1dc440b1ec81..35dd1c582fe22fa8396b914c2321e1ff76775b1e 100644 (file)
@@ -1,20 +1,16 @@
 /// crmFile: Manage file attachments
 (function (angular, $, _) {
-  var partialUrl = function (relPath) {
-    return CRM.resourceUrls['civicrm'] + '/partials/crmAttachment/' + relPath;
-  };
 
   angular.module('crmAttachment', ['angularFileUpload']);
 
   // crmAttachment manages the list of files which are attached to a given entity
   angular.module('crmAttachment').factory('CrmAttachments', function (crmApi, crmStatus, FileUploader, $q) {
-    var _target;
-
     // @param target an Object(entity_table:'',entity_id:'') or function which generates an object
     function CrmAttachments(target) {
-      _target = target;
       var crmAttachments = this;
+      this._target = target;
       this.files = [];
+      this.trash = [];
       this.uploader = new FileUploader({
         url: CRM.url('civicrm/ajax/attachment'),
         onAfterAddingFile: function onAfterAddingFile(item) {
@@ -37,7 +33,7 @@
     angular.extend(CrmAttachments.prototype, {
       // @return Object(entity_table:'',entity_id:'')
       getTarget: function () {
-        return (angular.isFunction(_target) ? _target() : _target);
+        return (angular.isFunction(this._target) ? this._target() : this._target);
       },
       // @return Promise<Attachment>
       load: function load() {
@@ -78,7 +74,7 @@
             var newItems = crmAttachments.uploader.getNotUploadedItems();
             if (newItems.length > 0) {
               _.each(newItems, function (item) {
-                item.formData = [_.extend({}, target, item.crmData)];
+                item.formData = [_.extend({crm_attachment_token: CRM.crmAttachment.token}, target, item.crmData)];
               });
               crmAttachments.uploader.onCompleteAll = function onCompleteAll() {
                 delete crmAttachments.uploader.onCompleteAll;
             return dfr.promise;
           });
       },
+      // Compute a digest over the list of files. The signature should change if the attachment list has changed
+      // (become dirty).
+      getAutosaveSignature: function getAutosaveSignature() {
+        var sig = [];
+        // Attachments have a special lifecycle, and attachments.queue is not properly serializable, so
+        // it takes some special effort to figure out a suitable signature. Issues which can cause gratuitous saving:
+        //  - Files move from this.uploader.queue to this.files after upload.
+        //  - File names are munged after upload.
+        //  - Deletes are performed immediately (outside the save process).
+        angular.forEach(this.files, function(item) {
+          sig.push({f: item.name.replace(/[^a-zA0-Z0-9\.]/, '_'), d: item.description});
+        });
+        angular.forEach(this.uploader.queue, function(item) {
+          sig.push({f: item.file.name.replace(/[^a-zA0-Z0-9\.]/, '_'), d: item.crmData.description});
+        });
+        angular.forEach(this.trash, function(item) {
+          sig.push({f: item.name.replace(/[^a-zA0-Z0-9\.]/, '_'), d: item.description});
+        });
+        return _.sortBy(sig, 'name');
+      },
       // @param Object file APIv3 attachment record (e.g. id, entity_table, entity_id, description)
       deleteFile: function deleteFile(file) {
         var crmAttachments = this;
           this.files.splice(idx, 1);
         }
 
+        this.trash.push(file);
+
         if (file.id) {
           var p = crmApi('Attachment', 'delete', {id: file.id}).then(
             function () { // success
               var msg = angular.isObject(response) ? response.error_message : '';
               CRM.alert(msg, ts('Deletion failed'));
               crmAttachments.files.push(file);
+
+              var trashIdx = _.indexOf(crmAttachments.trash, file);
+              if (trashIdx != -1) {
+                crmAttachments.trash.splice(trashIdx, 1);
+              }
             }
           );
           return crmStatus({start: ts('Deleting...'), success: ts('Deleted')}, p);
         var model = $parse(attr.crmAttachments);
         scope.att = model(scope.$parent);
         scope.ts = CRM.ts(null);
-        scope.inclUrl = partialUrl('attachments.html');
+        scope.inclUrl = '~/crmAttachment/attachments.html';
 
         // delay rendering of child tree until after model has been populated
         scope.ready = true;