1(function(window){ 2 var topWindow = BX.PageObject.getRootWindow(); 3if (BX.CAutoSave && topWindow.BX.CAutoSave) return; 4/******************************* AUTOSAVE *********************************/ 5 6BX.CAutoSave = function(params) 7{ 8 this.FORM_NAME = params.form; 9 this.FORM_MARKER = params.form_marker; 10 this.FORM_ID = params.form_id; 11 12 this.PERIOD = params.period || [4001, 20990]; 13 14 this.RESTORE_DATA = null; 15 this.TIMERS = [null, null]; 16 17 this.bInited = false; 18 this.bRestoreInProgress = false; 19 20 this.DISABLE_STANDARD_NOTIFY = params.DISABLE_STANDARD_NOTIFY; 21 this.NOTIFY_CONTEXT = null; 22 23 BX.ready(BX.defer(this.Prepare, this)); 24 BX.garbage(BX.delegate(this.Clear, this)); 25 26 if ( 27 BX.type.isNotEmptyString(this.FORM_MARKER) 28 && BX(this.FORM_MARKER) 29 ) 30 { 31 var formMarker = BX(this.FORM_MARKER); 32 if ( 33 BX(formMarker.form) 34 && BX.type.isNotEmptyString(formMarker.form.name) 35 ) 36 { 37 BX.addCustomEvent(topWindow, 'onExtAutoSaveReset_' + formMarker.form.name, BX.proxy(this.Reset, this)); 38 } 39 } 40}; 41 42BX.CAutoSave.prototype.Prepare = function() 43{ 44 var i; 45 46 if (this.FORM_NAME && BX.type.isString(this.FORM_NAME)) 47 this.FORM = document.forms[this.FORM_NAME]; 48 else if (this.FORM_MARKER && BX.type.isString(this.FORM_MARKER)) 49 this.FORM = (BX(this.FORM_MARKER)||{form:null}).form; 50 51 if (!BX.type.isDomNode(this.FORM)) 52 return; 53 54 this.FORM.BXAUTOSAVE = this; 55 BX.bind(this.FORM, 'submit', BX.proxy(this.ClearTimers, this)); 56 57 for (i=0; i<this.FORM.elements.length; i++) 58 { 59 this.RegisterInput(this.FORM.elements[i]); 60 } 61 62 setTimeout(BX.delegate(this._PrepareAfter, this), 10); 63}; 64 65BX.CAutoSave.prototype.RegisterInput = function(inp) 66{ 67 if (BX.type.isString(inp)) 68 { 69 setTimeout(BX.delegate(function(){this.RegisterInput(this.FORM[inp] || BX(inp))}, this), 10); 70 } 71 else if (BX.type.isDomNode(inp)) 72 { 73 if ( 74 inp.type != 'button' 75 && inp.type != 'submit' 76 && inp.type != 'reset' 77 && inp.type != 'image' 78 && inp.type != 'hidden' 79 ) 80 { 81 BX.bind(inp, 'change', BX.proxy(this.Init, this)); 82 83 if (inp.type == 'text' || inp.type == 'textarea') 84 { 85 BX.bind(inp, 'keyup', BX.proxy(this.Init, this)); 86 } 87 88 if (inp.type == 'checkbox' || inp.type == 'radio') 89 { 90 BX.bind(inp, 'click', BX.proxy(this.Init, this)); 91 } 92 } 93 } 94}; 95 96BX.CAutoSave.prototype.UnRegisterInput = function(inp) 97{ 98 if (BX.type.isString(inp)) 99 inp = this.FORM[inp] || BX(inp); 100 if (BX.type.isDomNode(inp)) 101 { 102 BX.unbind(inp, 'change', BX.proxy(this.Init, this)); 103 BX.unbind(inp, 'keyup', BX.proxy(this.Init, this)); 104 BX.unbind(inp, 'click', BX.proxy(this.Init, this)); 105 } 106}; 107 108BX.CAutoSave.prototype._PrepareAfter = function() 109{ 110 // we can set other "target events" here 111 BX.onCustomEvent(this.FORM, 'onAutoSavePrepare', [this, BX.proxy(this.Init, this)]); 112 113 if (this.RESTORE_DATA) 114 { 115 var id = this.FORM.name || Math.random(); 116 BX.removeCustomEvent('onExtAutoSaveRestoreClick_' + id, BX.proxy(this.Restore, this)); 117 BX.addCustomEvent('onExtAutoSaveRestoreClick_' + id, BX.proxy(this.Restore, this)); 118 119 var o = this._NotifyContext(); 120 if (o) 121 { 122 o.Notify( 123 BX.message('AUTOSAVE') + ' <a href="javascript:void(0)" onclick="BX.CAutoSave.Re
123store(\'' + BX.util.urlencode(id) + '\', this); return false;">' + BX.message('AUTOSAVE_R') + '</a>', 124 false, 125 true 126 ); 127 } 128 129 // may be useful sometimes 130 BX.onCustomEvent(this.FORM, 'onAutoSaveRestoreFound', [this, this.RESTORE_DATA]); 131 } 132}; 133 134BX.CAutoSave.prototype.Init = function() 135{ 136 // if (this.bRestoreInProgress) 137 // return; 138 139 if (this.TIMERS[0]) 140 { 141 clearTimeout(this.TIMERS[0]); 142 this.TIMERS[0] = null; 143 } 144 145 this.TIMERS[0] = setTimeout(BX.proxy(this.TimerHandler, this), this.PERIOD[0]); 146 147 if (!this.TIMERS[1]) 148 { 149 this.TIMERS[1] = setInterval(BX.proxy(this.Save, this), this.PERIOD[1]); 150 } 151 152 // may also be useful 153 BX.onCustomEvent(this.FORM, 'onAutoSaveInit', [this]); 154 155 return true; 156}; 157 158BX.CAutoSave.prototype.TimerHandler = function() 159{ 160 if (this.TIMERS[1]) 161 { 162 clearInterval(this.TIMERS[1]); 163 this.TIMERS[1] = null; 164 } 165 this.Save(); 166}; 167 168BX.CAutoSave.prototype.Save = function() 169{ 170 if (this.FORM && BX.isNodeInDom(this.FORM)) 171 { 172 var i, j, el, data = {autosave_id: this.FORM_ID, form_data: {}}; 173 174 for (i=0; i<this.FORM.elements.length; i++) 175 { 176 el = this.FORM.elements[i]; 177 178 if (el.name && el.name != 'sessid' && el.name != 'lang' && el.name != 'autosave_id') 179 { 180 var n = el.name, v = '', t = el.type.toLowerCase(); 181 182 switch (t) 183 { 184 case 'button': 185 case 'submit': 186 case 'reset': 187 case 'image': 188 case 'file': 189 case 'password': 190 break; 191 192 case 'radio': 193 case 'checkbox': 194 if (el.checked) 195 v = el.value || 'on'; 196 break; 197 198 case 'select-multiple': 199 n = n.substring(0, n.length-2); 200 v = []; 201 for (j=0;j<el.options.length;j++) 202 { 203 if (el.options[j].selected) 204 { 205 v.push(el.options[j].value); 206 } 207 } 208 break; 209 210 default: 211 v = el.value; 212 } 213 214 if (n.indexOf('[]') > 0) 215 { 216 n = _encodeName(n); 217 if (typeof(data.form_data[n]) == 'undefined') 218 data.form_data[n] = [v]; 219 else 220 data.form_data[n].push(v); 221 } 222 else 223 data.form_data[_encodeName(n)] = v; 224 } 225 } 226 227 // we can adjust form_data before autosaving 228 BX.onCustomEvent(this.FORM, 'onAutoSave', [this, data.form_data]); 229 BX.ajax.post( 230 '/bitrix/tools/autosave.php?bxsender=core_autosave&sessid=' + BX.bitrix_sessid(), data, BX.proxy(this._Save, this) 231 ); 232 } 233 else 234 { 235 this.Clear(); 236 } 237}; 238 239BX.CAutoSave.prototype.Reset = function() 240{ 241 if (this.FORM && BX.isNodeInDom(this.FORM)) 242 { 243 BX.ajax.post( 244 '/bitrix/tools/autosave.php?bxsender=core_autosave&action=reset&sessid=' + BX.bitrix_sessid(), {autosave_id: this.FORM_ID }, null 245 ); 246 } 247}; 248 249BX.CAutoSave.prototype._Save = function(data) 250{ 251 BX.onCustomEvent(this.FORM, 'onAutoSaveFinished', [this, data]); 252}; 253 254BX.CAutoSave.prototype.Restore = function(data, clicker) 255{ 256 if (data) 257 { 258 this.RESTORE_DATA = _decodeData(data); 259 } 260 else if (this.FORM && this.RESTORE_DATA) 261 { 262 // we can change restore data or make some unusual actions here 263 BX.onCustomEvent(this.FORM, 'onAutoSaveRestore', [this, this.RESTORE_DATA]); 264 265 this.bRestoreInProgress = true; 266 267 for (var i=0; i<this.FORM.elements.length; i++) 268 { 269 var el = this.FORM.elements[i]; 270 if (el && BX.type.isDomNode(el) && el.name) 271 { 272 var value = undefined, n = el.name; 273 274 if (el.type == 'select-multiple') 275 n = el.name.substring(0, el.name.length-2); 276 277 value = this.RESTORE_DATA[n]; 278 279 if (n.indexOf('[]') > 0 && BX.type.isArray(value)) 280 value = this.RESTORE_DATA[n].shift(); 281 282 if (el.type != 'checkbox' && typeof value == 'undefined') 283 continue; 284 285 var bChange = false; 286 287 switch(el.type) 288 { 289 case 'radio': 290 if (!el.checked && !!(value == el.value)) 291 { 292 bChange = true; 293 BX.fireEvent(el, 'click'); 294 } 295 break; 296 case 'checkbox': 297 if (el.checked != !!(value == el.value)) 298 { 299 bChange = true; 300 BX.fireEvent(el, 'click'); 301 } 302 break; 303 304 case 'select-one': 305 for (var j = 0; j < el.options.length; j++) 306 { 307 var q = el.options[j].selected; 308 el.options[j].selected = !!(value == el.options[j].value); 309 bChange |= el.options[j].selected != q; 310 } 311 312 break; 313 314 case 'select-multiple': 315 value = this.RESTORE_DATA[el.name.substring(0, el.name.length-2)]; 316 for (j = 0; j < el.options.length; j++) 317 { 318 q = el.options[j].selected; 319 el.options[j].selected = !!(BX.type.isArray(value) && BX.util.in_array(el.options[j].value, value)); 320 bChange |= el.options[j].selected != q; 321 } 322 break; 323 324 case 'file': 325 case 'button': 326 case 'image': 327 case 'submit': 328 case 'reset': 329 case 'password': 330 break; 331 332 default: 333 bChange = value != el.value; 334 el.value = value; 335 } 336 337 if (bChange) 338 BX.fireEvent(el, 'change'); 339 } 340 } 341 342 var o = this._NotifyContext(); 343 if (o) 344 o.hideNotify(clicker.parentNode.parentNode); 345 346 this.bRestoreInProgress = false;
347 348 BX.onCustomEvent(this.FORM, 'onAutoSaveRestoreFinished', [this, this.RESTORE_DATA]); 349 } 350}; 351 352BX.CAutoSave.prototype._NotifyContext = function() 353{ 354 var o = null; 355 356 if (!this.DISABLE_STANDARD_NOTIFY) 357 { 358 if (this.NOTIFY_CONTEXT) 359 o = this.NOTIFY_CONTEXT; 360 else if (BX.WindowManager && BX.WindowManager.Get()) 361 o = BX.WindowManager.Get(); 362 else if (BX.adminPanel) 363 o = BX.adminPanel; 364 else if (BX.admin && BX.admin.panel) 365 o = BX.admin.panel; 366 367 this.NOTIFY_CONTEXT = o; 368 } 369 370 return o; 371}; 372 373BX.CAutoSave.prototype.ClearTimers = function() 374{ 375 if (this.TIMERS) 376 { 377 clearTimeout(this.TIMERS[0]); 378 clearInterval(this.TIMERS[1]); 379 } 380}; 381 382BX.CAutoSave.prototype.Clear = function() 383{ 384 if (this.FORM) 385 { 386 this.FORM.BXAUTOSAVE = null; 387 388 for (var i=0; i<this.FORM.elements.length; i++) 389 { 390 this.UnRegisterInput(this.FORM.elements[i]); 391 } 392 } 393 394 this.ClearTimers(); 395 396 // we should unset any additional "target events" here 397 BX.onCustomEvent(this.FORM, 'onAutoSaveClear', [this]); 398 399 this.FORM = null; 400 this.TIMERS = null; 401}; 402
403BX.CAutoSave.Restore = function(id, el) 404{ 405 BX.onCustomEvent('onExtAutoSaveRestoreClick_' + id, [null, el]); 406}; 407 408function _encodeName(n) 409{ 410 var q; 411 while (q = /[^a-zA-Z0-9_\-]/.exec(n)) 412 { 413 n = n.replace(q[0], 'X' + BX.util.str_pad_left(q[0].charCodeAt(0).toString(), 6, '0') + 'X'); 414 } 415 return n; 416} 417 418function _decodeName(n) 419{ 420 var q; 421 while (q = /X[\d]{6}X/.exec(n)) 422 { 423 n = n.replace(q[0], String.fromCharCode(parseInt(q[0].replace(/(^X[0]*)|(X$)/g, '')))) 424 } 425 return n; 426} 427 428function _decodeData(data) 429{ 430 var d = {}; 431 for (var i in data) 432 { 433 d[_decodeName(i)] = data[i]; 434 } 435 return d; 436} 437 topWindow.BX.CAutoSave = BX.CAutoSave; 438})(window); 439 440
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.