Common.js - whitespace fixes
[civicrm-core.git] / js / angular-crmAttachment.js
index a8082879f9b9e0699fe2d276b2ca5781f2c32388..35dd1c582fe22fa8396b914c2321e1ff76775b1e 100644 (file)
@@ -1,8 +1,5 @@
 /// crmFile: Manage file attachments
 (function (angular, $, _) {
-  var partialUrl = function (relPath) {
-    return '~/crmAttachment/' + relPath;
-  };
 
   angular.module('crmAttachment', ['angularFileUpload']);
 
@@ -13,6 +10,7 @@
       var crmAttachments = this;
       this._target = target;
       this.files = [];
+      this.trash = [];
       this.uploader = new FileUploader({
         url: CRM.url('civicrm/ajax/attachment'),
         onAfterAddingFile: function onAfterAddingFile(item) {
             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;