1/*-----------------------------------------------------------------------------------------------------------------------\dlo/ 2Date: Sep 10th, 2010 3Revised: March 4, 2014 4Name: CHO Prototype Utility. 5Description: Base script library to use in CHOE3 6Author: Dmitry Lopyrev 7Note: Requires Prototype JS library (v.1.7c - modified) 8 9---------------------------------------------------------------------------------------------------------------------------*/ 10 11//------------------------------------------------------------------------------------------------------------------\dlo/ 12//Extend object prototypes 13//---------------------------------------------------------------------------------------------------------------------- 14Object.extend(Object, { 15 guid: function () { return new Date().getTime().toPaddedString(10, 16).toUpperCase(); }, 16 wrap: Object.extend.wrap(function (proceed, destination, source, properties) { 17 if (!Object.isArray(properties) || !properties.length) 18 return proceed(destination, source); 19 properties.each(function (it) { 20 !Object.isUndefined(source[it]) && (destination[it] = source[it]); 21 }); 22 return destination; 23 }), 24 get: function (o, property, def) { 25 if (!o) return def; 26 var properties = (property || '').split('.'); 27 property = properties.first(); 28 properties = properties.slice(1); 29 o = o[property]; 30 if (!Object.isUndefined(o) && properties.length) 31 return arguments.callee(o, properties.join('.')); 32 return o || def; 33 }, 34 getValue: function (o, property, def) { 35 o = Object.get(o, property); 36 if (!o) 37 return def; 38 if (Object.isFunction(o.getValue)) 39 return o.getValue() || def; 40 return o.value || def; 41 }, 42 cast: function (o) { 43 for (it in o) { 44 if (Object.isString(o[it])) 45 o[it] = o[it].cast(true); 46 } 47 return o; 48 }, 49 //Temporary 50 isBoolean: function (o) { 51 return typeof o == "boolean"; 52 } 53 54}); 55 56//---------------------------------------------------------------------------------------------------------------------- 57//Extend Window prototype object Doesn't work on Android mobile stock browser 58//---------------------------------------------------------------------------------------------------------------------- 59/* 60Object.extend(Window.prototype, { 61 Wait: function (n) { 62 var d = new Date().add('ms', String(n).toNumber() * 1000); 63 while (new Date() <= d) {} 64 } 65}); 66*/ 67Wait = function (n) { 68 var d = new Date().add('ms', String(n).toNumber() * 1000); 69 while (new Date() <= d) { } 70}; 71 72 73//---------------------------------------------------------------------------------------------------------------------- 74//Extend Number prototype object 75//---------------------------------------------------------------------------------------------------------------------- 76Object.extend(Number.prototype, { 77 toString: Number.prototype.toString.wrap(function (proceed, f) { 78 try { 79 var number = this; 80 if (Object.isString(f) && /(G|C|N|F|P)/g.test(f)) { 81 return isNaN(number) ? "" : String(f || 'G').replace(/(G|C|N|F|P)/g, 82 function ($1) { 83 switch ($1) { 84 case 'C': 85 return number.toFixed(2); 86 case 'N': 87 return number.toFixed(0); 88 case 'F': 89 return number.toFixed(2); 90 case 'P': 91 return number.toString() + "%"; 92 } 93 return proceed(); 94 } 95 ); 96 } else { 97 98 return proceed.apply(this, $A(arguments).slice(1)); 99 } 100 } catch (e) { 101 } 102 103 }), 104 toOrdinal: function () { 105 var s = ["th", "st", "nd", "rd"], v = this % 100; 106 return this + (s[(v - 20) % 10] || s[v] || s[0]); 107 }, 108 toNumber: function() { 109 return this; 110 } 111}); 112 113Object.extend(Array.prototype, { 114 removeFirst: function (n) { 115 n = Math.abs(String(n).toNumber() || 1); 116 if (this.length < n) 117 return this; 118 return this.splice(this.length - n, n); 119 }, 120 removeLast: function (n) { 121 while (this.length && n > 0) 122 this.pop(), n--; 123 return this; 124 }, 125 exclude: function(a) { 126 if (Object.isArray(a)) { 127 return this.without.apply(this, $A(a)); 128 } 129 return this.without.call(this, arguments); 130 } 131 132}); 133 134 135 136//---------------------------------------------------------------------------------------------------------------------- 137//Extend object prototypes 138//---------------------------------------------------------------------------------------------------------------------- 139Object.extend(String.prototype, { 140 toNumber: function (def, radix) { 141 var val = String(this).replace(/([^\-\d\. ])/g, "") || (Object.isNumber(def) ? def.toString() : '0'); 142 if (val.indexOf('.') == -1) 143 return parseInt(val, radix || 10); 144 else 145 return parseFloat(val); 146 }, 147 cast: function (b) { 148 if (b) { 149 if (/^[-]?[\d ]+[\.]?[\d ]*$/.test(this)) 150 return this.toNumber(); 151 if (/^(true|false)$/i.test(this)) 152 return this.toLowerCase() == 'true'; 153 } 154 return this.toString(); 155 }, 156 include: String.prototype.include.wrap(function (proceed, pattern, ignorecase) { 157 if (ignorecase === true) 158 return this.toLowerCase().indexOf((pattern || '').toLowerCase()) > -1; 159 return proceed(pattern); 160 161 }), 162 addQueryParam: function(o) { 163 if (!o) 164 return this; 165 var p = Object.extend(this.toQueryParams(), Object.isString(o) ? o.toQueryParams(): o); 166 return this.replace(/[\?#].*/gi, '') +"?" + Object.toQueryString(p); 167 168 } 169}); 170//------------------------------------------------------------------------------------------------------------------\dlo/ 171// Extend Date prototype object 172//---------------------------------------------------------------------------------------------------------------------- 173Object.extend(Date.prototype, { 174 toString: Date.prototype.toString.wrap(function (proceed, f) { 175 if (Object.isUndefined(f)) 176 return proceed(); 177 var d = this; 178 return isNaN(this) ? "" : String(f).replace(/(('.+')|yyyy|yy|MMMM|MMM|MM|w|dddd|dd|ds|d|hh|h|mm|m|ss|tt|p)/g, 179 function ($1) { 180 var h; 181 switch ($1) { 182 case 'yy': return (d.getFullYear() % 100).toPaddedString(2); 183 case 'yyyy': return d.getFullYear().toPaddedString(4); 184 case 'MMMM': 185 case 'MMM': return (['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][d.getMonth()]).substr(0, $1.length == 3 ? 3 : 20); 186 case 'MM': return (d.getMonth() + 1).toPaddedString(2); 187 case 'p': return ['Night', 'Morning', 'Afternoon', 'Evening'][parseInt(d.getHours() / 6)]; 188 case 'dddd': 189 case 'w': return ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][d.getDay()]; 190 case 'ds': return d.getDate().toOrdinal(); 191 case 'dd': return d.getDate().toPaddedString(2); 192 case 'd': return d.getDate().toString(); 193 case 'hh': return d.getHours().toPaddedString(2); //hour (01-24) 194 case 'h': return ((h = d.getHours() % 12) ? h
194: 12).toString(); //hour (01-12) 195 case 'mm': return d.getMinutes().toPaddedString(2); 196 case 'm': return d.getMinutes().toString(); 197 case 'ss': return d.getSeconds().toPaddedString(2); 198 case 'tt': return d.getHours() < 12 ? 'am' : 'pm'; 199 default: return $1.replace(/'/g, ""); 200 } 201 } 202 ); 203 }), 204 CustomFormat: function (f) { 205 return this.toString(f); 206 }, 207 add: function (interval, value) { 208 var d = new Date(this.getTime()), b = false; 209 if (!interval || value === 0) return d; 210 if (typeof (value) == 'string') { 211 b = true, value = parseInt('0' + value, 10); 212 } 213 switch (interval.toLowerCase()) { 214 case 'ms': 215 d.setMilliseconds((b ? 0 : this.getMilliseconds()) + value); break; 216 case 'sec': 217 d.setSeconds((b ? 0 : this.getSeconds()) + value); break; 218 case 'min': 219 d.setMinutes((b ? 0 : this.getMinutes()) + value); break; 220 case 'h': 221 d.setHours((b ? 0 : this.getHours()) + value); break; 222 case 'd': 223 d.setDate((b ? 0 : this.getDate()) + value); break; 224 case 'm': 225 d.setMonth((b ? 0 : this.getMonth()) + value); break; 226 case 'y': 227 d.setFullYear((b ? 0 : this.getFullYear()) + value); break; 228 } 229 return d; 230 }, 231 toObject: function (f) { 232 var d = this, o = { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0, ms: 0 }; 233 String(f || 'YMDhmsl').replace(/(Y|M|D|h|m|s|l)/g, 234 function ($1) { 235 switch ($1) { 236 case 'Y': o.year = d.getFullYear(); break; 237 case 'M': o.month = d.getMonth(); break; 238 case 'D': o.day = d.getDate(); break; 239 case 'h': o.hour = d.getHours(); break; 240 case 'm': o.minute = d.getMinutes(); break; 241 case 's': o.second = d.getSeconds(); break; 242 case 'l': o.ms = d.getMilliseconds(); break; 243 } 244 } 245 ); 246 return o; 247 }, 248 ticks: function () { 249 function monthToDays(year, month) { 250 var add = 0; 251 var result = 0; 252 if ((year % 4 == 0) && ((year % 100 != 0) || ((year % 100 == 0) && (year % 400 == 0)))) add++; 253 254 switch (month) { 255 case 0: return 0; 256 case 1: result = 31; break; 257 case 2: result = 59; break; 258 case 3: result = 90; break; 259 case 4: result = 120; break; 260 case 5: result = 151; break; 261 case 6: result = 181; break; 262 case 7: result = 212; break; 263 case 8: result = 243; break; 264 case 9: result = 273; break; 265 case 10: result = 304; break; 266 case 11: result = 334; break; 267 case 12: result = 365; break; 268 } 269 if (month > 1) result += add; 270 return result; 271 }; 272 function timeToTicks(hour, minute, second) { 273 return (((hour * 3600) + minute * 60) + second) * 10000000; 274 }; 275 function dateToTicks(year, month, day) { 276 //number of days in the the years 277 var a = parseInt((year - 1) * 365); 278 //count the leapyear days 279 //A year is a leap year if it can be divided by 4, but can't be divided by 100, except of case when it can be divided by 400. 280 var b = parseInt((year - 1) / 4); 281 var c = parseInt((year - 1) / 100); 282 var d = parseInt((a + b - c)); 283 var e = parseInt((year - 1) / 400); 284 var f = parseInt(d + e); 285 //number of days for complete months. 286 var monthDays = monthToDays(year, month - 1); 287 //add in number of completed days in the month 288 var g = parseInt((f + monthDays) + day - 1); 289 return g * 864000000000; 290 }; 291 var o = this.toObject(); 292 return dateToTicks(o.year, o.month, o.day) + timeToTicks(o.hour, o.minute, o.second) + (o.ms * 10000); 293 }, 294 round: function (n) { 295 var min = this.getHours() * 60 + this.getMinutes(); 296 min = Math.floor(min / Math.abs(n) + 0.5) * Math.abs(n); 297 return this.setTime().add('min', min); 298 }, 299 clone: function () { 300 return new Date(this.getTime()); 301 }, 302 diff: function (d, f) { 303 if (d instanceof Date) { 304 switch (String(f)) { 305 case 'y': 306 case 'Y': return this.getFullYear() - d.getFullYear(); 307 case 'M': return (this.getMonth() + 12 * this.getFullYear()) - (d.getMonth() + 12 * d.getFullYear()); 308 case 'd': return parseInt((this.getTime() - d.getTime()) / (24 * 3600 * 1000)); 309 case 'd+': return parseInt((this.getTime() - d.getTime()) / (24 * 3600 * 1000)) + (parseInt((this.getTime() - d.getTime()) % (24 * 3600 * 1000)) >= 12 ? 1 : 0); 310 case 'h': return parseInt((this.getTime() - d.getTime()) / (3600 * 1000)); 311 case 'h+': return parseInt((this.getTime() - d.getTime()) / (3600 * 1000)) + (parseInt((this.getTime() - d.getTime()) % (3600 * 1000)) >= 30 ? 1 : 0); 312 case 'm': return parseInt((this.getTime() - d.getTime()) / (60 * 1000)); 313 case 'm+': return parseInt((this.getTime() - d.getTime()) / (60 * 1000)) + (parseInt((this.getTime() - d.getTime()) % (60 * 1000)) >= 30 ? 1 : 0); 314 case 's': return parseInt((this.getTime() - d.getTime()) / 1000); 315 default: return this.getTime() - d.getTime(); 316 } 317 } else { 318 return 0; 319 } 320 321 }, 322 weekend: function () { 323 return this.getDay() == 0 || this.getDay() == 6; 324 }, 325 setTime: Date.prototype.setTime.wrap(function (proceed, time) { 326 if (Object.isNumber(time)) 327 return proceed(time); 328 time = String(time || '').replace(/(am|pm)/i, function($1) { return ' '+$1}); 329 330 var d = new Date(this.CustomFormat("yyyy/MM/dd ") + time); 331 return d; 332 }) 333}); 334 335Object.extend(Function.prototype, { 336 argumentValues: function (n) { 337 var names = this.argumentNames().slice(n); 338 var o = {}; 339 for (var i = 0; i < this.arguments.length; i++) { 340 if (names[i]) 341 o[names[i]] = this.arguments[i]; 342 else if (Object.isString(this.arguments[i]) || Object.isDate(this.arguments[i]) || Object.isNumber(this.arguments[i]) || Object.isArray(this.arguments[i]) || Object.isBoolean(this.arguments[i])) { 343 !Object.isArray(o.parameters) && (o.parameters = []); 344 o.parameters.push(this.arguments[i]); 345 } else { 346 Object.extend(o, this.arguments[i]); 347 } 348 } 349 return o; 350 } 351}); 352 353//---------------------------------------------------------------------------------------------------------------------- 354//- Prototype Library Extesions 355//---------------------------------------------------------------------------------------------------------------------- 356//Added new methods to DOM elements 357Element.addMethods({ 358 isDescendantOf: function (element, host) { 359 if (!Object.isElement($p(host))) 360 return false; 361 host = $p(host); 362 var isDecendant = false; 363 //Check if current element is desendant of popup container 364 var b = $p(element).descendantOf(host); 365 while (element.parentNode) { 366 element = element.parentNode; 367 isDecendant |= element === host.up(); 368 } 369 //close popup if isn't decendant of host or popup selector 370 return Boolean(isDecendant); 371 }, 372 noClick: function (element) { 373 element = $p(element); 374 element.$click = element.onclick ? element.onclick : Prototype.emptyFunction; 375 element.onclick = null; 376 element.on("click", function (e) { e.stop(); }.bindAsEventListener()); 377 element.tagName === 'A' && (element.writeAttribute('href', (element.readAttribute('disabled') ? "" : "javascript:void(0);"))); 378 return element; 379 }, 380 getInnerText: function (element) { 381 return element.innerText || element.textContent; 382 }, 383 setInnerText: function (element, txt) { 384 if (element.innerText) element.innerText = txt; 385 else if (element.textContent) element.innerHTML = txt; 386 }, 387 //Create and returns an object based on item attributes started with "data-"; 388 getActions: function (element, options, def) { 389 def = def || {}, options = options || {}; 390 /* 391 | possible property for options : 392 | camelize : convert object's property name to Camelize string (a first letter is capital) 393 | lower : use lower case in property name 394 | cast: convert parameter value to type (based on content), overwize value will always be a string 395 */ 396 return $A(element.attributes).inject(def, function (o, attr) { 397 if (attr.name.startsWith('data-')) { 398 var ns = attr.name.replace('data-', '').split('-'); 399 var result = o; 400 for (var i = 0, it; it = ns[i++];) { 401 if (options.camelize) 402 it = ('-' + it).camelize(); 403 if ((options.capitalize)) 404 it = it.capitalize(); 405 if ((options.lower)) 406 it = it.toLowerCase(); 407 !result[it] && (result[it] = {}); 408 if (i == ns.length) 409 result[it] = attr.value.cast(options.cast); 410 else 411 result = result[it]; 412 }; 413 } 414 return o; 415 }); 416 }, 417 getFields: function (element, opt) { 418 //returns input elements separated by group name (and only for group specified in "names" parameter) 419 if (!Object.isElement(element)) 420 return null; 421 opt = opt || {}; 422 var inputs = Object.isArray(opt) ? opt : Form.getInputs(element); 423 if (Object.isString(opt.type)) { //'text|textarea|hidden|checkbox|radio' 424 opt.type = new RegExp(opt.type, 'i'); 425 } 426 if (!Object.isArray(inputs)) 427 return null;
428 var data = inputs.inject({}, function (o, it) { 429 if (!Object.isElement(it)) 430 return o; 431 if (opt.type && !opt.type.test(it.type)) 432 return o; 433 434 var data = Object.extend({ field: it.id.split('_').last() }, it.getActions({lower:true})); 435 436 if (Object.isArray(o[data.field])) 437 o[data.field].push(it); 438 else 439 o[data.field] = it; 440 return o; 441 }); 442 return data; 443 444 }, 445 simulate: function (element, eventName, memo) { 446 447 var eventMatchers = { 448 'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll|change)$/, 449 'MouseEvents': /^(?:click|mouse(?:down|up|over|move|out))$/ 450 }; 451 var options = { 452 pointerX: 0, 453 pointerY: 0, 454 button: 0, 455 ctrlKey: false, 456 altKey: false, 457 shiftKey: false, 458 metaKey: false, 459 bubbles: true, 460 cancelable: true 461 }; 462 463 options = Object.extend(options, arguments[2] || {}); 464 var oEvent, eventType = null; 465 466 element = $p(element); 467 468 for (var name in eventMatchers) { 469 if (eventMatchers[name].test(eventName)) { 470 eventType = name; 471 break; 472 } 473 } 474 475 if (!eventType) 476 return undefined; 477 478 if (document.createEvent) { 479 oEvent = document.createEvent(eventType); 480 if (eventType == 'HTMLEvents') { 481 oEvent.initEvent(eventName, options.bubbles, options.cancelable); 482 } else { 483 oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView, 484 options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY, 485 options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element); 486 } 487 oEvent.memo = memo; 488 element.dispatchEvent(oEvent); 489 } else { 490 options.clientX = options.pointerX; 491 options.clientY = options.pointerY; 492 oEvent = Object.extend(document.createEventObject(), options); 493 oEvent.memo = memo; 494 element.fireEvent('on' + eventName, oEvent); 495 } 496 return element; 497 } 498}); 499 500//---------------------------------------------------------------------------------------------------------------------- 501//Added new Form methods 502//---------------------------------------------------------------------------------------------------------------------- 503Form.Methods.LoadFields = function (form, container, isfullname) { 504 //returns new object for each found input field in form element : 505 //Properties :: 506 // field - current input field 507 // value - current input field's value (can be treat as default value ) 508 // IsChanged(method) - to return true if input field value has changed 509 // Note :: the name of this property is based on a field name (Input Control ID on server side) 510 // Optional :: if container passed in it will be updated with new properties 511 if (form = $p(form), !form) 512 return; 513 514 var elements = Form.getElements(form); 515 elements = elements.length ? elements : [form]; 516 517 var o = elements.inject({}, function (o, inp) { 518 if (inp.name) { 519 var name = Object.isString(container) ? container : (isfullname ? inp.name : inp.name.split('$').last()); 520 var data = { 521 IsChanged: function () { return Boolean(this.field.getValue() !== this.value); }, 522 AcceptChanges: function () { return this.value = this.field.getValue(); }, 523 Values: function (flag) { 524 return $H(this).keys().inject({}, function (values, key) { 525 if (this[key].field && Object.isFunction(this[key].field.getValue)) 526 if ((flag === true && this[key].IsChanged()) || flag == undefined) 527 values[key] = this[key].field.getValue(); 528 return values; 529 }, this); 530 } 531 }; 532 if (inp.type == 'radio') { 533 Object.extend(data, { field: $p(inp.id), value: inp.getValue(), options: form.select("[name='" + inp.name + "']") }); 534 } else if (inp.type == 'checkbox') { 535 //Do not use Checkbox list: user 536 Object.extend(data, { field: inp, value: inp.getValue() }); 537 } else { 538 Object.extend(data, { field: inp, value: inp.getValue() }); 539 } 540 541 if (Object.isArray(o[name])) 542 o[name].push(data); 543 else if (o[name]) { 544 if (inp.type != 'radio') 545 o[name] = [o[name], data]; 546 } else 547 o[name] = data; 548 }; 549 return o; 550 }, this); 551 if (Object.isString(container)) { 552 return o[container]; 553 } 554 container && (Object.extend(container, o)); 555 return o; 556};
557 558//Add new methods to all Prototypes 559Element.addMethods(); 560 561 562/** 563* Ajax.Request.abort 564* extend the prototype.js Ajax.Request object so that it supports an abort method 565*/ 566Ajax.Request.prototype.abort = function () { 567 // prevent and state change callbacks from being issued 568 this.transport.onreadystatechange = Prototype.emptyFunction; 569 // abort the XHR 570 this.transport.abort(); 571 // update the request counter 572 Ajax.Responders.dispatch('onComplete', this); 573 574 //Ajax.activeRequestCount--; 575 //if (Ajax.activeRequestCount < 0) { 576 // Ajax.activeRequestCount = 0; 577 //} 578}; 579 580 581/*- End of Extensions ---------------------------------------------------------------------------------------------------------*/ 582 583var Utility = { 584 Global : {bubbletip:true}, 585 UI: {}, //UI classes holder 586 AddLibrary: function (w) { 587 if (w && !w.Prototype) { 588 var newScr = w.document.createElement("SCRIPT"); 589 newScr.src = ($$('script').find(function (s) { return /prototype.js/i.test(s.src); }) || {}).src; 590 if (newScr.src) { 591 newScr.type = "text/javascript"; 592 w.document.getElementsByTagName("head")[0].appendChild(newScr); 593 } 594 } 595 596 }, 597 AddStyle: function () { 598 var b; 599 var links = $$('link').inject([], function (list, it) { 600 if (/App_Themes/i.test(Object.isElement(it) && it['href'])) { 601 list.push(it.href); 602 if (/preloader.css/i.test(it.href)) 603 b = true; 604 } 605 return list; 606 }); 607 if (!links.length || b) 608 return; 609 var link = document.createElement("LINK"); 610 link.type = 'text/css'; 611 link.rel = 'stylesheet'; 612 link.href = links[0].substr(0, links[0].toLowerCase().indexOf("app_themes")) + 'app_themes/preloader.css'; 613 document.getElementsByTagName("head")[0].appendChild(link); 614 615 } 616}; 617 618 619//---------------------------------------------------------------------------------------------------------------------- 620//[serfi] $hack-hack$ helper function shaves of HTML from an AJAX invocation supposed to return application/JSON content 621//---------------------------------------------------------------------------------------------------------------------- 622function CleanupHtmlJSON(text) { 623 var returnObject = null; 624 var lines = text.split('\r\n'); 625 lineCount = lines.length; 626 strJSONSerialized = lines[lineCount - 1]; 627 //perhaps the library does this cleansing already but too cryptic for me at this point 628 sanitizedJSON = (strJSONSerialized.replace('"d":"{', '"d":{')).replace('"}"}', '"}}'); 629 sanitizedJSON = sanitizedJSON.replace(/\\"/g, '"'); 630 sanitizedJSON = sanitizedJSON.replace(/\\\\/g, '\\'); 631 try { 632 returnObject = sanitizedJSON.evalJSON(); 633 } catch (e) { 634 returnObject = '{ "Title": "Application & Validation Error", "Message": "Unspecified Error." }'.evalJSON(); 635 } 636 return returnObject.d; 637} 638 639 640//---------------------------------------------------------------------------------------------------------------------- 641//Class to create and handle Web Method Requests 642//---------------------------------------------------------------------------------------------------------------------- 643Utility.WebMethodRequest = new Class.create({ 644 initialize: function (Caller, options) { 645 this.method = ''; 646 this.parameters = {}; 647 //update options 648 Object.extend(this, options || {}); 649 //current object to hold this WebRequestMethod instance 650 this.Caller = Caller; 651 if (this.Caller.ShowError) 652 this.ShowError = this.Caller.ShowError; 653 if (this.Caller.CompleteRequest) 654 this.CompleteRequest = this.Caller.CompleteRequest; 655 }, 656 //Show Error. Executes when WebMethod returns an error 657 ShowError: function (request) { 658 659 this.StopProgress(); 660 var err = { message: 'Error ', title: request.statusText || 'Error', cssButton: 'simple', callBack: this.Caller.onErrorC
660omplete }; 661 if (request) { 662 if (request.responseJSON) { 663 err = Object.extend(err, request.responseJSON); 664 //ignore uppercase for properties 665 err.message = err.Message || err.message; 666 err.title = err.Title || err.title; 667 // } else if (request.status == 500) { 668 // //the parsing failed: $hack-hack$ - strip off the HTML and reparse: only the last line is a valid JSON serialization 669 // var messageJSON = CleanupHtmlJSON(request.responseText); 670 // err = Object.extend(err, messageJSON); 671 // err.message = err.Message || err.message; 672 // err.title = err.Title || err.title; 673 } else if (typeof request.statusText != 'undefined') { 674 //current response text probably is YSofD, so we need to parse if 675 var ysof = /<!--\s*\[(.*?)]:(\s*.*\s(.*[\n\r]*)*?)\s*(at(.*[\n\r]*)*)-->/; 676 var matches = request.responseText.match(/<!--\s*\[(.*?)]:(\s*.*\s(.*[\n\r]*)*?)\s*(at(.*[\n\r]*)*)-->/); 677 if (Object.isArray(matches)) { 678 err.title = matches[1]; 679 err.message = matches[2]; 680 } 681 682 else { 683 //show fill body of error page 684 err.message = request.responseText; 685 err.isHTML = true; 686 } 687 } 688 else if (request.message) { 689 err.message = request.message; 690 err.title; 691 } 692 if (Object.isFunction(this.Caller.onError)) { 693 err = this.Caller.onError.call(this.Caller, err, request); 694 }; 695 } 696 if (err) 697 //Show error message 698 $alert(err); 699 }, 700 //Called when request is completed 701 CompleteRequest: function (response) { 702 document.title = this.Title; 703 var isexecuted = false; // true - don't execute onComplete! 704 705 //removes current message if exists 706 this.StopProgress(); 707 708 if (this.ajaxRequest.success()) { 709 try { 710 711 if (response && response.responseJSON) { 712 713 //if new update properties passed in apply the properties to current object instance 714 if (response.responseJSON.properties) 715 Object.extend(this.Caller, response.responseJSON.properties); 716 717 //Check Local method. 718 var callbackfunction = response.responseJSON.callback || response.responseJSON.method; 719 var caller; 720 if (Object.isFunction(this.__callback)) { 721 isexecuted = true; 722 if (Object.isArray(response.responseJSON.methodparameters)) 723 this.__callback.apply(caller, response.responseJSON.methodparameters); 724 else 725 this.__callback.call(caller, (response.responseJSON.methodparameters || response.responseJSON), response); 726 delete this.__callback; 727 } 728 //if result has a method property and current object has this method, so invoke that method with patameters (optional property) 729 //NOTE. the callback method can contains full method description like 'host.method'. 730 //So, in that case we have to change the caller context 731 else if (Object.isFunction(func = Object.get(this.Caller, callbackfunction))) { 732 isexecuted = true; 733 caller = Object.get(this.Caller, callbackfunction.split('.').removeLast(1).join('.')) || this.Caller; 734 if (Object.isArray(response.responseJSON.methodparameters)) 735 func.apply(caller, response.responseJSON.methodparameters); 736 else 737 func.call(caller, (response.responseJSON.methodparameters || response.responseJSON), response); 738 739 //Check Global method. 740 //if result has a method property and current object has this method, so invoke that method with patameters (optional property) 741 } else if (Object.isFunction(func = Object.get(window, callbackfunction))) { 742 isexecuted = true; 743 caller = Object.get(window, callbackfunction.split('.').removeLast(1).join('.')) || window; 744 if (Object.isArray(response.responseJSON.methodparameters)) 745 func.apply(caller, response.responseJSON.methodparameters.concat([response])); 746 else 747 func.call(caller, (Object.isUndefined(response.responseJSON.methodparameters) ? response.responseJSON : response.responseJSON.methodparameters), response); 748 } 749 } 750 //call complete method if exists and not executed yet 751 if (!isexecuted) {
752 if (response.responseJSON == null || Object.toJSON(response.responseJSON) == "{}") 753 return; 754 if (Object.isFunction(this.Caller.Complete)) { 755 if (Object.isArray(response.responseJSON.methodparameters)) 756 this.Caller.Complete.apply(this.Caller, response.responseJSON.methodparameters); 757 else 758 this.Caller.Complete.call(this.Caller, (response.responseJSON.methodparameters || response.responseJSON), response); 759 } else if (Object.isString(response.responseJSON)) 760 response.responseJSON.evalScripts(); 761 else 762 throw new Error("Callback function "+(callbackfunction ? "(" + callbackfunction + ")" : "")+" cannot be executed."); 763 } 764 } catch (err) { 765 this.ShowError(err); 766 } 767 } 768 769 //removes current request 770 //this.ajaxRequest && (delete this.ajaxRequest); 771 }, 772 773 //Show a progres message if message object is set 774 //NOTE:: the message object should be an Array with two items: 1- signature of mesage type, 2 - parameters (must have property 'host' set) 775 StartProgress: function (msg) { 776 this.$progressmessage = this.$progressmessage || ( msg ? $progress(msg) : this.Caller.progressmessage); 777 if (this.$progressmessage instanceof Utility.Message) { 778 this.$progressmessage.Show(); 779 } 780 }, 781 782 //Hides a progress message 783 StopProgress: function () { 784 if (this.$progressmessage instanceof Utility.Message) { 785 this.$progressmessage.Close(); 786 delete this.$progressmessage; 787 } 788 }, 789 790 //Build and returns current url to request based on parameters 791 GetUrl: function (method) { 792 var url = location.href.replace(/[\?#].*/gi, '').concat(/\/$/gi.test(location.pathname) ? "default.aspx" : "");
793 var data = String(method).split('|').filter(Boolean); 794 if (data.length > 1) { 795 data[0] = data[0] || url; 796 data = [data.join("/"), '']; 797 } else { 798 if (window.pagewebmethodurl) 799 data = [window.pagewebmethodurl , data[0]]; 800 else 801 data = [ url , data[0]]; 802 803 data[0] = data[0].replace(/\/AjaxMethod$/i, '') + '/AjaxMethod'; 804 } 805 if (location.protocol =='https:') 806 data[0] = data[0].replace(/^http:\/\//i, 'https://'); 807 808 return data; 809 }, 810 811 //Updates container passed in with HTML code returned by Web Method 812 Update: function (method, parameters, container, progress) { 813 try { 814 var f; 815 this.Title = document.title; 816 // the Caller must exists 817 if (!this.Caller || !method) 818 return false; 819 820 //Call onRequest if exists (Allow to modify parameters before request) 821 Object.isFunction(this.Caller.onRequest) && (this.Caller.onRequest.call(this, parameters)); 822 823 if (this.stopRequest) { 824 this.stopRequest = false; 825 return; 826 } 827 // WEB-30832 - DEBUGGING ONLY!!! 828 //console.log('method:', method); 829 //if (method === 'BookEvent.ProceedBooking') { 830 //console.log('postData:', JSON.stringify(parameters)); 831 //return; 832 //} 833 //Show a Progress message if assigned 834 this.StartProgress(progress); 835 836 //Assign main properties 837 this.parameters = parameters || {}; 838 if (Object.isFunction(this.parameters.callback)) { 839 this.__callback = this.parameters.callback; 840 delete this.parameters.callback; 841 } 842 var url = this.GetUrl(method); 843 var opt = { 844 method: 'POST', 845 webMethod: true, // true, if we need to analize result from .NET web service 846 evalScripts: true, 847 contentType: 'application/json', 848 postBody: Object.toJSON(Boolean(url[1]) ? { methodName: url[1], data: this.parameters } : { data: this.parameters }), 849 onFailure: this.ShowError.bind(this), 850 onComplete: this.CompleteRequest.bind(this) 851 }; 852 if (Object.isElement(container)) 853 //Create an AJAX Updater to update container 854 this.ajaxRequest = new Ajax.Updater(container, url[0], opt); 855 else 856 //Create an AJAX Request 857 this.ajaxRequest = new Ajax.Request(url[0], opt); 858 859 //Access denied cannot be catch, so check the case and re-throw the error 860 if (this.ajaxRequest.transport.readyState != 1) 861 throw new Error('Access denied.'); 862 } catch (e) { 863 this.ShowError(e); 864 } 865 866 }, 867 868 Fetch: function (method, parameters) { 869 this.Update(method, parameters); 870 }, 871 //Checks if Ajax request is created and running 872 IsProcessing: function () { 873 return this.ajaxRequest && (this.ajaxRequest.transport.readyState > 0 && this.ajaxRequest.transport.readyState < 4); 874 }, 875 876 IsPending: function () { 877 return Ajax.activeRequestCount > 0; 878 }, 879 880 //Abort ajax request if created. 881 //NOTE: After Web Method request has been created only response on Client side can be aborted. 882 //On server side a web method still processed. 883 Stop: function () { 884 try { 885 if (this.ajaxRequest) { 886 this.ajaxRequest.abort(); 887 } 888 } catch (e) { }; 889 } 890 891}); 892//---------------------------------------------------------------------------------------------------------------------- 893//Base class 894//---------------------------------------------------------------------------------------------------------------------- 895Utility.Base = Class.create({ 896 initialize: function (host) { 897 //mandatory - DOM container 898 // NOTE: this.host might be set before class initializer call ( on a constructor) 899 this.host = this.host || $p(host) || $$(host); 900 901 if (Object.isElement(this.host)) { 902 this.host.identify(); 903 //Apply default settings 904 if (Object.isFunction(this.defaults)) { 905 this.defaults(this.defaults.argumentNames().length ? this.host.getActions() : undefined); 906 } else { 907 Object.extend(this, this.host.getActions()); 908 } 909 } else if (this.host instanceof Window) { 910 Object.isFunction(this.defaults) && Object.extend(this, this.defaults()); 911 } else if (Object.isArray(this.host) && this.host.length && Object.isElement(this.host[0])) { 912 this.host.invoke('identify'); 913 if (Object.isFunction(this.defaults)) { 914 this.defaults(); 915 } 916 } 917 if (!this.host) 918 throw new Error('Class cannot be instantiated! <' + host
918+ '>'); 919 920 var $names = this.initialize.argumentNames().slice(2); //skip $super and host arguments 921 var $args = $A(arguments).slice(1); //skip host argument 922 $args.each(function (it, i) { 923 var name = i < $names.length ? $names[i] : null; 924 if (name != '$super' && name != 'host') { 925 if (name) { 926 this[name] = Object.extend(this[name] || {}, Object.cast(it)); 927 } else if (Object.isString(it) || Object.isDate(it) || Object.isNumber(it) || Object.isArray(it) || Object.isBoolean(it)) { 928 if (!Object.isArray(this.parameters)) this.parameters = []; 929 this.parameters.push(it); 930 } else { 931 Object.extend(this, Object.cast(it)); 932 } 933 } 934 }, this); 935 936 this.events = {}; 937 938 return this; 939 }, 940 run: function (name) { 941 if (name) { 942 var args = $A(arguments).slice(1); 943 //if name is a CSV strip all names and treat each name as a separate function 944 945 var func, caller = name.split('.').removeLast(1).join('.'); 946 947 if (Object.isFunction(func = Object.get(this, name))) { 948 caller = Object.get(this, caller) || this; 949 return func.apply(caller, args); 950 //if result has a method property and current object has this method, so invoke that method with patameters (optional property) 951 } else if (Object.isFunction(func = Object.get(self, name))) { 952 caller = Object.get(self, caller) || self; 953 return func.apply(caller, args); 954 } 955 } 956 return undefined; 957 }, 958 on: function (eventName, func, fire) { 959 if (!this.host) 960 return this; 961 !this.events && (this.events = {}); 962 //Check if Event.Handler passed in as first parameter, add it to event collection 963 if (eventName instanceof Event.Handler) { 964 func = eventName, eventName = eventName.eventName; 965 } 966 967 if (Object.isString(eventName) && func instanceof Event.Handler) { 968 this.events[eventName] = func; 969 } else if (Object.isString(eventName) && this.events[eventName] instanceof Event.Handler) { 970 this.events[eventName].start(); 971 } else { 972 Object.isFunction(func) && (this.events[eventName] = this.host.on(eventName, null, func)); 973 } 974 fire && this.fire(eventName); 975 return this; 976 }, 977 off: function () { 978 var names = !arguments.length ? $H(this.events).keys() : $A(arguments); 979 for (var name in this.events) { 980 if (names.include(name)) { 981 this.events[name].stop(); 982 //delete this.events[name]; 983 } 984 } 985 return this; 986 }, 987 start: function () { 988 var names = !arguments.length ? $H(this.events).keys() : $A(arguments); 989 for (var name in this.events) { 990 if (names.include(name)) 991 this.events[name].start(); 992 } 993 }, 994 stop: function () { 995 var names = !arguments.length ? $H(this.events).keys() : $A(arguments); 996 for (var name in this.events) { 997 if (names.include(name)) 998 this.events[name].stop(); 999 } 1000 }, 1001 fire: function (name) { 1002 if (!this.host.simulate(name)) 1003 this.host.fire.apply(this.host, arguments); 1004 return this; 1005 } 1006}); 1007//---------------------------------------------------------------------------------------------------------------------- 1008//Generic Class to create selectors with server side business actions 1009//---------------------------------------------------------------------------------------------------------------------- 1010Utility.AjaxSelector = new Class.create(Utility.Base, { 1011 initialize: function ($super) { 1012 1013 if (!$super.apply(this, $A(arguments).slice(1))) 1014 return false; 1015 1016 //Verify and add progress information if needed 1017 var progress = Object.get(this, 'parameters.progress') || self.executeprogress; 1018 if (Object.isString(progress)) 1019 this.progressmessage = $loading({ host: this.host, message: progress }); 1020 else if (progress) 1021 this.progressmessage = self.progressmessage; 1022 1023 //Add new Web Request object 1024 this.WebRequest = new Utility.WebMethodRequest(this); 1025 1026 //Assign an active event to to call server method 1027 if (Object.isString(this.activeevent)) { 1028 this.host.noClick(); 1029 this.host[this.activeevent] = this.Call.bindAsEventListener(this); 1030 } 1031 return true; 1032 }, 1033 1034 //Request. Usually uses in OnClick event 1035 Call: function (e) { 1036 self.focus(); 1037 this.Request(this.method, this.parameters, this.container); 1038 return false; 1039 }, 1040 1041 //Call AJAX WebMethod 1042 //argumets method (required) - method to call 1043 // parameters (optional) - parameters (an object) to pass in 1044 // updateContainer (optional) - DOM element or and object like {success: #DOMELEMENT, failure: #DOMELEMENT} to update on complete. 1045 // If it's not exist (or ommited) use AJAX.Request 1046 Request: function (method, parameters, updateContainer) { 1047 this.WebRequest.Update(method, parameters, updateContainer); 1048 } 1049 1050}); 1051 1052 1053//---------------------------------------------------------------------------------------------------------------------- 1054//Class to add keyboard support to Selector (select item using keyboard : Up, Down, Home, End, Select, Cancel) 1055//---------------------------------------------------------------------------------------------------------------------- 1056Utility.AjaxDropDown = new Class.create(Utility.AjaxSelector, { 1057 defaults: function () { 1058 this.propertynames = ['Text', 'Value', 'Selected']; 1059 this.parameters = {}; 1060 this.layout = {}; 1061 this.waitmessage = "Loading..."; 1062 this.activeevent = "onclick"; 1063 }, 1064 initialize: function ($super) { 1065 1066 if (!$super.apply(this, $A(arguments).slice(1))) 1067 return false; 1068 1069 1070 if (this.layout.temporary) { 1071 this.Container = this.host; 1072 this.Container.addClassName('ajaxselector'); 1073 } else 1074 this.host.wrap(this.Container = new Element('div', { className: 'ajaxselector' })); 1075 1076 //Assign a progress message to the Host 1077 if (this.waitmessage) 1078 this.progressmessage = $loading({ host: this.Container, message: this.waitmessage });
1079 1080 return this; 1081 }, 1082 1083 //Override. Checks and updates popup container. If there is no items to select close popup with delay 1084 Complete: function (response) { 1085 if (response.responseJSON) { 1086 if (this.Selector) 1087 this.DestroySelector(); 1088 this.CreateSelector(response.responseJSON); 1089 } 1090 }, 1091 1092 //default function to transform option (needs to be overriden on time of Initialization) 1093 //Item transformation method. 1094 //where: 1095 // item - selected DOM element, 1096 // highlight- search expression, 1097 // keys - array of property names 1098 TransformItem: function (item, keys) { 1099 if (item === 'CREATE') //create 1100 return null; 1101 1102 item.$data = $H(item).keys().inject("", function (list, key) { 1103 list += ' data-parameter-' + key.toLowerCase() + '="' + item[key] + '"'; 1104 return list; 1105 }); 1106 item.$text = item[keys[0]]; 1107 return ('<div class="item" #{$data}">#{$text}</div>').interpolate(item); 1108 }, 1109 1110 1111 //Load data and update container, 1112 // Data can be present in two formats, 1113 // 1 - HTML code (formatted text) to update container with 1114 // 2 - Array of objects 1115 CreateSelector: function (data) { 1116 if (!data) 1117 return false; 1118 if (!this.Selector) 1119 //create a popup container 1120 $p(document.body).insert(this.Selector = new Element("div", { className: "ajaxselector selector" }).setStyle({ position: 'absolute', visibility: 'hidden' })); 1121 1122 1123 if (Object.isArray(data)) { 1124 1125 //Calls item transformation to create option container. 1126 //If not handled, this.container will be used a a container 1127 var parent = this.TransformItem.call(this.container, 'CREATE'); 1128 var properties = Object.isArray(this.propertynames) ? this.propertynames : ['Text']; 1129 //transform and add options to container 1130 for (var i = 0, item; item = data[i++];) { 1131 //call transformation function with two parameters: current item data and text box value 1132 item.index = i; 1133 (parent || this.Selector).insert(this.TransformItem.call((parent || this.Selector), item, properties)); 1134 } 1135 } else if (Object.isString(data)) { 1136 this.Selector.update(data); 1137 } 1138 if (this.items = this.Selector.select('.item'), this.items.length) { 1139 this.items.each(function (item, index) { 1140 item.index = index; 1141 item.onclick = this.Select.bindAsEventListener(this); 1142 item.onmouseover = this.Activate.bind(this, item); 1143 }, this); 1144 } 1145 this.ShowSelector(); 1146 1147 return false; 1148 }, 1149 1150 ShowSelector: function () { 1151 //set container position 1152 // var layout = Object.extend({}, this.layout); 1153 this.Selector.clonePosition(this.Container, { setWidth: false, setHeight: false }); 1154 this.layout.width = this.layout.width || Math.max(this.Container.measure('width'), this.Selector.measure('width')); 1155 this.layout.height = this.layout.height || Math.min(this.Selector.measure('border-box-height'), this.items[0].measure('border-box-height') * this.items.length); 1156 this.layout.minwidth = this.layout.minwidth || this.layout.width; 1157 this.layout.minheight = this.layout.minheight || this.layout.height; 1158 this.layout.top = this.layout.top || (this.Selector.measure('top') + document.viewport.getScrollOffsets().top); 1159 1160 this.Selector.setStyle({ 1161 top: this.layout.top + 'px', 1162 width: this.layout.width + 'px', 1163 height: this.layout.height + 'px', 1164 'min-width': this.layout.minwidth + 'px', 1165 'min-height': this.layout.minheight + 'px', 1166 visibility: 'visible' 1167 }); 1168 1169 //Add event handlers 1170 this.on(":exit", this.DestroySelector.bind(this)); 1171 this.on(":select", this.Select.bindAsEventListener(this)); 1172 this.on(":move", this.Move.bindAsEventListener(this)); 1173 this.on(document.on("keyup", this.KeyPress.bindAsEventListener(this))); 1174 this.on(document.on("mousedown", this.Close.bindAsEventListener(this))); 1175 this.on(Event.on(self, "mousewheel", this.Close.bindAsEventListener(this))); 1176 this.on(Event.on(self, "resize", this.Close.bindAsEventListener(this))); 1177 1178 Object.isFunction(this.onShow) && (this.onShow(this.host, this.container));
1179 1180 if (Object.isArray(this.items) && this.items.length) 1181 this.Activate(this.items.first()); 1182 1183 }, 1184 1185 setFocus: function (index) { 1186 if (Object.isArray(this.items) && this.items.length && (this.items.length > index)) 1187 this.Activate(this.items[index], true); 1188 }, 1189 1190 DestroySelector: function (item) { 1191 //destroy event handlers 1192 this.off(); 1193 1194 Object.isFunction(this.onHide) && (this.onHide()); 1195 1196 //destroy content and item collections 1197 this.Selector.remove(); 1198 1199 if (this.layout.temporary) { 1200 this.Container.removeClassName('ajaxselector'); 1201 } 1202 delete this.items; 1203 delete this.Selector; 1204 1205 }, 1206 1207 Select: function (e) { 1208 Event.stop(e); 1209 if (!Object.isArray(this.items) && Object.isUndefined(this.ActiveIndex)) 1210 return false; 1211 var item = this.items[this.ActiveIndex]; 1212 var data = item.getActions(); 1213 //call onselect event. 1214 //NOTE.If data is Empty object, you can analize selected item by using 'this' 1215 Object.isFunction(this.onSelect) && (this.onSelect.call(this, this, item, data)); 1216 //close selector 1217 this.fire(':exit'); 1218 }, 1219 1220 Activate: function (item, addExtraBottomPadding) {
1221 if (!item || Object.isUndefined(item.index)) { 1222 return false; 1223 } 1224 1225 if (this.ActiveIndex == item.index) 1226 return true; 1227 1228 var prevIndex = this.ActiveIndex || 0; 1229 this.items[prevIndex].removeClassName("over"); 1230 this.items[this.ActiveIndex = item.index].addClassName("over"); 1231 1232 !this.items[this.ActiveIndex]._height && (this.items[this.ActiveIndex]._height = this.items[this.ActiveIndex].getHeight()); 1233 //we need to calculate top and bottom pixels of active item 1234 var top = this.items[this.ActiveIndex]._height * this.ActiveIndex; 1235 var bottom = this.items[this.ActiveIndex]._height * (this.ActiveIndex + 1); 1236 1237 //do scrolling to make item visible 1238 if (top < this.Selector.scrollTop) 1239 this.Selector.scrollTop = Math.max(this.Selector.scrollTop - top, 0); 1240 else if (bottom > this.Selector.scrollTop + this.Selector.getHeight()) 1241 { 1242 if (addExtraBottomPadding) { 1243 // web-117 added extra padding to display focuses item on top 1244 var units = Math.ceil(this.Selector.getHeight() / this.items[this.ActiveIndex]._height); 1245 this.Selector.scrollTop = Math.max(bottom - this.Selector.getHeight() + (this.items[this.ActiveIndex]._height * (units - 3)), 0); 1246 } 1247 else 1248 this.Selector.scrollTop = Math.max(bottom - this.Selector.getHeight(), 0); 1249 } 1250 1251 }, 1252 1253 Close: function (e) { 1254 var el = Event.element(e); 1255 if (!Object.isElement(el) || (el !== this.Selector && !el.descendantOf(this.Selector) && el !== this.host)) { 1256 this.fire(":exit"); 1257 } 1258 }, 1259 1260 Move: function (e) { 1261 Event.stop(e); 1262 1263 if (!e || Object.isUndefined(e.memo) || Object.isUndefined(e.memo.index) || !this.items.length) 1264 return false; 1265 1266 index = e.memo.index; 1267 1268 //if string - consider it as item position 1269 if (Object.isString(index)) { 1270 if (index == 'BOTTOM') 1271 index = this.items.length - 1; 1272 else // 'TOP' or other 1273 index = 0; 1274 } else if (Object.isNumber(index)) { 1275 if (Object.isUndefined(this.ActiveIndex)) 1276 index = index > 0 ? 0 : this.items.length - 1; 1277 else 1278 index = this.ActiveIndex + index; 1279 } 1280 1281 if (index >= 0 && index < this.items.length) 1282 this.Activate(this.items[index]); 1283 }, 1284 1285 //Handle Key Press event (IE specific) 1286 KeyPress: function (e) { 1287 1288 var code = ((e = e || event), e.keyCode || e.which || e.charCode); 1289 Event.stop(e); 1290 switch (code) { 1291 case Event.KEY_ESC: 1292 this.fire(":exit"); 1293 return false; 1294 case Event.KEY_RETURN: 1295 this.fire(":select"); 1296 return false; 1297 case Event.KEY_UP: 1298 case Event.KEY_DOWN: 1299 case Event.KEY_HOME: 1300 case Event.KEY_END: 1301 return !Prototype.Browser.IE; 1302 } 1303 return false; 1304 } 1305}); 1306 1307 1308Utility.Actions = Class.create(Utility.Base, { 1309 SetActions: function(rule) { 1310 this.host.select(rule || '[data-action]').each(function(it) { 1311 if (!it.$click) { 1312 it.data = it.getActions({ cast: true }); 1313 it.noClick().on('click', function(e) { 1314 e.stop(); 1315 this.DoAction(it.data.action.toLowerCase(), it.data, it); 1316 }.bindAsEventListener(this)); 1317 } 1318 }, this); 1319 }, 1320 DoAction: function(action, it, element) { 1321 } 1322}); 1323 1324Utility.Callback = new Class.create(Utility.Base, { 1325 initialize: function ($super, signature, init) { 1326 if (!$super.apply(this, $A(arguments).slice(1))) 1327 return false; 1328 this.signature = signature; 1329 1330 // init might play a role of WebForm_InitCallback 1331 Object.isFunction(init) && (init()); 1332 }, 1333 DoAssign: function () { 1334 this.controls.each(function (it) { 1335 $$(it.selector).first().on('click', this.RequestWithParam.bindAsEventListener(this, it.prms)); 1336 }, this); 1337 }, 1338 RequestWithParam: function (e, prms) { 1339 e.stop(); 1340 if (!Object.isString(prms)) 1341 prms = Object.toJSON(prms); 1342 return this.Request(prms); 1343 }, 1344 Request: function (prms) { 1345 WebForm_DoCallback && WebForm_DoCallback(this.signature, prms || '', this.Callback.bind(this), '', null, false); 1346 return false; 1347 }, 1348 Callback: function (result) { 1349 try { 1350 if (String(result).isJSON()) { 1351 result = result.evalJSON(); 1352 this.run(result.method, result.parameters); 1353 } else { 1354 alert(result); 1355 } 1356 } catch (e) { 1357 alert(e.message); 1358 } 1359 } 1360}); 1361 1362 1363Utility.Redirect = function (url, w) { 1364 w = w && w.location ? w : self;
1365 if (url && Object.isString(url)) 1366 w.location.href = url; 1367/* 1368 else if (url == "") 1369 w.location.href = w.location.href; 1370*/ 1371 else //if (url == "") 1372 w.location.reload(true); 1373 1374}; 1375 1376Utility.RedirectNewWindow = function (url, w) { 1377 w = w && w.location ? w : self; 1378 if (url && Object.isString(url)) 1379 w.open(url, '_blank') 1380 else 1381 w.location.reload(true); 1382 1383}; 1384 1385Ajax.JSONRequest = Class.create(Ajax.Base, (function () { 1386 var head = document.getElementsByTagName('head')[0]; 1387 return { 1388 initialize: function ($super, url, id, options) { 1389 $super(options); 1390 this.options.url = url; 1391 this.options.id = id; 1392 this.options.callbackParamName = this.options.callbackParamName || 'callback'; 1393 this.options.timeout = this.options.timeout || 10000; // Default timeout: 10 seconds 1394 this.responseJSON = {}; 1395 this.request(); 1396 }, 1397 1398 request: function () { 1399 // Add callback as a parameter and build request URL 1400 if (Object.isString(this.options.parameters)) 1401 this.options.parameters = this.options.parameters.toQueryParams(); 1402 1403 //Check ID and create a name for callback function 1404 if (this.options.id) { 1405 this._name = '_prototypeJSONPCallback_' + (this.options.id ? String(this.options.id) : ''); 1406 this.options.parameters[this.options.callbackParamName] = this._name; 1407 } 1408 this.options.parameters = Object.toQueryString(this.options.parameters); 1409 this.options.url = this.options.url + (this.options.parameters ? ((this.options.url.include('?') ? '&' : '?') + this.options.parameters) : ''); 1410 this.script = new Element('script', { type: 'text/javascript', src: this.options.url }); 1411 1412 if (this.options.id) { 1413 this.timeout = setTimeout(function () { 1414 this.cleanup(); 1415 if (Object.isFunction(this.options.onFailure)) { 1416 this.options.onFailure.call(this, this); 1417 } 1418 }.bind(this), this.options.timeout); 1419 1420 // Define callback function 1421 window[this._name] = function (json) { 1422 this.cleanup(); // Garbage collection 1423 if (Object.isFunction(this.options.onComplete)) { 1424 this.responseJSON = json; 1425 this.options.onComplete.call(this, this); 1426 } 1427 }.bind(this); 1428 } 1429 1430 if (Object.isFunction(this.options.onCreate)) { 1431 this.options.onCreate.call(this, this); 1432 } 1433 if (!$$('head [src="' + this.options.url + '"]').first()) 1434 head.insert(this.script); 1435 1436 }, 1437 cleanup: function () { 1438 window[this._name] = undefined; 1439 if (this.timeout) { 1440 clearTimeout(this.timeout); 1441 this.timeout = null; 1442 } 1443 if (this.script && Object.isElement(this.script)) { 1444 this.script.remove(); 1445 this.script = null; 1446 } 1447 } 1448 }; 1449})()); 1450 1451 1452 1453 1454//---------------------------------------------------------------------------------------------------------------------- 1455//Class to show progress on image load 1456//---------------------------------------------------------------------------------------------------------------------- 1457Utility.ImageLoader = Class.create({ 1458 initialize: function (img, settings) { 1459 //duration should be in seconds 1460 this.settings = Object.extend({ period: 0.1, duration: 3, loading: 'loading', max: 140 }, settings); 1461 1462 if (this.img = $p(img), !this.img || this.img.tagName != 'IMG' || !this.settings.progress) 1463 return false; 1464 1465 this.dim = this.img.up().getDimensions(); 1466 this.settings = Object.extend(this.settings, this.img.getActions()); 1467 this.settings.duration *= 10; 1468 1469 this.Run(); 1470 }, 1471 1472 //Starts counter, checks time every second and update DOM element 1473 Run: function () { 1474 if (this.settings.duration > 0) { 1475 this.img.hide();
1476 this.timer = new PeriodicalExecuter(function (pe) { 1477 try { 1478 if (this.IsReady()) { 1479 //reached zero, stop executer 1480 pe.stop(); 1481 this.Update(); 1482 } else if (--this.settings.duration <= 0) { 1483 throw new Error('stop'); 1484 } else { 1485 this.ShowProgress(); 1486 } 1487 1488 //not reached yet 1489 } catch (e) { 1490 // Stops executer in case of error 1491 pe.stop(); 1492 this.Cancel(); 1493 } 1494 }.bind(this), this.settings.period); // execute funcion on behalh of current object every second 1495 } 1496 return this; 1497 }, 1498 IsReady: function () { 1499 return this.img.complete && this.img.getWidth() > 0 && this.img.getHeight() > 0; 1500 1501 }, 1502 ShowProgress: function () { 1503 if (!this.loading) { 1504 this.img.insert({ before: this.loading = new Element('img', { src: this.settings.progress, className: this.settings.loading }) }); 1505 1506 } 1507 }, 1508 1509 Resize: function () { 1510 //do not resize if settings are not specified 1511 this.settings.width = String(this.settings.width).toNumber(); 1512 this.settings.height = String(this.settings.height).toNumber(); 1513 1514 if (!this.settings.width && !this.settings.height) 1515 return; 1516 1517 //get image dimensions 1518 var dim = this.img.getDimensions(); 1519 //calculate aspect ratio 1520 var ratio = dim.height / dim.width; 1521 //if Height is requested 1522 if (this.settings.height > this.settings.width && this.settings.width == 0) 1523 this.settings.width = this.settings.height * 1 / ratio; 1524 //if width is requested 1525 else if ((this.settings.width >= this.settings.height && this.settings.height == 0)) 1526 this.settings.height = this.settings.width * ratio; 1527 1528 this.img.setStyle({ width: Math.round(this.settings.width) + 'px', height: Math.round(this.settings.height) + 'px' }); 1529 }, 1530 1531 HideProgress: function () { 1532 this.loading && (this.loading.remove()); 1533 if (!this.settings || !this.settings.hideImage) //sprte - 7514 removing forced inheritance when ImageLoader is loaded 1534 this.img.setStyle('visibility:inherit').show(); 1535 }, 1536 1537 Update: function () { 1538 this.HideProgress(); 1539 this.Resize(); 1540 }, 1541 1542 Cancel: function () { 1543 this.HideProgress(); 1544 1545 } 1546}); 1547 1548//Control's Bubble Tip (like the element title) 1549Utility.BubbleTip = Class.create(Utility.Base, { 1550 defaults: function (o) { 1551 return this.options = Object.extend({ 1552 css: 'bubbletip', 1553 gravity: 'se', 1554 offset: 0, 1555 opacity: 1, 1556 trigger: 'hover' 1557 }, o); 1558 }, 1559 initialize: function ($super, host, options) { 1560 try { 1561 if (!$super.apply(this, $A(arguments).slice(1))) 1562 return false; 1563 1564 if (this.getValue()) { 1565 this.on(this.options.trigger == 'hover' ? 'mouseenter' : 'focus', this.enter.bindAsEventListener(this)); 1566 this.on(this.options.trigger == 'hover' ? 'mouseleave' : 'blur', this.leave.bindAsEventListener(this)); 1567 1568 if (this.host.readAttribute('bubbletip') || this.options.bubbletip) 1569 this.host.addClassName(this.options.css); 1570 //this.on('mousedown', this.toggle.bindAsEventListener(this)); 1571 1572 } 1573 1574 return this; 1575 1576 } 1577 catch (e) { 1578 1579 } 1580 }, 1581 show: function (e) { 1582 if (!(this.content = this.getValue())) 1583 return; 1584 if (this.disabled) 1585 return; 1586 1587 this.host.writeAttribute('title', null); 1588 if (!this.tooltip) { 1589 $p(document.body).insert(this.tooltip = new Element("div", { className: 'ps-tip' }).update('<div class="ps-tip-arrow"></div><div class="ps-tip-inner">#{content}</div></div>'.interpolate(this))); 1590 this.tooltip.setStyle({ top: 0, left: 0, visibility: 'hidden', display: 'block' }); 1591 } 1592 var host = Object.extend(this.host.cumulativeOffset(), this.host.getDimensions()); 1593 var tip = Object.extend(this.tooltip.getDimensions(), { opacity: this.options.opacity }); 1594 var gravity = this.options.gravity;
1595 var i = 0; 1596 do { 1597 i++; 1598 switch (gravity) { 1599 case 'se': 1600 tip = Object.extend(tip, { top: host.top + host.height / 2, left: host.left + host.width + this.options.offset }); 1601 break; 1602 case 'sw': 1603 tip = Object.extend(tip, { top: host.top + host.height / 2, left: host.left - tip.width - this.options.offset }); 1604 break; 1605 case 'ne': 1606 tip = Object.extend(tip, { top: host.top - tip.height, left: host.left + host.width + this.options.offset }); 1607 break; 1608 case 'nw': 1609 tip = Object.extend(tip, { top: host.top - tip.height, left: host.left - host.width - this.options.offset }); 1610 break; 1611 } 1612 var b = tip.left > 0 && (tip.left + tip.width) < $Screen.viewport.width && tip.top > 0 && (tip.top + tip.height) < $Screen.viewport.width; 1613 if (!b) { 1614 if (gravity == 'se') gravity = 'sw'; 1615 else if (gravity == 'sw') gravity = 'ne'; 1616 else if (gravity == 'ne') gravity = 'nw'; 1617 else gravity = 'se'; 1618 } 1619 if (i == 5) gravity = this.options.gravity; 1620 1621 } while (!b && i < 5) 1622 this.tooltip.setStyle("top:#{top}px;left:#{left}px".interpolate(tip)).addClassName('ps-tip-' + gravity); 1623 this.tooltip.setStyle({ visibility: 'visible', opacity: this.options.opacity }); 1624 1625 }, 1626 getValue: function () { 1627 return unescape((this.host.readAttribute('title') || this.host.readAttribute('bubbletip') || this.options.title || this.options.bubbletip || this.content || '').replace(/(^\s*|\s*$)/, "")); 1628 1629 ; 1630 }, 1631 setValue: function (text) { 1632 if (!text) return; 1633 if (this.content = String(text).replace(/(^\s*|\s*$)/, "")) { 1634 if (this.host.readAttribute('bubbletip') || this.options.bubbletip) 1635 this.host.addClassName(this.options.css); 1636 this.host.writeAttribute('title', null); 1637 } 1638 }, 1639 hide: function () { 1640 if (!this.tooltip) 1641 return; 1642 this.tooltip.remove(); 1643 delete this.tooltip; 1644 }, 1645 enter: function (e) { 1646 if (e.shiftKey) 1647 return; 1648 this.show(e); 1649 }, 1650 leave: function (e) { 1651 this.hide(); 1652 }, 1653 toggle: function (e) { 1654 if (!e.ctrlKey) return; 1655 (this.disabled = !Boolean(this.disabled)) ? this.hide() : this.show(); 1656 } 1657}); 1658 1659Utility.RGB = { 1660 parse1: function (r, g, b, a) { 1661 if (arguments.length == 1) { 1662 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(String(arguments[0])); 1663 Object.extend(this, result ? { 1664 R: parseInt(result[1], 16), 1665 G: parseInt(result[2], 16), 1666 B: parseInt(result[3], 16) 1667 } : {}); 1668 } else { 1669 this.R = String(r).toNumber(); 1670 this.G = String(g).toNumber(); 1671 this.B = String(b).toNumber(); 1672 this.A = parseFloat(String(a)); 1673 } 1674 1675 }, 1676 parse: function (r, g, b, a) { 1677 if (arguments.length == 1 && Object.isString(arguments[0])) { 1678 var color = String(arguments[0]).replace(/\s\s*/g, '');// Remove all spaces 1679 var cache, p = parseInt; // Use p as a byte saving reference to parseInt 1680 1681 // Checks for 6 digit hex and converts string to integer 1682 if (cache = /^#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})/.exec(color)) 1683 cache = [p(cache[1], 16), p(cache[2], 16), p(cache[3], 16)]; 1684 1685 // Checks for 3 digit hex and converts string to integer 1686 else if (cache = /^#([\da-fA-F])([\da-fA-F])([\da-fA-F])/.exec(color)) 1687 cache = [p(cache[1], 16) * 17, p(cache[2], 16) * 17, p(cache[3], 16) * 17]; 1688 1689 // Checks for rgba and converts string to 1690 // integer/float using unary + operator to save bytes 1691 else if (cache = /^rgba\(([\d]+),([\d]+),([\d]+),([\d]+|[\d]*.[\d]+)\)/.exec(color)) 1692 cache = [+cache[1], +cache[2], +cache[3], +cache[4]]; 1693 1694 // Checks for rgb and converts string to 1695 // integer/float using unary + operator to save bytes 1696 else if (cache = /^rgb\(([\d]+),([\d]+),([\d]+)\)/.exec(color)) 1697 cache = [+cache[1], +cache[2], +cache[3]]; 1698 1699 // Performs RGBA conversion by default 1700 cache && isNaN(cache[3]) && (cache[3] = 1); 1701 1702 return cache; 1703 } else { 1704 return [String(r).toNumber(), String(g).toNumber(), String(b).toNumber(), parseFloat(String(a))]; 1705 } 1706 1707 }, 1708 toHex: function () { 1709 var cache = this.parse.apply(this, $A(arguments)); 1710 //return ("#" + this.R.toColorPart() + this.G.toColorPart() + this.B.toColorPart()).toUpperCase(); 1711 return cache && cache[3] > 0 ? ("#" + cache[0].toColorPart() + cache[1].toColorPart() + cache[2].toColorPart()).toUpperCase() : 'transparent'; 1712 }, 1713 toRGB: function () { 1714 var cache = this.parse.apply(this, $A(arguments)); 1715 return cache && cache[3] > 0 ? "rgb(#{0},#{1},#{2})".interpolate(cache) : 'transparent'; 1716 }, 1717 toRGBA: function () { 1718 var cache = this.parse.apply(this, $A(arguments)); 1719 return cache ? "rgba(#{0},#{1},#{2},#{3})".interpolate(cache) : 'transparent'; 1720 }, 1721 toContrast: function () { 1722 var cache = this.parse.apply(this, $A(arguments)); 1723 return cache ? ((((cache[0] * 299) + (cache[1] * 587) + (cache[2] * 114)) / 1000 >= 128) ? '#000' : '#FFF') : "#000"; 1724 } 1725}; 1726//---------------------------------------------------------------------------------------------------------------------- 1727//Class to create four time of messages: 1728// - Alert - shows a Dialog window with one button (closes window) 1729// - Confirm - shows a Dialog with confirm message and two choices: Yes or No 1730// - Dialog - shows a Dialog with a close button on header 1731// - Progress - shows custom progress message (in a center of the window) and disables all client actions 1732// - Loading - shows a custom progress message linked to given DOM element 1733//---------------------------------------------------------------------------------------------------------------------- 1734Utility.Message = Class.create({ 1735 defaults: function () { 1736 return { 1737 overlay: true, 1738 ok: 'OK', // text for the OK button 1739 cancel: 'Cancel', // text for the Cancel button 1740 controls: true //allows to show/hide controls (Ok,Cancel) if presented 1741 //omitted acceptable parameters: 1742 //radius: true, 1743 //shadow:true, 1744 //css // use custom CSS to modify the layout 1745 //callback, //a call back function on closing message 1746 //width, 1747 //height 1748 }; 1749 }, 1750 initialize: function (type, options) { 1751 1752 //validate type 1753 if (!(['alert', 'confirm', 'dialog', 'progress', 'popup', 'loading'].include(this.type = type))) 1754 return false; 1755 this.events = []; 1756 //Load and validate options 1757 this.options = Object.extend(this.defaults(), Object.isString(options.message) ? options : Object.extend(options, options.message)); 1758 //host 1759 this.options.host = this.options.host || self; 1760 //title 1761 this.options.title = this.options.title || this.type.capitalize(); 1762 //message 1763 this.options.message = this.options.isHTML ? (this.options.message || '') : (this.options.message || '').replace(/\n/g, '<br />'); 1764 /* 1765 this.options.message = (this.options.message || ''); 1766 this.options.isHTML && (this.options.message = this.options.message.replace(/\n/g, '<br/>')); 1767 */ 1768 //a callback 1769 this.options.callback = Object.isFunction(this.options.callback) ? this.options.callback : Prototype.emptyFunction; 1770 1771 if (Object.isFunction(this[this.options.auto])) 1772 return this[this.options.auto].apply(this); 1773 return this; 1774 }, 1775 HTMLk8: function (data) { 1776 switch (this.type) { 1777 case 'alert': 1778 return ('<div class="message-header-k8"><span class="message-title-k8">#{title}</span><span class="message-tools-k8"><span data-action="discard" class="close-k8"></span></span></div>' + 1779 '<div class="message-body-k8"><div class="message-k8"></div></div>' +
1780 '<div class="message-controls-k8"><button data-action="ok" class="ModuleBtn ModuleBtnGray" data-default="true">#{ok}</button</div>').interpolate(data); 1781 case 'confirm': 1782 return ('<div class="message-header-k8"><span class="message-title-k8">#{title}</span><span class="message-tools-k8"><span data-action="discard" class="close-k8"></span></span></div>' + 1783 '<div class="message-body-k8"><div class="message-k8"></div></div>' + 1784 '<div class="message-controls-k8"><button data-action="ok" class="ModuleBtn ModuleBtnGray" data-default="true">#{ok}</button> <button data-action="cancel" class="ModuleBtn ModuleBtnGray">#{cancel}</button></div>').interpolate(data); 1785 case 'dialog': 1786 return ('<div class="message-header-k8"><span class="message-title-k8">#{title}</span><span class="message-tools-k8"><span data-action="cancel" data-default="true" class="close-k8"></span></span></div>' + 1787 '<div class="message-body-k8"><div class="message-k8"></div></div>' + 1788 '<div class="message-controls-k8"><button data-action="ok" class="ModuleBtn ModuleBtnGray" data-default="true">#{ok}</button</div>').interpolate(data); 1789 case 'popup': 1790 return ('<div class="message-header-k8"><span class="message-title-k8">#{title}</span><span class="message-tools-k8"><span data-action="cancel" data-default="true" class="close-k8"></span></span></div>' + 1791 '<div class="message-body-k8"><div class="message-k8"></div></div>' + 1792 '<div class="message-controls-k8"><button data-action="ok" class="ModuleBtn ModuleBtnGray" data-default="true">#{ok}</button</div>').interpolate(data); 1793 case 'progress': 1794 return ('<div class="message-body-k8"><div class="message-k8"></div></div>');//.interpolate(data); 1795 1796 case 'loading': 1797 default: 1798 return '<div class="message-k8">#{message}</div>';//.interpolate(data); 1799 } 1800 }, 1801 HTML: function (data) { 1802 switch (this.type) { 1803 case 'alert': 1804 return ('<div class="message-header"><span>#{title}</span></div>' + 1805 '<div class="message-body"><div class="message"></div></div>' + 1806 '<div class="message-controls"><button data-action="ok" data-default="true">#{ok}</button</div>').interpolate(data); 1807 case 'confirm': 1808 return ('<div class="message-header"><span>#{title}</span><span class="message-tools"><span data-action="discard" class="close"></span></span></div>' + 1809 '<div class="message-body"><div class="message"></div></div>' + 1810 '<div class="message-controls"><button data-action="ok" data-default="true">#{ok}</button> <button data-action="cancel">#{cancel}</button></div>').interpolate(data); 1811 case 'dialog': 1812 return ('<div class="message-header"><span>#{title}</span><span class="message-tools"><span data-action="cancel" data-default="true" class="close"></span></span></div>' + 1813 '<div class="message-body"><div class="message"></div></div>' + 1814 '<div class="message-controls"><button data-action="ok" data-default="true">#{ok}</button</div>').interpolate(data); 1815 case 'popup': 1816 return ('<div class="message-header"><span>#{title}</span><span class="message-tools"><span data-action="cancel" data-default="true" class="close"></span></span></div>' + 1817 '<div class="message-body"><div class="message"></div></div>' + 1818 '<div class="message-controls"><button data-action="ok" data-default="true">#{ok}</button</div>').interpolate(data); 1819 case 'progress': 1820 return ('<div class="loader loader-general"><i class="icon-spinner spinning cms-icon-100 loader-icon" aria-hidden="true"></i><span class="loader-text">Loading</span></div>');//.interpolate(data); 1821 1822 case 'loading': 1823 default: 1824 return '<div class="message">#{message}</div>';//.interpolate(data); 1825 } 1826 }, 1827 Create: function () { 1828 var messageboxclass = this.options.k8 ? 'message-box-k8 ' : 'message-box '; 1829 var messageheaderclass = this.options.k8 ? '.message-header-k8 ' : '.message-header'; 1830 var messagebodyclass = this.options.k8 ? '.message-body-k8 ' : '.message-body'; 1831 var messageclass = this.options.k8 ? '.message-k8 ' : '.message'; 1832 var messagecontrolsclass = this.options.k8 ? '.message-control
1832s-k8 ' : '.message-controls'; 1833 1834 1835 if (this.options.keep !== true) 1836 this.Remove(); 1837 1838 if (this.type != 'progress') 1839 $p(document.body).insert(this.container = new Element("div", { 'class': messageboxclass + this.type })); 1840 else 1841 $p(document.body).insert(this.container = new Element("div", { 'class': 'cms-bootstrap'})); 1842 1843 this.options.width = this.Calculate(this.options.width, $Screen.viewport.width); 1844 this.options.height = this.Calculate(this.options.height, $Screen.viewport.height); 1845 1846 if (Object.isNumber(this.options.width)) { 1847 this.container.setStyle({ width: this.options.width + 'px' }); 1848 } 1849 if (Object.isNumber(this.options.height)) { 1850 this.container.setStyle({ height: this.options.height + 'px' }); 1851 } 1852 if (this.options.k8) { 1853 this.container.update(this.HTMLk8(this.options)).addClassName(this.options.css || '').setStyle("position:fixed;padding:0;margin:0;"); 1854 } else { 1855 this.container.update(this.HTML(this.options)).addClassName(this.options.css || '').setStyle("position:fixed;padding:0;margin:0;"); 1856 } 1857 1858 this._overlay = this.container.wrap('div', { 'class': 'message-box-overlay' }).setStyle("position:fixed;top:0px;left:0px;width:100%;height:100%;visibility:hidden;"); 1859 this.header = this.container.down(messageheaderclass); 1860 if (this.type != 'progress') { 1861 this.messagebody = this.container.down(messagebodyclass); 1862 this.messagecontainer = this.container.down(messageclass); 1863 } else { 1864 this.messagebody = this.container.down('.loader'); 1865 this.messagecontainer = this.container.down('.loader-text'); 1866 } 1867 1868 this.messagecontrols = this.container.down(messagecontrolsclass); 1869 if (this.messagecontrols) { 1870 !this.options.controls && (this.messagecontrols.remove(), this.messagecontrols = undefined); 1871 } 1872 1873 this.Update({ message: this.options.message }); 1874 this.container.select('[data-action]').each(function (it) { 1875 it.on('mousedown', this.DoAction.bind(this)); 1876 }, this); 1877 if (!this.options.defaultAction && (this.options.defaultAction = this.container.select('[data-default]').first(), this.options.defaultAction)) 1878 this.options.defaultAction = this.options.defaultAction.getActions().action; 1879 1880 if ('loading' == this.type) { 1881 this._overlay.setStyle('background-color:transparent;'); 1882 } 1883 1884 this.options.radius && this.container.addClassName('-radius'); 1885 this.options.shadow && this.container.addClassName('-shadow'); 1886 1887 // Make draggable. Note:: requires draggables library 1888 if (this.header && Utility.Drag && !this.options.disabledrag) { 1889 try { 1890 new Utility.Drag(this.container, { handle: this.header.setStyle({ cursor: 'move' }) }); 1891 } catch (e) { } 1892 } 1893 this.options.host.__message = this; 1894 return this; 1895 }, 1896 Update: function (opt) { 1897 if (Object.isUndefined(opt)) return; 1898 opt.title && this.container.down('.message-header span').update(opt.title); 1899 opt.message && this.messagecontainer.update(opt.message); 1900 return this; 1901 }, 1902 Indicate: function () { 1903 if (this.type == 'progress') { 1904 var max = 40; 1905 var start = 0; 1906 var el = this.messagebody; 1907 if (el) { 1908 this.events.push(new PeriodicalExecuter(function (pe) { 1909 try { 1910 el.setStyle('background-position:#{0}px #{1}px'.interpolate([start, 0])); 1911 start += start == max ? start * -1 : 1; 1912 } catch (e) { 1913 pe.stop(); 1914 } 1915 }, 0.01)); 1916 } 1917 } 1918 return this; 1919 }, 1920 Show: function (opt) { 1921 1922 if (self.progressmessage instanceof Utility.Message && self.progressmessage.IsShown()) 1923 self.progressmessage.Hide(); 1924 1925 if (Object.isNumber(opt)) 1926 this.Hide.bind(this).delay(opt); 1927 else if (opt) 1928 this.Update(opt); 1929 if (this.options.host.__message !== this) 1930 this.Create(); 1931 1932 this.Reposition().Indicate().AddEventHandlers(); 1933 1934 self.focus(); 1935 return this; 1936 }, 1937 IsShown: function () {
1938 return this._overlay && this._overlay.getStyle('visibility') != 'hidden'; 1939 }, 1940 Hide: function () { 1941 this.Close(); 1942 }, 1943 Close: function (f) { 1944 //removes all events 1945 this.RemoveEventHandlers(); 1946 if (this.options.keep === true) { 1947 this._overlay.setStyle('visibility:hidden'); 1948 return this; 1949 } 1950 if (this.container) { 1951 Object.isFunction(this.onHide) && this.onHide(); 1952 1953 this.container.remove(); 1954 delete this.container; 1955 } 1956 if (this._overlay) { 1957 this._overlay.remove(); 1958 delete this._overlay; 1959 } 1960 1961 //remove handler for current message 1962 this.options.host.__message = undefined; 1963 return this; 1964 }, 1965 DoAction: function (e) { 1966 var data = e.element().getActions(); 1967 if (e.keyCode == Event.KEY_RETURN) { 1968 data.action = this.options.defaultAction; 1969 } else if (e.keyCode == Event.KEY_ESC) { 1970 data.action = 'cancel'; 1971 } 1972 switch (data.action) { 1973 case 'ok': 1974 this.Close(); 1975 if (this.options.callback !== Prototype.emptyFunction) 1976 this.options.callback.apply(this, [e.element(), this.messagecontainer]); 1977 else { 1978 //NOTE: issue with Firefox and .simulate() 1979 // Object.isElement(this.options.host) && this.options.host.simulate('click'); 1980 if (Object.isElement(this.options.host) && Object.isFunction(this.options.host.onclick)) 1981 this.options.host.onclick(); 1982 } 1983 break; 1984 case 'cancel': 1985 this.Close(); 1986 this.options.callback.apply(this, [false, this.messagecontainer]); 1987 break; 1988 case 'discard': 1989 this.Close(); 1990 this.options.callback.apply(this, [undefined, this.messagecontainer]); 1991 break; 1992 default: 1993 return; 1994 } 1995 }, 1996 1997 //Closes previous message and removes existing reference on it 1998 Remove: function () { 1999 // Hide stored message if exists 2000 if (this.options.host.__message) 2001 this.options.host.__message.Close(); 2002 }, 2003 2004 Calculate: function (value, max) { 2005 2006 //check width and height properties 2007 if (Object.isString(value) && value) { 2008 value = Math.ceil((String(value).indexOf('%') > 0 ? max / 100 : 1) * value.toNumber()); 2009 } 2010 if (Object.isNumber(value)) 2011 return value; 2012 return undefined; 2013 }, 2014 2015 2016 //Maintain position of container 2017 Reposition: function () { 2018 this._overlay.setStyle('visibility:visible'); 2019 var pos = { 2020 set: Object.isNumber(this.options.top) && Object.isNumber(this.options.left), 2021 top: String(this.options.left).toNumber(), 2022 left: String(this.options.top).toNumber() 2023 }; 2024 2025 if (this.type == 'loading') { 2026 if (this.options.host) { 2027 pos.set = false; 2028 if (!this.options.host.getWidth()) { 2029 this.container.hide(); 2030 } else { 2031 this.container.clonePosition(this.options.host, { offsetLeft: pos.left, offsetTop: pos.top }); 2032 } 2033 } 2034 } else { 2035 2036 var dim = document.viewport.getDimensions(); 2037 pos = { 2038 set: true, 2039 top: pos.set ? pos.top : Math.max(((dim.height - this.container.getHeight()) / 2), 0), 2040 left: pos.set ? pos.left : Math.max((dim.width - this.container.getWidth()) / 2, 0) 2041 }; 2042 } 2043 if (pos.set) 2044 this.container.setStyle("top:#{top}px;left:#{left}px".interpolate(pos)); 2045 2046 if (!(/loading|progress/gi.test(this.type))) { 2047 var dim = { 2048 containerHeight: this.container.measure('padding-box-height'), 2049 messagebodyHeight: this.messagebody.measure('padding-box-height'), 2050 maxHeight: $Screen.viewport.height * .75,
2051 maxWidth: $Screen.viewport.width * .75, 2052 headerHeight: this.header ? this.header.getHeight() : 0, 2053 footerHeight: this.messagecontrols ? this.messagecontrols.getHeight() : (this.options.radius ? 15 : 0), 2054 }; 2055 this.messagebody.setStyle({ 2056 height: Math.min((this.options.height ? (this.options.height - dim.headerHeight - dim.footerHeight) : dim.messagebodyHeight), dim.maxHeight) + 'px', 2057 marginBottom: dim.footerHeight + 'px' 2058 }); 2059 this.messagecontainer.setStyle({ 2060 height: Math.min((this.options.height ? (this.options.height - dim.headerHeight - dim.footerHeight - 5) : this.messagebody.clientHeight - 25), this.messagebody.clientHeight - 25) + 'px', 2061 }); 2062 } 2063 return this; 2064 }, 2065 2066 KeyDown: function (e) { 2067 if ((['alert', 'confirm', 'dialog'].include(this.type) && (e.keyCode == Event.KEY_RETURN || e.keyCode == Event.KEY_ESC)) || 2068 (/progress/.test(this.type) && e.ctrlKey && e.keyCode == Event.KEY_BACKSPACE)) { 2069 Event.stop(e); 2070 this.DoAction(e); 2071 } 2072 }, 2073 2074 AddEventHandlers: function () { 2075 this.events.push(Event.on(top, "resize", this.Reposition.bind(this))); 2076 if (this._overlay) { 2077 this.events.push(Event.on(document, "keydown", this.KeyDown.bindAsEventListener(this))); 2078 if (this.options.overlay) { 2079 this.events.push(Event.on(this._overlay, "mousedown", this.Deny.bindAsEventListener(this))); 2080 this.events.push(Event.on(this.container, "mousewheel", this.Deny.bindAsEventListener(this))); 2081 this.events.push(Event.on(document, "mousewheel", this.Deny.bindAsEventListener(this))); 2082 } 2083 } 2084 return this; 2085 }, 2086 Deny: function (e) { 2087 if (e && e.element() === this._overlay) { 2088 e.stop(); 2089 return false; 2090 } 2091 }, 2092 RemoveEventHandlers: function () { 2093 $A(this.events).invoke('stop'); 2094 } 2095}); 2096 2097Utility.Drag = Class.create(Utility.Base, { 2098 initialize: function ($super, host, options) { 2099 if (!$super.apply(this, $A(arguments).slice(1))) 2100 return false; 2101 //host must be absolute/fix positioned 2102 this.options.handle.on('mousedown', this.Start.bindAsEventListener(this)); 2103 }, 2104 2105 Start: function (e) { 2106 this.left = this.host.offsetLeft; 2107 this.top = this.host.offsetTop; 2108 this.X = e.clientX; 2109 this.Y = e.clientY; 2110 this.host.addClassName('dragged'); 2111 this.on(Event.on(document, 'mousemove', this.Drag.bindAsEventListener(this))); 2112 this.on(Event.on(document, 'mouseup', this.Release.bindAsEventListener(this))); 2113 return false; 2114 }, 2115 Drag: function (e) { 2116 2117 this.Set(e.clientX - this.X, e.clientY - this.Y); 2118 return false; 2119 }, 2120 Set: function (dx, dy) { 2121 /* 2122 var left = Math.min(Math.Max(this.left + dx, 0), $Screen.viewport.width); 2123 var y = Math.min(Math.Max(e.clientY - this.Y, 0), $Screen.viewport.height); 2124 */ 2125 2126 this.host.setStyle({ left: (this.left + dx) + 'px', top: (this.top + dy) + 'px' }); 2127 }, 2128 Release: function () { 2129 this.host.removeClassName('dragged'); 2130 this.off(); 2131 } 2132}); 2133 2134Utility.Device = Class.create({ 2135 initialize: function () { 2136 this.isTouchDevice = 'ontouchstart' in window; 2137 this.EventName = function (opt) { 2138 return opt ? { 'click': 'click', 'start': 'touchstart', 'move': 'touchmove', 'end': 'touchend', 'resize': 'orientationchange' } 2139 : { 'click': 'click', 'start': 'mousedown', 'move': 'mousemove', 'end': 'mouseup', 'resize': 'resize' }; 2140 }(Boolean('ontouchstart' in window)); 2141 Event.observe(window, this.EventName['resize'], this.Refresh.bindAsEventListener(this)); 2142 this.viewport = this.GetViewPort(); 2143 }, 2144 GetViewPort: function () { 2145 var dim = document.viewport.getDimensions(); 2146 if (!dim.width || !dim.height) 2147 dim = { 2148 width: window.innerWidth, //Math.max(Math.max(document.documentElement.scrollWidth, document.body.scrollWidth), document.documentElement.clientWidth), 2149 height: window.innerHeight //Math.max(Math.max(document.documentElement.scrollHeight, document.body.scrollHeight), document.documentElement.clientHeight) 2150 }; 2151 return dim; 2152 }, 2153 GetVisibleArea: function () { 2154 var offsets = document.viewport.getScrollOffsets(); 2155 var dim = document.viewport.getDimensions(); 2156 return { 2157 top: offsets.top,
2158 bottom: offsets.top + dim.height, 2159 left: offsets.left, 2160 right: offsets.left + dim.width 2161 }; 2162 }, 2163 IsFullyVisible: function (layout) { 2164 var d = this.GetVisibleArea(); 2165 layout = Object.isElement() ? e.getLayout().toObject() : layout; 2166 var b = ((layout.top >= d.top) && ((layout.top + layout.height) <= d.bottom)); 2167 return b;// || isAppearingBottom || isAppearingTop; 2168 }, 2169 Refresh: function (e) { 2170 this.viewport = this.GetViewPort(); 2171 document.fire('::refresh', this.viewport); 2172 } 2173}); 2174 2175 2176///* 2177//This function should be assigned in inline HTML code. In order to show custom Confirm 2178//before real action (usually placed in "onclick" event) we need to call this method on event earier, 2179//like "onmousedown". 2180//Note: A javascript call used on "onmousedown" should ended with "return false;" to prevent event bubbling (call onclick) 2181//NOTE: In all shortcuts arguments can be a List of arguments or an object with specified properties 2182 2183//Example: 2184//<a href='javascript:__doPostBack([elementid], [argument])' onmousedown="javascript:ConfirmOnClick(this,{MESSAGE},{TITLE})" 2185//*/ 2186 2187// Aliases 2188//Redirection or reloader 2189$redirect = Utility.Redirect; 2190$redirectWindow = Utility.RedirectNewWindow; 2191 2192//Image Loader 2193$ImageLoader = Utility.ImageLoader; 2194 2195$loadscript = Ajax.JSONRequest; 2196 2197//Creates a shortcuts for Alert 2198$alert = function (message, title, callback) { 2199 if (window.useStandart) 2200 return alert(message || o.options.message); 2201 else 2202 return new Utility.Message('alert', Object.extend({ radius: true, shadow: true, auto: 'Show' }, arguments.callee.argumentValues())); 2203}; 2204 2205//Creates a shortcuts for INFO 2206$message = function (message, title, callback) { 2207 return $dialog(message, title, callback); 2208}; 2209 2210//Creates a shortcuts for Confirm 2211$dialog = function (message, title, callback) { 2212 return new Utility.Message('dialog', Object.extend({ radius: true, shadow: true, isHTML: true, auto: 'Show' }, arguments.callee.argumentValues())); 2213}; 2214 2215//Creates a shortcuts for Confirm 2216$confirm = function (message, title, callback) { 2217 return new Utility.Message('confirm', Object.extend({ radius: true, shadow: true, auto: 'Show' }, arguments.callee.argumentValues())); 2218}; 2219 2220 2221//Creates a shortcuts for PROGRESS 2222$progress = function (message) { 2223 return new Utility.Message('progress', Object.extend({ radius: true, shadow: true, }, arguments.callee.argumentValues())); 2224}; 2225 2226$loading = function (message) { 2227 return new Utility.Message('loading', Object.extend({ overlay: false }, arguments.callee.argumentValues())); 2228}; 2229 2230$popupwindow = function (url, title, width, height) { 2231 2232 var prms = Object.isString(url) ? { url: url, title: title, width: width, height: height } : url; 2233 2234 var id = "$" + Object.guid(); 2235 prms = Object.extend({ 2236 message: '<iframe id="' + id + 'frm" src="' + prms.url + '" marginWidth="0" marginHeight="0" frameBorder="0" scrolling="auto" style="width:100%;height:100%" data-popup="' + id + '" />', 2237 radius: true, 2238 shadow: true, 2239 auto: 'Show' 2240 }, prms); 2241 2242 self[id] = new Utility.Message('popup', prms); 2243 self[id].frm = $p(id + 'frm'); 2244 2245 if (Object.isElement(self[id].frm) && self[id].frm.contentWindow) { 2246 self[id].onHide = function () { try { this.frm.contentWindow.document.fire(':close'); } catch (e) { } }.bind(self[id]); 2247 self[id].frm.contentWindow.Close = function () { this.Close(); }.bind(self[id]); 2248 } 2249 return self[id]; 2250}; 2251 2252 2253$execute = function (host, method, parameters) { 2254 (self.event instanceof Event.Handler) && Event.stop(self.event); 2255 if (!Object.isElement(host)) { 2256 parameters = method, method = host, host = document.body; 2257 } 2258 new Utility.AjaxSelector(host, { method: method, parameters: parameters }).Call(); 2259 return false; 2260}; 2261 2262window.$isIOSDevice = /(iPad|iPhone|iPod|Macintosh)/g.test(navigator.userAgent) && !(/(CriOS)/g.test(navigator.userAgent)) && navigator.maxTouchPoints; 2263 2264window.$Screen = window.$Screen || new Utility.Device(); 2265 2266document.observe("dom:loaded", function () { 2267 2268 2269 2270 //Add event handler to a document to show a waiting message. 2271 //A wating message could be stored as window variable 2272 //To not show this progress message on each page postback we need to assign this varialble to empty string or null 2273 //window.onbeforeunload = function (e) { debugger; $progress(self.progressmessage); } 2274 //NOTE :: to temporary (one time) disable a progress message on page reload/unload just assign none-string value to self.progressmessage property 2275 // usage:: OnClientClick="progressmessage={restore:progressmessage};" - to restore message, or - progressmessage=false - restore 'Please wait...' 2276 //Create default progress message text. 2277 //To disable showing the Progress message window assigne this property to null/undefined 2278 2279 self.executeprogress = "Loading..."; 2280 Object.isUndefined(self.progressmessage) && (self.progressmessage = $progress({ message: "Loading", auto: 'Create', keep: true })); 2281 2282 Event.observe(document.body, ':unload', function (e) { 2283 if (Object.isUndefined(self.progressmessage)) 2284 return; 2285 else if (self.progressmessage instanceof Utility.Message) { 2286 if (self !== top && top.progressmessage instanceof Utility.Message && top.progressmessage.IsShown()) 2287 return; 2288 // To hide a progress message on page reload after 20 sec 2289 // IMPORTANT for the cases where external app/page is used (like <a href="..." target="new|..-") 2290 self.progressmessage.Show(10); 2291 2292 } else { 2293 Object.isString(self.progressmessage) ? $progress(self.progressmessage) : (self.progressmessage = (self.progressmessage && self.progressmessage.restore || "Please wait...")); 2294 } 2295 });
2296 2297 Event.observe(window, 'beforeunload', function (e) { 2298 $p(document.body).fire(':unload'); 2299 }); 2300 //Create all tooltips 2301 !$Screen.isTouchDevice && Utility.Global.bubbletip && ($$('[title]', '[bubbletip]').each(function (it) { new Utility.BubbleTip(it); })); 2302 try { 2303 //Append style 2304 Utility.AddStyle(); 2305 } 2306 catch (ex) { 2307 $alert({ title: 'Load error', message: ex.message }); 2308 } 2309}); 2310
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.