/usr/share/civicrm/ang/crmAutosave.js is in civicrm-common 4.7.1+dfsg-2ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | /// crmAutosave
(function(angular, $, _) {
angular.module('crmAutosave', ['crmUtil']);
// usage:
// var autosave = new CrmAutosaveCtrl({
// save: function -- A function to handle saving. Should return a promise.
// If it's not a promise, then we'll assume that it completes successfully.
// saveIf: function -- Only allow autosave when conditional returns true. Default: !form.$invalid
// model: object|function -- (Re)schedule saves based on observed changes to object. We perform deep
// inspection on the model object. This could be a performance issue you
// had many concurrent autosave forms or a particularly large model, but
// it should be fine with typical usage.
// interval: object -- Interval spec. Default: {poll: 250, save: 5000}
// form: object|function -- FormController or its getter
// });
// autosave.start();
// $scope.$on('$destroy', autosave.stop);
// Note: if the save operation itself
angular.module('crmAutosave').service('CrmAutosaveCtrl', function($interval, $timeout, $q) {
function CrmAutosaveCtrl(options) {
var intervals = angular.extend({poll: 250, save: 5000}, options.interval);
var jobs = {poll: null, save: null}; // job handles used ot cancel/reschedule timeouts/intervals
var lastSeenModel = null;
var saving = false;
// Determine if model has changed; (re)schedule the save.
// This is a bit expensive and doesn't need to be continuous, so we use polling instead of watches.
function checkChanges() {
if (saving) {
return;
}
var currentModel = _.isFunction(options.model) ? options.model() : options.model;
if (!angular.equals(currentModel, lastSeenModel)) {
lastSeenModel = angular.copy(currentModel);
if (jobs.save) {
$timeout.cancel(jobs.save);
}
jobs.save = $timeout(doAutosave, intervals.save);
}
}
function doAutosave() {
jobs.save = null;
if (saving) {
return;
}
var form = _.isFunction(options.form) ? options.form() : options.form;
if (options.saveIf) {
if (!options.saveIf()) {
return;
}
}
else if (form && form.$invalid) {
return;
}
saving = true;
lastSeenModel = angular.copy(_.isFunction(options.model) ? options.model() : options.model);
// Set to pristine before saving -- not after saving.
// If an eager user continues editing concurrent with the
// save process, then the form should become dirty again.
if (form) {
form.$setPristine();
}
var res = options.save();
if (res && res.then) {
res.then(
function() {
saving = false;
},
function() {
saving = false;
if (form) {
form.$setDirty();
}
}
);
}
else {
saving = false;
}
}
var self = this;
this.start = function() {
if (!jobs.poll) {
lastSeenModel = angular.copy(_.isFunction(options.model) ? options.model() : options.model);
jobs.poll = $interval(checkChanges, intervals.poll);
}
};
this.stop = function() {
if (jobs.poll) {
$interval.cancel(jobs.poll);
jobs.poll = null;
}
if (jobs.save) {
$timeout.cancel(jobs.save);
jobs.save = null;
}
};
this.suspend = function(p) {
self.stop();
return p.finally(self.start);
};
}
return CrmAutosaveCtrl;
});
})(angular, CRM.$, CRM._);
|